作者:良知犹存
转载授权以及围观:欢迎添加微信公众号:Conscience_Remains
总述
曾经开发的时候遇到这样情况,我们开发的设备需要长时间工作上报信息,但是我们在后台查看上报数据,发现设备总是有断开的情况。因为是远程的设备无法进行现场查看,这个时候我们就用到了MCU的复位的状态解析上报,辅助我们进行诊断故障的来源,可能是程序到死循环,可能是程序hardfault,也可能硬件电源不稳定导致的复位。
综合上面的要求,我们分析一下STM32相应的寄存器,以及讲解相关函数使用方法。
一、MCU寄存器介绍
在stm32开发手册里面选择 RCC寄存器 中的 控制状态寄存器 书签,就可以看到相应的介绍:
其中包含了:低功耗复位标志、窗口看门狗复位标志、独立看门狗复位标志、软件复位标志、上电/掉电复位标志、NRST引脚复位标志。
在RCC功能的这一栏下级菜单 系统复位 里面有对复位比较详细的介绍:
这些复位标志能够被我们解析并保存上报的话,我们就可以通过复位标志的信息进而判断MCU崩溃的原因。下面我来进行介绍相应的标志以及组合判断。
在RCC_CSR所有复位源,复位的时候都会使引脚复位置位,上电复位只产生引脚复位,其余的复位都产生一个引脚复位,和一个相应的自身复位。
所以程序解析的时候先检测是否有pin复位
void GetResetFlag(void) { devfaultcode.resetfault = 0; if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) { dprintf("*RCC_FLAG_PINRST\r\n"); devfaultcode.resetfault = 0xF001; } if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET) { printf("*RCC_FLAG_IWDGRST\r\n"); devfaultcode.resetfault = 0xF002; } if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET) { printf("*RCC_FLAG_WWDGRST\r\n"); devfaultcode.resetfault = 0xF003; } if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) { printf("*RCC_FLAG_PORRST\r\n"); devfaultcode.resetfault = 0xF004; } if(RCC_GetFlagStatus(RCC_FLAG_SFTRST) != RESET) { printf("*RCC_FLAG_SFTRST\r\n"); devfaultcode.resetfault = 0xF005; } if(RCC_GetFlagStatus(RCC_FLAG_LPWRRST) != RESET) { printf("*RCC_FLAG_LPWRRST\r\n"); devfaultcode.resetfault = 0xF006; } RCC_ClearFlag(); //Clears the RCC reset flags. ErrListInsert(ErrHead,devfaultcode.resetfault); printf("devfaultcode:%d\r\n",devfaultcode.resetfault); }
以上代码通过建立一个单向链表把采集到的复位标志进行保存发送到服务器端。
二、中断故障函数
在开发过程中,我们会遇到hardfault这样的bug,但是如果是远程上报信息,仅凭复位标志是无法检测的,一般hardfault会有软件复位标志和看门狗复位标志(如果设备开启看门狗)。
而我选择了另一种方式,因为这些故障标志在程序复位之后就会消失,所以我在故障发生的时间进行变量记录保存到FLASH,通过自定义的故障码表,再在程序中进行故障出现位置进行故障码的存入,再利用各种通讯方式上报,后台就可以对于设备出现的各种问题按表对照,如同汽车的故障码表一样。
void HardFault_Handler(void) { devfaultcode.resetfault = 0xF007; writeFlash(); /* Go to infinite loop when Hard Fault exception occurs */ while (1) { printf("HardFault\r\n"); } } /** * @brief This function handles Memory Manage exception. * @param None * @retval None */ void MemManage_Handler(void) { devfaultcode.resetfault = 0xF008; writeFlash(); /* Go to infinite loop when Memory Manage exception occurs */ while (1) { printf("MemManageFault\r\n"); } } /** * @brief This function handles Bus Fault exception. * @param None * @retval None */ /*总线Fault,取址或取值时的内存错误*/ void BusFault_Handler(void) { devfaultcode.resetfault = 0xF009; writeFlash(); /* Go to infinite loop when Bus Fault exception occurs */ while (1) { printf("BusFault\r\n"); } } /** * @brief This function handles Usage Fault exception. * @param None * @retval None */ /*用法 Fault */ void UsageFault_Handler(void) { resetfault = 0xF010; writeFlash(); /* Go to infinite loop when Usage Fault exception occurs */ while (1) { printf("UseageFault\r\n"); } }
通过在程序设备故障码表监控程序的健康,对于任何一个开发者来说都有很多好处,这里只是我通过介绍MCU的标志位继而扩展的话题,下一次,我把我用来存放故障码的链表,再详细介绍一下使用过程。
这就是我分享的复位等一些标志的使用过程,里面代码是实践过的,如果大家有什么更好的思路,欢迎分享交流哈。