当前位置:首页 > 单片机 > 单片机
[导读]STM32支持了位带操作(bit_band),有两个区中实现了位带。其中一个是SRAM 区的最低1MB 范围,第二个则是片内外设 区的最低1MB 范围。这两个区中的地址除了可以像普通的RAM 一样使用外,它们还都有自己的“位带别名区

STM32支持了位带操作(bit_band),有两个区中实现了位带。其中一个是SRAM 区的最低1MB 范围,第二个则是片内外设 区的最低1MB 范围。这两个区中的地址除了可以像普通的RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区 把每个比特膨胀成一个32 位的字。

每个比特膨胀成一个32 位的字,就是把 1M 扩展为 32M , 于是;RAM地址 0X200000000(一个字节)扩展到8个32 位的字,它们是:(STM32中的SRAM依然是8位的,所以RAM中任一地址对应一个字节内容)

0X220000000 ,0X220000004,0X220000008,0X22000000C,0X220000010,0X220000014, 0X220000018,0X22000001C


支持位带操作的两个内存区的范围是:

0x2000_0000‐0x200F_FFFF(SRAM 区中的最低1MB)

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

CM3 使用如下术语来表示位带存储的相关地址:
位带区:支持位带操作的地址区
位带别名:对别名地址的访问最终作用到位带区的访问上(这中途有一个地址映射过程)
在位带区中,每个比特都映射到别名地址区的一个字——这是只有 LSB 有效的字。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到 LSB,并把 LSB 返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。

举一个例子:
1. 在地址 0x20000000 处写入 0x3355AACC
2. 读取地址0x22000008。本次读访问将读取 0x20000000,并提取比特 2,值为 1。
3. 往地址 0x22000008 处写 0。本次操作将被映射成对地址 0x20000000 的“读-改-写”操作(原子的),把比特2 清 0。
4. 现在再读取 0x20000000,将返回 0x3355AAC8(bit[2]已清零)。
位带别名区的字只有 LSB 有意义。另外,在访问位带别名区时,不管使用哪一种长度的数据传送指令(字/半字/字节),都把地址对齐到字的边界上,否则会产生不可预料的结果。

对SRAM 位带区的某个比特,记它所在字节地址为A,位序号

在别名区的地址为:

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

对于片上外设位带区的某个比特,记它所在字节的地址为A,位序号为n(0<=n<=7),则该比特

在别名区的地址为:

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

上式中,“*4”表示一个字为4 个字节,“*8”表示一个字节中有8 个比特。


把“位带地址+位序号”转换别名地址宏

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

把该地址转换成一个指针

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

MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;


使用STM32库,例如点亮LED

GPIO_ResetBits(GPIOC, GPIO_Pin_4); //关LED5

GPIO_SetBits(GPIOC, GPIO_Pin_7); //开LED2


一般读操作

STM32_Gpioc_Regs->bsrr.bit.BR4 =1;// 1:清除对应的ODRy位为0

STM32_Gpioc_Regs->bsrr.bit.BS7 =1;// 1:设置对应的ODRy位为1


如果使用位带别名区操作

STM32_BB_Gpioc_Regs->BSRR.BR[4] =1;// 1:清除对应的ODRy位为0

STM32_BB_Gpioc_Regs->BSRR.BS[7] =1;// 1:设置对应的ODRy位为1

代码比STM32库高效十倍!


对内存变量的位操作。

1. // SRAM 变量

2.


3. long CRCValue;

4.


5. // 把“位带地址+位序号”转换别名地址宏

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

7. //把该地址转换成一个指针

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

9.


10. // 对32位变量 的BIT1 置 1 :

11.


12. MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;

13.


14. //对任意一位( 第23位 ) 判断:

15.


16. if(MEM_ADDR(BITBAND( (u32)&CRCValue,23))==1)

17. {

18.


19. }


-----------------------------------------------------------------


支持了位带操作(bit_band),有两个区中实现了位带。其中一个是SRAM 区的最低1MB 范围,第二个则是片内外设

// 区的最低1MB 范围。这两个区中的地址除了可以像普通的RAM 一样使用外,它们还都有自

// 己的“位带别名区”,位带别名区把每个比特膨胀成一个32 位的字

//

// 每个比特膨胀成一个32 位的字,就是把 1M 扩展为 32M ,

//

// 于是;RAM地址 0X200000000(一个字节)扩展到8个32 位的字,它们是:

// 0X220000000 ,0X220000004,0X220000008,0X22000000C,0X220000010,0X220000014, 0X220000018,0X22000001C

// 支持位带操作的两个内存区的范围是:

// 0x2000_0000‐0x200F_FFFF(SRAM 区中的

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

// 把“位带地址+位序号”转换别名地址宏

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

//把该地址转换成一个指针

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

// MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;

例如点亮LED

// 使用STM32库

GPIO_ResetBits(GPIOC, GPIO_Pin_4); //关LED5

GPIO_SetBits(GPIOC, GPIO_Pin_7); //开LED2

// 一般读操作

STM32_Gpioc_Regs->bsrr.bit.BR4 =1;// 1:清除对应的ODRy位为0

STM32_Gpioc_Regs->bsrr.bit.BS7 =1;// 1:设置对应的ODRy位为1

//如果使用位带别名区操作

STM32_BB_Gpioc_Regs->BSRR.BR[4] =1;// 1:清除对应的ODRy位为0

STM32_BB_Gpioc_Regs->BSRR.BS[7] =1;// 1:设置对应的ODRy位为1

代码比STM32库高效十倍!


// SRAM 变量

long CRCValue;

// 把“位带地址+位序号”转换别名地址宏

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

//把该地址转换成一个指针

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

// 对32位变量 的BIT1 置 1 :

MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;

//对任意一位( 第23位 ) 判断:

if(MEM_ADDR(BITBAND( (u32)&CRCValue,23))==1)

{

}


---------------------------------------------------------------------------------------------------------------------------------------------------------------


Cortex?-M3存储器映像包括两个位段(bit-band)区。这两个位段区将别名存储器区中的每个字映射到位段存储器区的一个位,在别名存储区写入一个字具有对位段区的目标位执行读-改-写操作的相同效果。

在STM32F10xxx里,外设寄存器和SRAM都被映射到一个位段区里,这允许执行单一的位段的写和读操作。

下面的映射公式给出了别名区中的每个字是如何对应位带区的相应位的:

bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)

其中:

bit_word_addr是别名存储器区中字的地址,它映射到某个目标位。

bit_band_base是别名区的起始地址。

byte_offset是包含目标位的字节在位段里的序号

bit_number是目标位所在位置(0-31)


在 CM3 支持的位段中,有两个区中实现了位段。


其中一个是 SRAM 区的最低 1MB 范围, 0x20000000 ‐ 0x200FFFFF(SRAM 区中的最低 1MB);


第二个则是片内外设区的最低 1MB范围, 0x40000000 ‐ 0x400FFFFF(片上外设区中的最低 1MB)。


在 C 语言中使用位段操作


在 C编译器中并没有直接支持位段操作。比如,C 编译器并不知道对于同一块内存,能够使用不同的地址来访问,也不知道对位段别名区的访问只对 LSB 有效。欲在 C中使用位段操作,最简单的做法就是#define 一个位段别名区的地址。例如:


#define DEVICE_REG0 ((volatile unsigned long *) (0x40000000))


#define DEVICE_REG0_BIT0 ((volatile unsigned long *) (0x42000000))


#define DEVICE_REG0_BIT1 ((volatile unsigned long *) (0x42000004))


...


*DEVICE_REG0 = 0xab;        //使用正常地址访问寄存器


*DEVICE_REG0_BIT1 = 0x1;


还可以更简化:


//把“位带地址+位序号” 转换成别名地址的宏


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

  //把该地址转换成一个指针


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


于是:


MEM_ADDR(DEVICE_REG0) = 0xAB;  //使用正常地址访问寄存器 


MEM_ADDR(BITBAND(DEVICE_REG0,1)) = 0x1;  //使用位段别名地址


注意:当你使用位段功能时,要访问的变量必须用 volatile 来定义。因为 C

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭