在實際的MCU產(chǎn)品開發(fā)中,開發(fā)人員經(jīng)常會遇到各種各樣的異常問題。發(fā)生異常時,有時MCU是真正“死機”了,例如在進行ESD實驗時,MCU可能真的死掉,即使通過NRST引腳復位也無法恢復。有時則是程序跑入了某個異常的分支,MCU本身仍在工作,只是表現(xiàn)出異常現(xiàn)象。
當發(fā)生異常時,如果能快速復現(xiàn),調試相對容易。最棘手的是那些難以復現(xiàn)的問題,比如經(jīng)常遇到“板子上電后工作正常,但持續(xù)帶電運行很長時間后才出現(xiàn)異常”的情況。此時,既不能給板子斷電,也不能讓其復位,因為這會破壞現(xiàn)場環(huán)境。假設這個異常并非MCU真的死掉,那么有沒有什么方法能知道當前MCU的程序運行到哪里了呢?
下面以一個簡單的測試代碼為例。我們在代碼最后一行故意寫了一條會導致進入HardFault的語句。

進入HardFault的原因是0x10000000是一個未映射、受保護或總線不可達的地址,對該地址的寫訪問會引發(fā)總線錯誤。
進入HardFault后,LED燈停止閃爍。那么,在不引起MCU復位的前提下,如何確認程序確實進入了HardFault呢?
我們對Keil MDK工程先進行如下配置,之后通過調試器SWD接口連接MCU
1)取消勾選“Update Target before Debugging”:不勾選此項,啟動調試時將不會自動重新燒寫固件,而是直接連接到目標設備,并調試目標上當前已有的固件。

2)取消勾選“Reset after Connect”:不勾選此項,調試器只會以“attach”模式連接到正在運行的固件,不會清除RAM和重置外設寄存器,從而保留程序的運行時狀態(tài)和外設配置。否則,調試器會發(fā)出硬件復位信號,將MCU置為初始狀態(tài)。

3)取消勾選“Load Application at Startup”:不勾選此項,連接調試器后,程序計數(shù)器(PC)將指向目標MCU正在執(zhí)行的指令地址。否則,PC會指向Reset_Handler,即程序入口。

完成上述配置后,進入Debug模式。此時可以在調試界面看到PC指針指向0x080000DE。
查看項目的map文件,可以發(fā)現(xiàn)這個地址對應的是HardFault_Handler函數(shù)。
補充說明:兩個地址末位相差1是因為ARM Cortex-M內核使用Thumb指令集,函數(shù)指針/符號通常帶有Thumb標志位(最低位bit0=1)。Map文件或符號表有時會保留此標志位,因此你會看到0x080000DF(即0x080000DE|1)。而Keil調試器顯示的是實際的字對齊代碼地址(忽略最低位),因此顯示為0x080000DE。
通過這種方法,可以輔助我們分析和定位部分MCU異常問題。
關注我們:
掃碼加入嵌入式交流群:
