STM32位带操作

stm32位带操作

要点:找到需要带操作的寄存器的地址,并把它转换为位带别名区地址。

1. 什么是位带?

通过普通的加载、存储指令来对单一的比特进行读写。例如下面就可以对P0^1口进行置位和复位。

P0^1 = 1;
P0^1 = 0;

在stm32开发过程中,如果使用库函数开发可以不使用位带操作。可以使用如下代码:

GPIO_SetBits(GPIO_IIC,IIC_SCL_Pin);
GPIO_SetBits(GPIO_IIC,IIC_SDA_Pin);

2. 位带别名区

在CM3中有两个区实现了位带。一个是SRAM区的最低1MB范围(0x2000_0000‐0x200F_FFFF ),第二个则是片内外设区的最低1MB范围(0x4000_0000‐0x400F_FFFF)。
这两个区中的地址除了可以像普通的RAM一样使用外,它们还有自己的“位带别名区”,位带别名区把每个比特膨胀成一个32位的字。
当通过位带别名区访问这些字的时候,就可以达到访问原始比特的目的。
(此处详见《Cortex-M3权威指南》)

1 Byte = 8 bit
1 KB   = 1024 Byte
1 MB   = 1024 KB

位带区(1MB): 支持位带操作的地址区
位带别名区(32MB): 对别名地址的访问最终作用到位带区的访问上(注:这中途有一个地址映射过程 )

LSB:最低有效位
在位带区中,每个比特都映射到别名地址区的一个字(一个字包含4个字节,也就是32比特,32位)——这是只有LSB有效的字。
当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到LSB,并把LSB返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。

对 SRAM 位带区的某个比特,记它所在字节地址为 A,位序号为n(0<=n<=7),则该比特在别名区的地址为:

AliasAddr = 0x22000000+((A-0x20000000)*8+n)*4 = 0x22000000+(A-0x20000000)*32+n*4

对于片上外设位带区:

AliasAddr = 0x42000000+((A-0x40000000)*8+n)*4 = 0x42000000+(A-0x20000000)*32+n*4

SRAM区中的位带地址映射

位带区 等效的别名地址
0x20000000.0 0x22000000.0
0x20000000.1 0x22000004.0
0x20000000.2 0x22000008.0
... ...
0x20000000.31 0x2200007C.0
0x20000004.0 0x22000080.0

download

3. 工程实例

//将位带地址+序号转换为别名地址的宏。
//此处左移5就等价于乘于32,左移2就等价于乘于2.
#define BITBAND(addr,bitnum)  ((addr & 0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))

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

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

#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808

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

#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

//设置输入输出方向寄存器后给GPIOA的1口置位和复位只需要如下代码所示,这样再对IO操作是不是就很简单了。

PAout(1)=1;
PAout(1)=0;
posted @ 2022-02-08 21:31  slyuan  阅读(398)  评论(0编辑  收藏  举报