STM32学习笔记:位带操作(Bit_band Operations)

注意:本文中关于STM32的位带操作原理只适用于Cortex-M3和Cortex-M4(F)内核处理器,Cortex-M系列的其他内核处理器可能不支持位段操作(如Cortex-M0内核处理器就不支持位段操作),详情请参考相关内核处理器的指南或技术参考手册(TRM)。
1、位带操作
CPU不能直接对位带区中的单个数据位位寻址,只能通过对位带别名区的访问(或读/写)实现对位带区单个数据位的访问(或读/写),这种操作被称为位带操作。Cortex-M3和Cortex-M4(F)内核处理器预定义了2个这样的存储器区域,分别位于SRAM的头1MB和片上外设区域的头1MB。详情参考Cortex-M3和Cortex-M4内核处理器的存储器映射,如图1所示。
注意:MCS-51核单片机支持直接位寻址。MCS-51核汇编指令集中有专门的汇编指令用于对可位寻址的存储器单元位寻址,而支持51核的C编译器提供了增强C语言对硬件控制的扩展类型关键字(如sbit)用于在C程序中定义位操作变量。并且和其他编译器一样,C编译器提供的51核MCU头文件中对存储器中的特殊功能寄存器(即存储器映射寄存器)做了封装,以便将寄存器名作为变量在程序中直接使用。C语言允许将局部变量的值放在CPU中的寄存器中,所以若C程序中用关键字register声明一个变量为内核寄存器变量,那么这个变量的值将直接存储到处理器内核中的寄存器中,需要时CPU直接从内核寄存器中取出参加运算,由于CPU对内核寄存器的存取速度远高于对内存的存取速度,所以这样将提高程序的执行效率。其实如今的编译器优化后,CPU会将内存中的变量值实时copy一份暂存在处理器内核寄存器中以便快速对内存存取。
位带区(bit-band):支持位带操作的存储器地址区域。
位带别名区(bit-band alias):存储器位带区的重映射地址区域。访问位带别名区域会引起对位带区域的访问(读/写)。

图1 Cortex-M3和Cortex-M4内核处理器的存储器映射
2、位带操作的C程序实现
位带别名区中,从其起始地址开始的每一个字的存储空间中,只有其最低位的数据LSB(bit[0])被使用,所以对位带别名区的访问必须是按4个字节对齐的(数据按4字节对齐依次排列)。那么,一个数据位就对应一个字的空间(1:32),所以图1中位带区的大小与位带别名区的大小比分别为1MB和32MB。
(1)片上SRAM位带地址的重映射
由图1可知,
片上SRAM的位带区地址范围:0x20000000-0x20100000
片上SRAM的位带别名区地址范围:0x22000000-0x23FFFFFF

图2 片上SRAM位带地址的重映射
由图2 位带地址的重映射可以求得片上SRAM中,映射到位带区目标位的别名位带区的字地址:
对比图2中16进制序列:(位带区字地址偏移-位带别名区字地址偏移)
0-0,0-4,0-8……4-80,4-84,4-88……8-100,8-104,8-108……C-180,C-184,C-188……
可知位带区字地址偏移左移5位后等于位带别名区字地址偏移。
再观察图2中的位带别名区,发现位带别名区字地址偏移 0x00000000-0x01FFFFFC刚好有32MB,所以
位带别名区的字地址==位带别名区的基地址+位带别名区的字地址偏移=0x22000000+位带别名区的字地址偏移 (1)
位带别名区的字地址偏移==(位带区目标位所在的字地址偏移<<5 )+( 位带区目标位编号<<2) (2)
因此,位带别名区的字地址==0x22000000+ (位带区目标位所在的字地址偏移<<5) + (位带区目标位编号<<2) ① (注:位带区目标位编号0-31)
(2)片上外设位带地址的重映射
由图1可知,
片上外设的位带区地址范围:0x40000000-0x40100000
片上外设的位带别名区地址范围:0x42000000-0x43FFFFFF

图3 片上外设位带地址的重映射
同理,按照(1)中的分析方法一样,可求得片上外设中,映射到位带区目标位的别名位带区的字地址:
位带别名区的字地址==0x42000000+ (位带区目标位所在的字地址偏移<<5) + (位带区目标位编号<<2) ② (注:位带区目标位序号0-31)
为了方便起见,可以将式①和式②统一成一个公式(用位带区目标位所在的字地址和目标位序号表示位带别名区字地址):
位带别名区的字地址==(位带区目标位所在的字地址&0xF0000000)+0x02000000+ [(位带区目标位所在的字地址&0xFFFFF)<<5 ] + (位带区目标位编号<<2) ③ (注:位带区目标位序号0-31)
所以,为了达到MSC-51一样的位寻址操作效果,在C程序中用宏定义一下:

/将“位带地址+位序号”转换成位带别名地址的宏定义,并强制转换成指针*/

#define Bit_Band(addr,num)  *((volatile unsigned long*)((addr&0xF0000000)+0x02000000+((addr&0xFFFFF)<<5)+(num<<2)))
1
这样,只需要对”Bit_Band(addr,num)”操作,就可以达到对位带别名区的访问,从而实现对位带区单个数据位的访问,间接实现“位寻址”的效果。
 

你可能感兴趣的:(STM32)