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