STM32 M3內核的位帶操作原理及步驟


STM32 M3內核的位帶操作原理及步驟

一、位帶操作有什么用?什么是位帶操作

    位帶操作的作用:可以實現對某一GPIO口寄存器(或SRAM內存中)的某一bit位直接寫0或1,達到控制GPIO口輸出(或改變SRAM中這一bit位的值);就如同51單片機控制GPIO口一樣的方便。比如:

       51:P1^0=1;  //把P1口的第一個引腳設置為高電平

       STM32:PAout(0)=1;   //把PA口的第一個引腳設置成高電平

    位帶操作的原理:在 CM3 中,有兩個區中實現了位帶,如下圖,其中一個是 SRAM 區的最低 1MB 范圍,第二個則是片內外設區的最低 1MB范圍。

 

     這兩個區中的地址除了可以像普通的 RAM 一樣使用外,它們還都有自己的“位帶別名區”,位帶別名區把每個比特(1bit)膨脹成一個 32 位(4個字節)。當你通過位帶別名區訪問這些字時,就可以達到訪問原始比特的目的。1MB位帶區對應32MB位帶別名區(1byte=8bit映射成8*4byte=32byte)。

 

    位帶區和位帶別名區的映射如下圖:

 

 

 

    位帶區:支持位帶操作的地址區

   位帶別名:對別名地址的訪問最終作用到位帶區的訪問上(這中途有一個地址映射過程)

 

    映射過程舉例如下:

       要設置0x2000 0000這個字節的第二個位bit2為1,使用位帶操作的步驟有:1、將1寫入位    帶別名區對應的映射地址(即0x22000008,因為1bit對應4個byte);2、將0x2000 0000的值    讀取到內部的緩沖區(這一步驟是內核完成的,屬於原子操作,不需要用戶操作);3、將bit2    置1,再把值寫 回到0x2000 0000(屬於原子操作,不需要用戶操作)。

  

    映射過程總結:在位帶區中,每個比特都映射到別名地址區的4個字節——且4個字節只有最低位有效。當一個別名地址被訪問時,會先把該地址變換成位帶地址。對於讀操作,讀取位帶地址中的4個字節(因為數據總線是32位的,寄存器也是32位的,所以是讀4個字節),再把需要的位右移到最低有效位,並把最低有效位返回(相當於將位帶區的值右移再做與操作)。對於寫操作,把需要寫的位左移至對應的位序號處(相當於把1(或0)左移n(n為該bit位所在的位置)位再和位帶區的值做與操作),然后執行一個原子的“讀-改-寫”過程。

    位帶操作的優點:1、操作簡單;2、因為進行的是原子操作,可以防止對寄存器的臟寫。

 

二、位帶操作的代碼實現解析

         這部分內容參考《STM32F3與F4系列Cortex M4內核編程手冊》,先貼原文:

         A word access to the SRAM or peripheral bit-band alias regions map to a single bit in the SRAM or peripheral bit-band region.

         Bit band accesses can use byte, halfword, or word transfers. The bit band transfer size matches the transfer size of the instruction making the bit band access.

         The following formula shows how the alias region maps onto the bit-band region:

                   bit_word_offset = (byte_offset x 32) + (bit_number x 4)

                   bit_word_addr = bit_band_base + bit_word_offset

 

Where:

  • Bit_word_offset is the position of the target bit in the bit-band memory region.

•      Bit_word_addr is the address of the word in the alias memory region that maps to the

                   targeted bit.

•      Bit_band_base is the starting address of the alias region.

•      Byte_offset is the number of the byte in the bit-band region that contains the targeted

                   bit.

  • Bit_number is the bit position, 0-7, of the targeted bit.

 

 

         這段英文介紹了位帶區和位帶別名區的地址映射關系。要獲得某個位帶區地址在位帶別名區的映射地址,按照上面的公式即可求出。下面一一解釋:

                   bit_word_offset:基於位帶別名區起始地址的偏移;

                   bit_word_addr:映射在位帶別名區的地址(即為所求的地址);

                   Bit_band_base:位帶別名區的起始地址,如下圖中編號3所示;

                   Byte_offset:該字節(或32位字)相對於位帶區起始地址的偏移;

                   Bit_number:該bit位在所在字節(或32位字)中的位置,范圍0~7(0~31),如下圖中編號1所示;

                   bit_number x 4:4表示一bit位在位帶別名區占4個字節的地址空間  

 

 

下面用實例來進行敘述:

參考資料中的實例:    

         1、位帶區起始地址在位帶別名區的地址映射:

         The alias word at 0x2200001C maps to bit[7] of the bit-band byte at 0x20000000:

                   0x2200001C = 0x22000000+ (0*32) + (7*4)

 

         2、位帶區結束地址在位帶別名區的地址映射:

         The alias word at 0x23FFFFED maps to bit[0] of the bit-band byte at 0x200FFFFF:

                   0x23FFFFED = 0x22000000 + (0xFFFFF*32) + (0*4)

                   下面解釋一下,0x00000~0xFFFFF為1MB的地址;0~7表示一個字節中某一bit位的位置;0x2200 0000表         示位帶別名區的起始地址;0xFFFFF*32=0xFFFFF*8*4,表示0xFFFFF*8個bit位在位帶別名區所占的地址空間。

 

         代碼中的實例分析:

                   #define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //輸出

 

                   #define GPIOA_ODR_Addr    (GPIOA_BASE+20)  //0x40020014表示GPIOA->ODR寄存器的地址

 

                   #define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

         #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))

         #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))

                  

上面的宏定義合成一條:

         #define   PAout(n) \

*((volatile unsigned long *)(( GPIOA_ODR_Addr & 0xF0000000)+0x2000000+(( GPIOA_ODR_Addr &0xFFFFF)<<5)+(n<<2))

其中:

         GPIOA_ODR_Addr & 0xF0000000=0x4000 0000

         (GPIOA_ODR_Addr &0xFFFFF)<<5=0x0002 0014*32

         n<<2=n*4

即:PAout(n)= 0x4000 0000+0x2000000+0x0002 0014*32+ n*4

                      =0x4200 0000+0x0002 0014*32+ n*4

看到這里應該就能看出,這個公式和參考手冊中的公式是一樣的,是不是很簡單!

 

接下來說下位帶操作編程步驟,拿GPIO口舉例:

一、宏定義GPIO口輸入輸出寄存器地址

二、找到位帶區起始地址和位帶別名區起始地址

三、根據公式做地址換算

四、宏定義PA(n)~PI(n)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM