STM32程序進不了main函數奇葩現象---你不知道的原因

1.現象

   在基於STM32開發一個項目過程中,遇到一個比較奇葩的現象:經常會時不時出現修改上層的應用代碼導致程序運行不起來,進不去main函數。這個STM32程序是分爲bootloader層和APP層,出現這個奇葩現象的時候,bootloader層是可以正常運行的,但是跳轉到APP層的時候,就發現進不了main函數。

2.分析

   一開始也是找不到原因何在,通過網上搜索發現也有類似出現STM32進不去main函數的,原因多數是因爲printf函數的應用導致的。但通過代碼檢查發現我遇到的這個奇葩現象,並非printf函數運用導致。這裏也藉此瞭解一下printf函數在stm32中使用注意事項,避免出現這個錯誤。

printf函數:

  printf之類的函數,使用了半主機模式,所以要利用目標ARM器件的輸入輸出設備,首先要關掉半主機機制,然後再將輸入輸出重定向到ARM器件上,如printf和scanf,需重寫fputc和fgetc.

具體代碼實現可參考如下(重寫fputc):

#if 1
#pragma import(__use_no_semihosting)  //確保沒有從C庫鏈接使用半主機的函數
//標準庫需要支持的函數
struct __FILE
{
    int handle;
};

FILE __stdout;
//以避免使用半主機模式
void _sys_exit(int x)
{
    x = x;
}

//重定義fputc函數
int fputc(int ch, FILE *f)
{
    while((USART1->ISR & 0X40) == 0); //循環發送,直到發送完畢

    USART1->TDR = (u8) ch;
    return ch;
}
#endif

如果不重寫fputc等函數,也可直接勾選keil工具裏面的Use MicroLIB.

3. 仿真調試

    當經過檢查後,發現並非是printf函數使用不當導致程序進不去main函數,於是採用在線仿真的方式一步步查找原因。

第一步:先是全速運行,發現程序直接進入了HardFault_Handler。

接着分析啓動文件startup_stm32xx.s:在執行進main函數之前,會先執行SystemInit函數,進行系統初始化。

在SystemInit函數裏面打斷點,單步執行調試,看程序能否執行進來:發現程序可以執行進來。

於是結合上面分析的printf函數原因, 於是嘗試在fputc函數打一斷點,看是否會跑進fputc函數:發現程序確實跑進了fputc函數

  通過SystemInit函數單步執行跑到fputc函數可以分析到,應該是程序哪裏出錯後,執行了打印輸出,而此時串口並未初始化。發現從SystemInit到fputc這樣順序執行下來,不可能會出現打印的函數,那此時有可能就是發生了某種中斷,導致在進入main函數之前,跑進了一箇中斷處理函數裏面去了。

 那有可能是哪個中斷導致的呢?: 像定時器、RTC這些中斷,都是進入main函數初始化後纔會開啓的,排除了這類中斷,那應該就是某種系統中斷導致的。該stm32程序用到了FreeRtos系統,那可能中斷就是systick中斷,svc中斷,pendsv中斷。而svc、pendsv中斷都是FreeRtos系統啓動後纔會執行的。那最大可能就是systick中斷了。

接着在systick中斷函數打斷點,重新單步執行,看是否進入該中斷:確實進入了該中斷。

通過對這個中斷函數一步步執行,發現最終在此處出錯了:進入了HardFault_Handler。

定位到是系統滴答中斷systick導致進不去main函數的原因了,那哪裏開啓了這個中斷呢?通過代碼分析發現是bootloader程序開啓了這個中斷,在跳轉到main函數之前並未關閉這個中斷,導致出現了這中異常錯誤。

4.解決辦法

  既然是系統滴答中斷導致的進不去main函數,那就要在進入main函數之前關閉這個滴答中斷。

方法一: 在bootloader程序跳轉到app層時就關閉系統滴答中斷:SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

方法二:在SystemInit函數關閉系統滴答中斷:SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; (如下圖所示)

5.總結

  在實際項目運用過程中,遇到類似這些奇葩現象,可以嘗試通過仿真調試,一步步嘗試可能出現錯誤的地方,進行打斷點分析,找出根因所在,你的點贊是我最大的動力。  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章