日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

单片机(MCU)如何才能不死机之对齐访问(Aligned Access)

發布時間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单片机(MCU)如何才能不死机之对齐访问(Aligned Access) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

從一個結構體說起。如下,在 STM32F0 的程序中,我們定義了一個結構體My_Struct ,那么這個結構體占用多少內存呢?

struct?Struct_Def?{ uint8_t?Var_B; uint16_t?Var_W0; uint16_t?Var_W1; uint32_t?Var_DW; }; struct?Struct_Def?My_Struct; int?main(void) {??My_Struct.Var_B?=?0x01;??My_Struct.Var_W0?=?0x0203;??My_Struct.Var_W1?=?0x0405;??My_Struct.Var_DW?=?0x06070809;????while(1); }

我們粗略一算,1 + 2 + 2 + 4 = 9 Bytes 。

下載到芯片,觀察一下變量,似乎沒錯。

圖片

如果有更進一步的好奇心,我們來到內存中實際看一下,可能會有出乎意料的發現:

圖片

編譯器在 Var_B 之后插入了一個字節,在 Var_W1 之后插入了兩個字節。這個結構體在內存中實際占用了 1 + 1 + 2 + 2 + 2 + 4 = 12 Bytes 。

為什么會這樣呢?這是 ARM Cortex M0 體系決定的,它只支持對齊訪問 ( Aligned Access )。比如我們訪問一個 4 字節 (Double Word) 型的變量時,如果這個變量的起始地址是能被 4 整除的話,我們說這種訪問是雙字節對齊的。如果訪問一個 2 字節 ( Word ) 變量,當起始地址能被 2 整除時是對齊的。訪問字節 ( Byte ) 型變量,總是對齊的。

那么如果進行了非對齊訪問呢?那就會產生一個嚴重錯誤 ( HardFault ) !!!

大家看一下例子中的這一個賦值語句:

My_Struct.Var_DW = 0x06070809;

它是一個 4 字節 ( Double Word ) 型的變量賦值。Var_DW 這個成員,如果按照在結構體中的順序,應該緊隨 Var_W1 之后,分配在 0x20000012,但是這個地址是不能被 4 整除的,所以編譯器在填充了 2 個字節 0 之后,把 Var_DW 的起始地址分配在了 0x20000014 。

圖片

到這里大家肯定會有一個疑問,這樣豈不是很浪費 RAM 嗎?RAM 又是相對來說價格比較高的。特別是在結構體比較多的情況下,大量的 RAM 白白浪費了!

還好,在這里我們可以用到偽指令 #pragma pack 了。

如下例所示,#pragma pack(1) 將會使結構體中的變量一個字節緊挨著一個字節在內存中分配,而不再考慮是否對齊的問題。可以看到結構體占用從 0x2000000C 到 0x20000014 的9個字節 RAM空間。

#pragma?pack(1) struct?Struct_Def? {uint8_t?Var_B;uint16_t?Var_W0;uint16_t?Var_W1;uint32_t?Var_DW; }; struct?Struct_Def?My_Struct; #pragma?pack()

那么問題來了,當我們讀寫地址非對齊的變量時,不就會產生 HardFault 嗎?

在這里,編譯器采取了曲線救國的方針。大家看下面賦值語句對應的匯編部分就會看到,它用 4 個STRB 指令(單字節操作,無論任何地址都是對齊操作), 代替了 1 個 STR 指令 ( 4 字節操作 )。如此,犧牲了一些效率,但是節省了內存空間。

圖片

這種用法節省了 RAM,但是帶來了一種比較隱蔽的錯誤。尤其是當我們用指針方式訪問這些變量時,編譯器無法發現錯誤,而且只有當語句實際執行時才會引起問題。所以在使用指針式要特別注意,指針所指向的地址,是否和指針類型所需要的地址對齊方式吻合。

以上面的 RAM 分配方式為例,非對齊訪問時會導致 MCU 進入 HardFault 。

volatile?uint32_t?Test_Var; Test_Var?=?*(uint8_t?*)(&My_Struct.Var_B);?//?這句是可以正確執行的Test_Var?=?*(uint16_t?*)(&My_Struct.Var_W0);?//?非對齊訪問,進入?HardFaultTest_Var?=?*(uint32_t?*)(&My_Struct.Var_DW);?//?非對齊訪問,進入?HardFault

對于變量的定義,我們還可以用下面的偽指令把變量以 n 字節對齊:

__align(n)

大家在實際工程中可以根據實際情況靈活的選擇和使用這些偽指令。


推薦閱讀:

專輯|Linux文章匯總

專輯|程序人生

專輯|C語言

我的知識小密圈

關注公眾號,后臺回復「1024」獲取學習資料網盤鏈接。

歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~

總結

以上是生活随笔為你收集整理的单片机(MCU)如何才能不死机之对齐访问(Aligned Access)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。