各個復位標志解析,讓我們對MCU的程序的健康更有把控
作者:良知猶存
轉載授權以及圍觀:歡迎添加微信號:Conscience_Remains
總述
曾經開發(fā)的時候遇到這樣情況,我們開發(fā)的設備需要長時間工作上報信息,但是我們在后臺查看上報數據,發(fā)現設備總是有斷開的情況。因為是遠程的設備無法進行現場查看,這個時候我們就用到了MCU的復位的狀態(tài)解析上報,輔助我們進行診斷故障的來源,可能是程序到死循環(huán),可能是程序hardfault,也可能硬件電源不穩(wěn)定導致的復位。
綜合上面的要求,我們分析一下STM32相應的寄存器,以及講解相關函數使用方法。
一、MCU寄存器介紹
????在stm32開發(fā)手冊里面選擇 RCC寄存器 中的 控制狀態(tài)寄存器 書簽,就可以看到相應的介紹:
其中包含了:低功耗復位標志、窗口看門狗復位標志、獨立看門狗復位標志、軟件復位標志、上電/掉電復位標志、NRST引腳復位標志。
????在RCC功能的這一欄下級菜單 系統(tǒng)復位 里面有對復位比較詳細的介紹:
這些復位標志能夠被我們解析并保存上報的話,我們就可以通過復位標志的信息進而判斷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);}
以上代碼通過建立一個單向鏈表把采集到的復位標志進行保存發(fā)送到服務器端。
二、中斷故障函數
????在開發(fā)過程中,我們會遇到hardfault這樣的bug,但是如果是遠程上報信息,僅憑復位標志是無法檢測的,一般hardfault會有軟件復位標志和看門狗復位標志(如果設備開啟看門狗)。
????而我選擇了另一種方式,因為這些故障標志在程序復位之后就會消失,所以我在故障發(fā)生的時間進行變量記錄保存到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"); }}
通過在程序設備故障碼表監(jiān)控程序的健康,對于任何一個開發(fā)者來說都有很多好處,這里只是我通過介紹MCU的標志位繼而擴展的話題,下一次,我把我用來存放故障碼的鏈表,再詳細介紹一下使用過程。
這就是我分享的復位等一些標志的使用過程,里面代碼是實踐過的,如果大家有什么更好的思路,歡迎分享交流哈。
猜你喜歡
bug解決不了?使用日志法
從單片機工程師的角度看嵌入式Linux
你的單片機裸機程序框架是怎樣的?
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!