STM32中的位帶(bitband)操作(轉(zhuǎn))
位帶操作的概念其實(shí) 30 年前就有了,那還是8051 單片機(jī)開創(chuàng)的先河,如今,CM3 將此能力進(jìn)化,這里的位帶操作是 8051 位尋址區(qū)的威力大幅加強(qiáng)版。
CM3 使用如下術(shù)語來表示位帶存儲的相關(guān)地址:
位帶區(qū):支持位帶操作的地址區(qū)
位帶別名:對別名地址的訪問最終作用到位帶區(qū)的訪問上(這中途有一個(gè)地址映射過程)
在位帶區(qū)中,每個(gè)比特都映射到別名地址區(qū)的一個(gè)字——這是只有 LSB 有效的字。當(dāng)一個(gè)別名地址被訪問時(shí),會先把該地址變換成位帶地址。對于讀操作,讀取位帶地址中的一個(gè)字,再把需要的位右移到 LSB,并把 LSB 返回。對于寫操作,把需要寫的位左移至對應(yīng)的位序號處,然后執(zhí)行一個(gè)原子的“讀-改-寫”過程。
支持位帶操作的兩個(gè)內(nèi)存區(qū)的范圍是:
0x2_0‐0x200F_FFFF(SRAM 區(qū)中的最低 1MB)
0x4_0‐0x400F_FFFF(片上外設(shè)區(qū)中的最低 1MB)
對 SRAM 位帶區(qū)的某個(gè)比特,記它所在字節(jié)地址為 A,位序號為 n(0<=n<=7),則該比特在別名區(qū)的地址為:
AliasAddr=0x22+((A-0x20)*8+n)*4=0x22+(A-0x20)*32+n*4
對于片上外設(shè)位帶區(qū)的某個(gè)比特,記它所在字節(jié)的地址為 A,位序號為 n(0<=n<=7),則該比特在別名區(qū)的地址為:
AliasAddr=0x42+((A-0x40)*8+n)*4=0x42+(A-0x40)*32+n*4
上式中,“*4”表示一個(gè)字為 4 個(gè)字節(jié),“*8”表示一個(gè)字節(jié)中有 8 個(gè)比特。
這里再不嫌啰嗦地舉一個(gè)例子:
1. 在地址 0x20 處寫入 0x3355AACC
2. 讀取地址0x22008。本次讀訪問將讀取 0x20,并提取比特 2,值為 1。
3. 往地址 0x22008 處寫 0。本次操作將被映射成對地址 0x20 的“讀-改-寫”操作(原子的),把比特2 清 0。
4. 現(xiàn)在再讀取 0x20,將返回 0x3355AAC8(bit[2]已清零)。
位帶別名區(qū)的字只有 LSB 有意義。另外,在訪問位帶別名區(qū)時(shí),不管使用哪一種長度的數(shù)據(jù)傳送指令(字/半字/字節(jié)),都把地址對齊到字的邊界上,否則會產(chǎn)生不可預(yù)料的結(jié)果。
/////////////////////////////////////////////////////////////////位帶操作,實(shí)現(xiàn)51類似的GPIO控制功能//具體實(shí)現(xiàn)思想,參考<>第五章(87頁~92頁).//IO口操作宏定義#define BITBAND(addr, bitnum) ((addr & 0xF0)+0x2+((addr &0xFFFFF)<<5)+(bitnum<<2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) //IO口地址映射#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 #define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008 #define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408 #define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808 #define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08 #define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08 //IO口操作,只對單一的IO口!//確保n的值小于16!#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //輸出 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //輸入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //輸出 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //輸入 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //輸出 #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //輸入 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //輸出 #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //輸入 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //輸出 #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //輸入#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //輸出 #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //輸入#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //輸出 #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //輸入
評論