嵌入式开发中断全解(2)Hard Fault的诊断

这篇具有很好参考价值的文章主要介绍了嵌入式开发中断全解(2)Hard Fault的诊断。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

承接上次的文章,讲几个大家应该都看过下面的几个中断,有的是在启动文件中或者是.c文件中。
嵌入式开发中断全解(2)Hard Fault的诊断
注意:上述是ST公司的Stm32芯片

嵌入式开发中断全解(2)Hard Fault的诊断
这里的GD32芯片是国产芯片,和stm32类似的操作,代码可以兼容。

1、void NMI_Handler(void)

不可屏蔽中断。主要是两方面触发,一个是外设触发,一个软件设置触发。首先要意识到,所有中断在某些情况下都是可屏蔽的。例如,如果中断控制器完全关闭,则不会向 CPU 传递任何中断。术语不可屏蔽中断实际上涵盖了一类中断,即使“正常”中断被屏蔽,仍可以将其传递给 CPU。NMI 仍然可以被屏蔽,但是通过标准内核代码难以访问的单独控制状态。在某些情况下屏蔽所有中断的能力也存在于其他具有悠久 NMI 历史的架构上。

操作系统软件需要仅在特定情况下被屏蔽的单独中断类别有两个主要原因。第一个原因很简单,中断可能会意外地被禁用,从而使系统处于无响应状态。乍一看,似乎可以轻松编写软件以在禁用中断后始终启用中断,但事实并非如此。现代操作系统内核通常跨越数百万行可以直接操作中断标志的代码。中断处理例程可能会导致同步异常,从而导致非线性代码路径,并可能导致禁用中断的死锁。还要考虑以完全内核权限运行并能够直接操纵 CPU 中断标志​​的第三方驱动程序。应该清楚的是,简单的代码检查或静态分析不足以防止中断被禁用。在一些场景中,能够快速传递中断至关重要,例如调试、跨 PE 同步和热补丁。原文克里斯托弗·达尔。
NMI属于内部中断,并且默认是使能的。NMI对外有一个引脚与之相关联,该引脚的默认功能就是NMI。我们可以知道,当我们使用该引脚用作其它功能的时候,如果把NMI引脚在电路上接地,程序在启动的时候就会触发NMI中断,从而进入到NMI_Handler函数中去,那程序一直卡在这了,后期再说说怎么屏蔽。(主要大家要看看芯片用户手册)。void NMI_Handler(void)函数原型如下。

/*!
    \brief      this function handles NMI exception 
    \param[in]  none
    \param[out] none
    \retval     none
*/
void NMI_Handler(void)
{
}

2、void SVC_Handler(void)
SVC(Supervisor Call)指令用于产生一个SVC异常。它是用户模式代码中的主进程,用于创造对特权操作系统代码的调用。SVC是用于呼叫操作系统所提供API的正道。用户程序只需知道传递给操作系统的参数,而不必知道各API函数的地址。

/*!
    \brief      this function handles SVC exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SVC_Handler(void)
{
}

3、void DebugMon_Handler(void)

调试监视器(断点, 数据观察点, 或外部调试请求),大部分debug的时候就是调试的时候遇到.

/*!
    \brief      this function handles DebugMon exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void DebugMon_Handler(void)
{
}

4、void PendSV_Handler(void)
PendSV是为系统级服务提供的中断驱动。在一个操作系统环境中,当没有其他异常正在执行时,可以使用PendSV来进行上下文的切换。
在进入PendSV处理函数时:
(1)xPSR、PC、LR、R12、R0~R3已经在处理栈中被保存。
(2)处理模式切换到线程模式。
(3)栈是主堆栈。
由于PendSV在系统中被设置为最低优先级,因此只有当没有其他异常或者中断在执行时才会被执行。

/*!
    \brief      this function handles PendSV exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void PendSV_Handler(void)
{
}

5、void SysTick_Handler(void)
看到这个大家肯定会想到滴答定时器,就是系统定时器 , 以后再分享个系统定时器的内容,在参考手册中, 有这样说法, 当systic为计数为0 则成1外部参考时钟源 21mhz bit[2]为0 内核时钟168MHZ bit[2] 为1 ,使能定时器中断为1,当计数产生为0产生中断,或者将bit[1]0使能位(0关闭,1打开, 系统定时器中断 一般用在操作系统的延时

/*!
    \brief      this function handles SysTick exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SysTick_Handler(void)
{
    delay_decrement();
}

以下四种常见的错误异常。
嵌入式开发中断全解(2)Hard Fault的诊断
6、void HardFault_Handler(void)
以下异常处理被关闭,而又发生了异常,则触发
• 执行异常处理时,发生了异常,则触发
• 复位时默认使能
传说中的段错误。主要原因两方面:(1)中断问题,例如中断嵌套太多,中断优先级问题,中断标志位没清楚等;(2)堆栈不够或者溢出,例如:当你需要大数组去存取数据,数组就会设置的太大,就会跑飞进入这个中断,这时候你可以把栈堆分配多一点。如何分配堆栈空间?可以先去了解内存布局。

/*!
    \brief      this function handles HardFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/

void HardFault_Handler(void)
{
    /* if Hard Fault exception occurs, go to infinite loop */
    while(1){
    }
}

硬错误异常是应对系统严重错误而设计的,其优先级为-1,仅次于NMI异常。触发硬错误异常的原因有:
• 调试出错
• 后面三个MemManage_Handler\BusFault_Handler\UsageFault_Handler常规错误异常不能及时响应
• 为响应中断,取中断向量时发生错误
• 仍可通过PRIMASK关闭
注意:

当总线错误异常、存储器管理错误异常、用法错误异常无法及时得到响应时或未被使能时,系统将产生硬错异常。当硬错误异常服务例程又引发新的硬错误异常时,系统将进入死锁状态,只能由复位使其退出.

7、void MemManage_Handler(void)
• 违反MPU设定的存储器访问规则
• 复位时默认未使能
在内核的MCU上写程序时,稍不留神,就可能出现内存溢出的情况。即,数组、指针变量溢出,导致MCU访问内部禁止访问的地址上。这样MCU就会跳转到 错误或者硬件错误中断上去,造成设备死机。也可以在这两个中断中加入强制CPU复位重启,但不能完全解决问题,其实发生存储管理错误中断(MemManage_Handler)后,都发现程序是跳到硬件错误中断(HardFault_Handler)里,说白了又是内存布局问题。

/*!
    \brief      this function handles MemManage exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void MemManage_Handler(void)
{
    /* if Memory Manage exception occurs, go to infinite loop */
    while(1){
    }
}

存储器管理错误异常是由于违规访问存储器空间或由某些非法访问引发的;通常包括以下类型:
• 访问存储区域时违反了MPU的设置规则
• 越权访问,访问了没有权限访问的地址;
• 访问了没有存储器的地址
• 试图从不可执行区域(XN)执行代码
• 对只读区域进行写操作

使能控制
• SCB->SHCSR. MEMFAULTENA @0xE000ED24

存储器管理错误异常,通常是与MPU相关联的。其诱因往往是违反了MPU设置的访问规则。某些非法访问,如在不可执行的存储器区域取指,也会会引发该异常,既使系统中没有MPU 或MPU被关掉了

发生Memory Management Fault时,可以查看存储器管理错误状态寄存器了解异常的类型
• SCB->CFSR. Memory Manage Fault(MFSR) @0xE000ED28

嵌入式开发中断全解(2)Hard Fault的诊断

8、void BusFault_Handler(void)
• 总线错误(Bus Fault)
• 取指令、数据读写、堆栈操作
• 复位时默认未使能

/*!
    \brief      this function handles BusFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/

void BusFault_Handler(void)
{
    /* if Bus Fault exception occurs, go to infinite loop */
    while(1){
    }
}

当内核通过AHB接口传送数据时收到了一个错误应答信号,则认总线传输错误,进而发起总线错误异常请求;通常异常来自:
• 取指令时发生错误,通常称为“预取指流产”
• 数据读、写时发生错误,也叫“数据流产”
• 响应中断时,出、入栈发生错误
使能控制
• SCB->SHCSR. BUSFAULTENA @0xE000ED24
AHB总线收到”错误”应答,通常有以下诱因:

企图访问无效的存储器区域,常见于企图访问的地址没有存储器
设备未准备就绪,不能进行总线访问
企图发起的传输宽度不被目标设备所支持
在用户权限下程序企图访问特权模式下的设备

发生Bus Fault时,可以查看总线错误状态寄存器了解异常
的大致类型,供异常处理程序分析
• SCB->CFSR.Bus Fault(BFSR) @0xE000ED2

嵌入式开发中断全解(2)Hard Fault的诊断

9、void UsageFault_Handler(void)
• 用法错误(Usage Fault)
• 执行未定义指令、非对齐操作、除零
• 复位时默认未使能

/*!
    \brief      this function handles UsageFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void UsageFault_Handler(void)
{
    /* if Usage Fault exception occurs, go to infinite loop */
    while(1){
    }
}

嵌入式开发中断全解(2)Hard Fault的诊断

发生用法错误时,可通过查看寄存器了解出错的原因
• SCB->CFSR. Usage Fault(UFSR) @0xE000ED2A

嵌入式开发中断全解(2)Hard Fault的诊断

解决方法:
通常一直循环进入某个中断,代码底层没错的前提就打断点,看看是在哪出错,检查内存使用,有没有访问越界,堆栈够不够。或者把可能出错的程序全部屏蔽。看是否再出现内存溢出,如果不再出现了,那就一点点打开屏蔽的代码。这样就可以轻松定位出错的位置上。然后再去分析为什会出现内存溢出。以下就是我这个小白,老是出错的问题:

第一,没有给指针变量赋初始值就开始使用。
第二,在给数组变量copy时,长度超限。如果这个数组是局部变量就会改变了栈中的其它变量和压栈的cpu寄存器,如果数组是,物理上相邻的变量就会被改变。
第三,中断与应用程序对同一指针变量的修改不同步。

(c语言基础一定要牢固啊!!!!以后再分享些c语言学习)

错误异常发生时:
• 上下文(Stack Frame)被入栈保存
• R0~R3, R12, LR,PC,xPSR
• 上下文保存在哪个堆栈中?由此时的LR决定
• LR = EXC_RETURN
• LR.2 = 1,保存在Main Stack,由MSP指向
• LR.2 = 0,保存在Process Stack,由PSP指向
嵌入式开发中断全解(2)Hard Fault的诊断
记录发生异常时的现场数据 :
采集现场有助于分析出错原因可以通过串口来看,如下面这段代码.

HardFault_Handler: 
TST LR, #4 
ITE EQ 
MRSEQ R0, MSP 
MRSNE R0, PSP 
B hard_fault_handler_c
void hard_fault_handler_c (unsigned int * hardfault_args) 
{ 
unsigned int stacked_r0; 
unsigned int stacked_r1; 
unsigned int stacked_r2; 
unsigned int stacked_r3; 
unsigned int stacked_r12; 
unsigned int stacked_lr; 
unsigned int stacked_pc; 
unsigned int stacked_psr; 
stacked_r0 = ((unsigned long) hardfault_args[0]); 
stacked_r1 = ((unsigned long) hardfault_args[1]); 
stacked_r2 = ((unsigned long) hardfault_args[2]); 
stacked_r3 = ((unsigned long) hardfault_args[3]); 
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_r12 = ((unsigned long) hardfault_args[4]); 
stacked_lr = ((unsigned long) hardfault_args[5]); 
stacked_pc = ((unsigned long) hardfault_args[6]); 
stacked_psr = ((unsigned long) hardfault_args[7]);
printf ("\n\n[Hard fault handler - all numbers in hex]\n"); 
printf ("R0 = %x\n", stacked_r0); 
printf ("R1 = %x\n", stacked_r1); 
printf ("R2 = %x\n", stacked_r2); 
printf ("R3 = %x\n", stacked_r3); 
printf ("R12 = %x\n", stacked_r12); 
printf ("LR [R14] = %x subroutine call return address\n", stacked_lr); 
printf ("PC [R15] = %x program counter\n", stacked_pc); 
printf ("PSR = %x\n", stacked_psr); 
printf ("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38)))); 
printf ("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28)))); 
printf ("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C)))); 
printf ("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30)))); 
printf ("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C)))); 
printf ("SCB_SHCSR = %x\n", SCB->SHCSR); while (1); 
}

俗话说:复习是进步他爹!!总结是进步他舅!!
单片机中断分为内部中断和外部中断两大类,外部中断由单片机外部设备产生,中断产生后通过单片机的外部管脚传递给单片机,传递这个中断信号最简单的方法就是 规定单片机的管脚在什么状态下有外部中断产生,这样单片机通常是有一个或多个IO口,当在输入状态时可以用来检测外部中断信号。嵌入式开发中断全解(1)
文章很长,能看到这也希望都能学到些东西,努力成为"栈溢出"工程师 ! ! ! 加油 !文章来源地址https://www.toymoban.com/news/detail-447567.html

到了这里,关于嵌入式开发中断全解(2)Hard Fault的诊断的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • STM32的中断系统详解(嵌入式学习)

    STM32的中断系统详解(嵌入式学习)

    中断是处理器中的一种机制,用于响应和处理突发事件或紧急事件。当发生中断时,当前正在执行的程序会被暂时中止,处理器会跳转到中断处理程序(也称为中断服务例程),对中断事件进行处理。处理完中断后,处理器再返回到被中断的程序继续执行。 中断可以分为内部

    2024年02月12日
    浏览(22)
  • 嵌入式-stm32-江科大-EXTI外部中断

    嵌入式-stm32-江科大-EXTI外部中断

    1.1 STM32 中断系统 中断 是指在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续执行, 当中断发生时是由硬件自动调用中断函数执行的,期间编译器会保护现场最后还原现场

    2024年01月25日
    浏览(16)
  • 【嵌入式】HC32F460串口接收超时中断+DMA

    【嵌入式】HC32F460串口接收超时中断+DMA

            项目需要使用一款UART串口编码器,编码器的数据以波特率57600持续向外发送。但这组数据包没有固定的包头和校验尾,仅仅是由多圈圈数和单圈角度组成的六字节数据码,这样接收到的数组无法确定实际的下标,所以这边考虑用串口接收超时中断+DMA来实现。 【

    2024年02月14日
    浏览(9)
  • 【嵌入式学习-STM32F103-TIM-定时中断和外部时钟】

    【嵌入式学习-STM32F103-TIM-定时中断和外部时钟】

    1、定时器基本定时,定一个时间,然后让定时器每隔一段时间产生一个中断,来实现每隔一个固定时间执行一段程序的目的,比如要做一个时钟、秒表或者使用一些程序算法 2、定时器输出比较的功能,输出比较这个模块最常见的用途是产生PWM波形,用于驱动电机等设备,使

    2024年02月12日
    浏览(13)
  • 嵌入式学习笔记——STM32的USART收发字符串及串口中断

    嵌入式学习笔记——STM32的USART收发字符串及串口中断

    上一篇中,介绍了串口收发相关的寄存器,通过代码实现了一个字节的收发,本文接着上面的内容,通过功能函数实现字符串的收发,然后引入中断解决收发过程中while()死等的问题。 根据昨天的字符发送函数,只需要稍作修改即可实现发送函数了,一个字符串的结尾会有一

    2024年02月03日
    浏览(20)
  • 嵌入式学习笔记(32)S5PV210的向量中断控制器

    嵌入式学习笔记(32)S5PV210的向量中断控制器

    6.6.1异常处理的2个阶段 可以将异常处理分为2个阶段来理解。第一个阶段是异常向量表跳转;第二个阶段是进入了真正的异常处理程序irq_handler之后的部分。 6.6.2回顾:中断处理的第一个阶段(异常向量表跳转阶段)处理 (1)第一个阶段之所以能够进行,主要依赖于CPU设计时

    2024年02月07日
    浏览(14)
  • 关于嵌入式开发的一些信息汇总:嵌入式C开发人员、嵌入式系统Linux

    关于嵌入式开发的一些信息汇总:嵌入式C开发人员、嵌入式系统Linux

    这篇文章是关于嵌入式开发的一些基本信息,供想入行的人参考。有一些作者本人的想法,以及来自外网的大拿的文章翻译而来,原文链接在此Learning Linux for embedded systems,再次感谢,支持原创。 普通C开发人员和嵌入式C开发人员之间的 基本区别在于 ,因为嵌入式C程序被设

    2024年02月03日
    浏览(66)
  • 适合嵌入式开发的GUI(嵌入式学习)

    适合嵌入式开发的GUI(嵌入式学习)

    嵌入式开发中的GUI(图形用户界面)是指在嵌入式系统中实现图形化的用户界面,以便用户可以通过触摸屏、按钮、鼠标或其他输入设备与系统进行交互。 以下是一些常见的嵌入式GUI开发方法: 轻量级GUI库:一些轻量级的GUI库适用于嵌入式系统,例如uGFX、LittlevGL、Nanogui等。

    2024年02月09日
    浏览(8)
  • 嵌入式Linux:如何进行嵌入式Linux开发?

    目录 1、裸机开发 2、SDK开发 3、驱动开发 3.1、字符设备驱动 3.2、块设备驱动 3.3、网络设备驱动 4、应用开发 嵌入式Linux开发主要有四种方式:裸机开发、SDK开发、驱动开发和应用开发。 裸机开发通常指在没有操作系统支持的环境中直接在硬件上运行程序的开发。这种开发方

    2024年01月25日
    浏览(15)
  • 嵌入式开发:单片机嵌入式Linux学习路径

    嵌入式开发:单片机嵌入式Linux学习路径

    SOC(System on a Chip)的本质区别在于架构和功能。低端SOC如基于Cortex-M架构的芯片,如STM32和NXP LPC1xxx系列,不具备MMU(Memory Management Unit),适用于轻量级实时操作系统如uCOS和FreeRTOS。高端SOC如基于Cortex-A架构的芯片,如三星、高通、飞卡、全志和瑞芯微等,具备MMU,支持虚拟内

    2024年02月15日
    浏览(18)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包