M3,M4核心都支援硬體位帶操作,M7核心不支援。
硬體位帶操作優勢
優勢1:
比如我們在地址0x2000 0000定義了一個變數unit8_t a, 如果我們要將此變數的bit0清零,而其它bit不變。
a & = ~0x01
這個過程就需要讀變數a,修改bit0,然後重新賦值給變數a,也就是讀 - 修改 - 寫經典三部曲,如果我們使用硬體位帶就可以一步就完成,也就是所謂的原子操作,優勢是不用擔心中斷或者RTOS任務打斷。
優勢2:
操作便捷,適合用於需要頻繁操作修改的場合,移植性強。不頻繁的直接標準庫,LL庫或者HAL庫配置即可。
背景知識
知道不知道都沒有關係,不影響我們使用硬體位帶,可以直接看後面案例的操作方法,完全不需要使用者去了解。
位帶操作就是對變數每個bit的操作,以M4核心的STM32F4為例:
1。 將1MB地址範圍 0x20000000-0x200FFFFF
對映到32MB空間範圍0x22000000 - 0x23FFFFFF ——> 這個對應STM32F4的通用RAM空間。
也就是說1MB空間每個bit都拓展為32bit來訪問控制:
0x20000000地址的位元組變數 bit0 對映到0x22000000來控制。
0x20000000地址的位元組變數 bit1對映到0x22000004來控制。
0x20000000地址的位元組變數 bit2對映到0x22000008來控制。
……。。。。依次類推
對映到32MB空間範圍0x42000000 - 0x43FFFFFF ——> 這個對應STM32F4的外設空間。
同樣也是1MB空間每個bit都拓展為32bit來訪問控制:
(3)舉例,比如訪問0x2000 0010地址裡面位元組變數的bit2
那麼實際要訪問的就是:
透過對地址空間0x22000208 進行賦值為0x01就表示bit2置位,賦值為0x00就表示bit2清零,對這個地址空間讀取操作就可以反應bit2的數值。
超簡單實現方案和四個經典方案
這種硬體未帶讓使用者去使用非常不方便,還需要倒騰地址計算。這裡以MDK為例,提供一種IDE支援的,直接加字尾__attribute__((bitband))即可,對於M3和M4可以直接轉換為硬體位帶實現。
案例1:超簡單控制RAM空間變數:
定義:
我們定義了一個8bit的變數tTestVar,控制每個bit的方法如下:
看彙編,已經修改為硬體位帶:
案例2:超簡單控制GPIO輸入輸出暫存器:
GPIO裡面最常用的就是輸入輸出。GPIO輸入暫存器定義如下,每個bit控制一個IO引腳。
我們軟體定義如下:
GPIO輸入暫存器定義如下:
我們軟體定義如下:
實際操作效果動態,注意看除錯狀態暫存器變化,控制GPIOA的PIN0到PIN3:
案例3:超方便的暫存器修改
比如定時器TIM1的CR暫存器:
我們的定義如下:
實際操作動態效果,注意看除錯狀態暫存器變化,設定TIM1 CR1暫存器的每個bit控制:
由於標準庫,HAL庫配置這些已經非常方便了,我們再使用這種方式意義不是很大,但對於需要頻繁操作的地方,這種方式就非常好使了,言簡意賅,移植性強,強力推薦,而且是原子操作方式,不用怕中斷打斷。
案例4:應用進階
最後我們來個進階,比如我們透過32位頻寬的FMC匯流排擴展出來32個GPIO,如果我們採用如下使用方式就非常不直觀
操作bit1 =0清零,就需要如下操作:
操作bit2和bit10置位,就需要如下操作:
這種操作會導致以後的程式碼修改非常不便,別人移植使用也非常不方便。如果我們改成如下方式,就方便太多了。
比如控制AD7606的OS0引腳高電平就是
控制OS0引腳是低電平就是:
簡單易用,超方便。
M7核心為什麼不支援
M核心權威指南作者Joseph Yiu回覆:
1、Cache問題,如果SRAM所在區域開啟了讀寫Cache,使用位帶操作的話,會有資料一致性問題。
2、位帶需要匯流排鎖機制,在AHB匯流排協議中這相對容易實現,但在AXI匯流排協議中這有點混亂,並且在鎖定序列期間,它可能導致其他匯流排主控的延遲更長。