來源:公眾號【魚鷹談單片機】
作者:魚鷹Osprey
ID :emOsprey
最近在調試 can 通信,因為 c8t6 flash 很小,而魚鷹培訓工程完成的驅動越來越多,導致 flash 不足,因此把 bsp 的優化級別設置成-O2,誰知道在串口輸入數據時直接 hardfault 了:
進一步跟蹤發現問題出在這條代碼中:
uint32_tcnt=*((uint32_t*)pinfo->pdma_cnt_rx);// 出錯代碼 ..... pinfo->last_dma_cnt = cnt;
這條代碼最開始是這樣
uint16_tcnt=*((uint16_t*)pinfo->pdma_cnt_rx);
因為我的last_dma_cnt 變量是 16 bit,我想節省一下 ram 空間,因為實際上 DMA 的計數器也只使用了 16 bit。
uint16_t last_dma_cnt; // used in dma
但是測試時發現出現 hardfault 了,通過匯編分析發現是非四字節對齊訪問 dma 外設,后面通過修改代碼,強制使用 32 bit 訪問,就再也沒出現問題了。
uint32_t cnt = *(( uint32_t*)pinfo->pdma_cnt_rx);
但昨天修改完編譯優化級別后,又一次出現了,匯編分析發現還是對齊問題,因為0x4002005c 這個地址確實是 DMA 的計數器地址。
只是再優化后,沒按我的要求 32bit 訪問,而是自作主張使用16bit訪問,因為它發現 cnt 這個變量操作的地方都是 16 bit,想當然的給我在取值時也給我直接優化成 16 bit 訪問。
這樣一來,由于 DMA 不支持 2 字節訪問指令,因此直接 hardfault 了。為了解決這個優化問題,可以直接使用 volatile 關鍵字,保證編譯器在取值時按照 4 字節對齊訪問,如下:
uint32_t cnt = *((volatile uint32_t*)pinfo->pdma_cnt_rx); // must: volatile uint32_t 匯編代碼 0x0800BCA6 6800 LDR r0,[r0,#0x00]
完結撒花!
-
CAN通信
+關注
關注
5文章
94瀏覽量
17943 -
串口
+關注
關注
14文章
1558瀏覽量
77064 -
代碼
+關注
關注
30文章
4828瀏覽量
69058 -
編譯
+關注
關注
0文章
661瀏覽量
33047
原文標題:遇見一個編譯優化導致的 bug
文章出處:【微信號:emOsprey,微信公眾號:魚鷹談單片機】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論