1.概述
客戶(hù)在使用 STM32G070 的時(shí)候,KEIL MDK 為編譯工具,當(dāng)編譯優(yōu)化選項(xiàng)設(shè)置為L(zhǎng)evel0 的時(shí)候,程序會(huì)出現(xiàn) Hard Fault 異常,而當(dāng)編譯優(yōu)化選項(xiàng)設(shè)置為 Level1 的時(shí)候,則程序運(yùn)行正常。
表面上看,這似乎是 KEIL MDK 的問(wèn)題,通過(guò)分析,導(dǎo)致這個(gè)問(wèn)題的本質(zhì)原因是內(nèi)存地址沒(méi)有對(duì)齊引起的,下面章節(jié)將詳細(xì)分析該問(wèn)題的來(lái)龍去脈以及解決方法。
2.問(wèn)題描述與分析
根據(jù)客戶(hù)的反饋,引起問(wèn)題的代碼很簡(jiǎn)單,客戶(hù)定義了幾個(gè)全局?jǐn)?shù)組,在主程序中訪(fǎng)問(wèn)這幾個(gè)數(shù)組就會(huì)出現(xiàn) Hard Fault 異常,參考代碼如下。

把客戶(hù)提供的代碼片段移植到 NUCLEO-G070RB 開(kāi)發(fā)板上,問(wèn)題很容易就復(fù)現(xiàn)了,代碼本身功能簡(jiǎn)單,寫(xiě)法上也沒(méi)有錯(cuò)誤,所以從代碼片段本身上看,無(wú)法確定問(wèn)題出在哪里,通過(guò) KEIL 調(diào)試器,在匯編窗口單步調(diào)試下,最終發(fā)現(xiàn)導(dǎo)致 HardFault 異常的語(yǔ)句為下圖所示語(yǔ)句。

根據(jù)單步調(diào)試得知出現(xiàn)問(wèn)題的語(yǔ)句為 LDR 指令,參考 Cortex M0 編程手冊(cè) PM0223 得知 LDR 指令的作用是從內(nèi)存地址中加載一個(gè) WORD 數(shù)據(jù)到目的寄存器 Rt 中,其中內(nèi)存地址根據(jù) Rn 或者 SP 寄存器的值以及立即數(shù) imm 得到。

根據(jù)指令的描述,使用 LDR 指令的時(shí)候,通過(guò) Rn 和 imm 計(jì)算得到的內(nèi)存地址必須是讀取字節(jié)數(shù)的倍數(shù),LDR 每次讀取一個(gè) WORD,所以使用 LDR 指令時(shí),內(nèi)存地址必須 4字節(jié)對(duì)齊。如果地址沒(méi)有對(duì)齊,則會(huì)導(dǎo)致 HardFault 異常。
結(jié)合 LDR 指令的描述,在調(diào)試狀態(tài)下,通過(guò)查看寄存器值,圖 2 出錯(cuò)語(yǔ)句中根據(jù) Rn和 imm 計(jì)算得到的內(nèi)存地址為 R0=0x2000000B,imm=4 所以?xún)?nèi)存地址為 0x2000000F,很顯然這個(gè)地址不是 4 字節(jié)對(duì)齊的。

而當(dāng)我們改變編譯優(yōu)化選項(xiàng)為 Level1 時(shí),得到的內(nèi)存地址為R0=0x20000000,imm=0x04 顯然這個(gè)地址是按照 4 字節(jié)對(duì)齊的,所以這種情況下是不會(huì)出現(xiàn) HardFault 異常的,印證了客戶(hù)的問(wèn)題現(xiàn)象。

3.問(wèn)題解決
通過(guò)上一節(jié)的分析,明確了導(dǎo)致該問(wèn)題的本質(zhì)原因是內(nèi)存地址沒(méi)有對(duì)齊,這個(gè)內(nèi)存地址實(shí)際上是代碼中定義的全局變量 g_curPlaySound_app 指向的地址,也就是全局?jǐn)?shù)組變量 SoundFile 的地址,在編譯器不同的優(yōu)化選項(xiàng)下,分配給 SoundFile 變量的地址是不一樣的,在本案例中,編譯優(yōu)化選項(xiàng) Level0 條件下,SoundFile 分配的地址沒(méi)有按照WORD 對(duì)齊,而在優(yōu)化選項(xiàng) Level1 條件下,SoundFile 分配的地址是 WORD 對(duì)齊,所以在兩種優(yōu)化選項(xiàng)下,出現(xiàn)了不一樣的運(yùn)行結(jié)果。
所以要保證程序不出錯(cuò),當(dāng)通過(guò)指針訪(fǎng)問(wèn)變量的時(shí)候,要確保指針指向的地址是 4 字節(jié)對(duì)齊的,在 Keil 環(huán)境下,可以通過(guò)__attribute__((aligned (4))) 關(guān)鍵字實(shí)現(xiàn),如下圖所示,通過(guò)該關(guān)鍵字,對(duì)齊了地址,也就不會(huì)出現(xiàn) HardFault 異常了。
圖6 確保地址對(duì)齊

4.總結(jié)
地址未對(duì)齊是嵌入式系統(tǒng)中容易忽視的一個(gè)細(xì)節(jié),忽視這點(diǎn)往往會(huì)導(dǎo)致一些奇怪的問(wèn)題,所以在開(kāi)發(fā)過(guò)程中,注意這些細(xì)節(jié)還是很有必要的。
來(lái)源:STM32單片機(jī)
審核編輯:湯梓紅
-
單片機(jī)
+關(guān)注
關(guān)注
6074文章
45322瀏覽量
662892 -
嵌入式系統(tǒng)
+關(guān)注
關(guān)注
41文章
3716瀏覽量
133046 -
STM32
+關(guān)注
關(guān)注
2305文章
11118瀏覽量
370929 -
MDK
+關(guān)注
關(guān)注
4文章
211瀏覽量
33443
發(fā)布評(píng)論請(qǐng)先 登錄
基于DWC_ether_qos的以太網(wǎng)驅(qū)動(dòng)開(kāi)發(fā)-LWIP的堆(內(nèi)存池)未對(duì)齊導(dǎo)致問(wèn)題的案例分享
STM32H7 0x00000000地址的內(nèi)容引發(fā)hardfault怎么解決?
HardFault_Handler異常
靈動(dòng)微課堂 (第173講) | HardFault定位方法和步驟
為什么要進(jìn)行內(nèi)存對(duì)齊操作呢
導(dǎo)致STM32進(jìn)入HardFault異常的原因
ARM處理器是否曾經(jīng)為指令或數(shù)據(jù)訪(fǎng)問(wèn)生成未對(duì)齊的突發(fā)
iMXRT1170的cortex M7上的HardFault異常是怎么回事?
RISC-V未對(duì)齊訪(fǎng)問(wèn)導(dǎo)致問(wèn)題案例
異常向量表重映射
一個(gè)跟地址對(duì)齊有關(guān)的應(yīng)用異常案例
解決STM32因字節(jié)對(duì)齊問(wèn)題導(dǎo)致讀寫(xiě)Flash失敗進(jìn)入HardFault的問(wèn)題
工程師筆記|一個(gè)地址未對(duì)齊引起的 HardFault 異常
ES32F36xx芯片發(fā)生HardFault異常時(shí)的函數(shù)調(diào)用關(guān)系及問(wèn)題定位

一個(gè)地址未對(duì)齊引起的HardFault異常
評(píng)論