STM32 位带操作 Bit-band operation详解

1.STM32位带区和位带别名区

参考书籍《The Defi nitive Guide to the ARM Cortex-M3》

Bit-band operation support allows a single load/store operation to access (read/write) to a single data bit. In the Cortex-M3, this is supported in two predefi ned memory regions called bit-band regions. One of them is located in the fi rst 1 MB of the SRAM region, and the other is located in the fi rst 1 MB of the peripheral region.

处理器存储器映射包括两个 bit-banding 区域。它们分别为 SRAM 和外设存储区域中的最低的 1MB。这些 bit-band 区域将存储器别名区的一个字映射为 bit-band 区的一个位。Cortex-M3 存储器映射有 2 个 32MB 别名区,它们被映射为两个 1MB 的 bit-band 区。

2.STM32内存图

32MB的 SRAM 别名区的访问映射为对 1MB SRAMbit-band 区的访问。如图

32MB 的外设别名区的访问映射为对 1MB 外设 bit-band 区的访问。如图

3.Bit-band原理

把每个比特膨胀或者说映射到一个32位的字,当访问这些字的时候就达到了访问比特的目的,比如说BSRR寄存器有32个位,那么可以映射到32个地址上,直接去访问(读-改-写)这32个地址就达到访问32个比特的目的。

4.优点1-操作简单:

文档这样说

当我们读一个寄存器中的某一个位值的时候如下操作。

 

汇编语言程序:

当我们写一个寄存器中的某一个位值的时候如下操作。

 

汇编语言程序

当需要从一个32位寄存器中读/写/改某一个位值的时候,首先需要先将这个32位寄存的值都拿出来,然后根据需要经过偏移、按位或、按位与运算来读/写/改某一位的值。但是当我们使用bit-band操作时候,因为bit-band是将寄存器中某一个位映射或者说膨胀到一个具体地址上(bit-band alias),因此当我们需要读/写/改某一个位时候,就可以直接对bit-band alias地址进行操作,这样就大大提高了程序的执行效率。

通过上图就可以看出当使用bit-band操作方法直接对bit-band alias操作的时候明显比普通的操作执行效率更高,代码量也更少。

5.优点2-多任务中实现共享资源的互斥访问

当不使用bit-band操作时,也可以使用互斥锁来保证共享资源的安全。

 

 

 

 

还有一种情况在任务程序中

 

6.实际应用

0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB)

用GPIO举例

 

6.1转换成实际应用代码

/* Peripheral base address in the alias region */
#define PERIPH_BASE           ((uint32_t)0x40000000) 

/* Peripheral memory map */
#define APB1PERIPH_BASE       PERIPH_BASE
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

/* gpio memory map */
#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE            (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE            (APB2PERIPH_BASE + 0x2000)

/*Port _OUTput data register Address offset*/
#define ODR_OFFSET 0x0C
/*Port input data register*/
#define IDR_OFFSET 0x08
/*the starting address of the alias region*/
#define BIT_BAND_BASE 0x2000000

/*寄存器位带地址映射转换*/
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+BIT_BAND_BASE+((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+ODR_OFFSET) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+ODR_OFFSET) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+ODR_OFFSET) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+ODR_OFFSET) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+ODR_OFFSET) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+ODR_OFFSET) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+ODR_OFFSET) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+IDR_OFFSET) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+IDR_OFFSET) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+IDR_OFFSET) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+IDR_OFFSET) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+IDR_OFFSET) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+IDR_OFFSET) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+IDR_OFFSET) //0x40011E08  

/* IO口操作,只对单一的IO口! 确保n的值小于16! */
#define GPIOA_OUT(bit_num)   BIT_ADDR(GPIOA_ODR_Addr,bit_num)  //输出 
#define GPIOA_IN(bit_num)    BIT_ADDR(GPIOA_IDR_Addr,bit_num)  //输入 

#define GPIOB_OUT(bit_num)   BIT_ADDR(GPIOB_ODR_Addr,bit_num)  //输出 
#define GPIOB_IN(bit_num)    BIT_ADDR(GPIOB_IDR_Addr,bit_num)  //输入 

#define GPIOC_OUT(bit_num)   BIT_ADDR(GPIOC_ODR_Addr,bit_num)  //输出 
#define GPIOC_IN(bit_num)    BIT_ADDR(GPIOC_IDR_Addr,bit_num)  //输入 

#define GPIOD_OUT(bit_num)   BIT_ADDR(GPIOD_ODR_Addr,bit_num)  //输出 
#define GPIOD_IN(bit_num)    BIT_ADDR(GPIOD_IDR_Addr,bit_num)  //输入 

#define GPIOE_OUT(bit_num)   BIT_ADDR(GPIOE_ODR_Addr,bit_num)  //输出 
#define GPIOE_IN(bit_num)    BIT_ADDR(GPIOE_IDR_Addr,bit_num)  //输入

#define GPIOF_OUT(bit_num)   BIT_ADDR(GPIOF_ODR_Addr,bit_num)  //输出 
#define GPIOF_IN(bit_num)    BIT_ADDR(GPIOF_IDR_Addr,bit_num)  //输入

#define GPIOG_OUT(bit_num)   BIT_ADDR(GPIOG_ODR_Addr,bit_num)  //输出 
#define GPIOG_IN(bit_num)    BIT_ADDR(GPIOG_IDR_Addr,bit_num)  //输入

7.使用

设置GPIOA的第5位输出高电平

/* 不使用位带操作 */
GPIOA->ODR|=1<<5; 

/* 使用位带操作 */
GPIOA_OUT(5)  = 1;

猜你喜欢

转载自blog.csdn.net/yuupengsun/article/details/106957337