[原创] Cortex-M3的位带操作

Jerryzgj   2014-12-17 14:12 楼主
    位操作由51单片机而来,结合自己最近看到的一个关于Cortex-M3位操作的介绍,说一下自己对CM3的位带操作的理解以及自己的实际应用。
    支持了位操作以后,可以使用普通的加载/存储指令来对单一的bit进行读写。在CM3中,有两个区中实现了位带。其中一个是SRAM区的最低1MB(0x20000000-0x200FFFFF)范围,第二个是片内外设区的最低1MB(0x40000000-0x400FFFFF)范围。这两个区中的地址除了可以像普通的RAM一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个bit膨胀成一个32位的字。当你通过位带别名区访问这些字时,就可以达到访问原始bit的目的。
    将位带操作的位带区的每一bit映射到别名地址区的一个字(这是只有LSB有效的字)。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,把需要的位右移到LSB,并把LSB返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。SRAM区的别名区是从0x22000000开始的,外设的别名区是从0x42000000开始的。
    简言之,位带操作就是通过位带别名区对位带区进行位操作。
    例如要设置地址0x2000 0000中的bit2,则使用位带操作与不使用位带操作的汇编代码如下:
    Without Bit-Band:
    LDR       R0,=0x20000000;
    LDR       R1,  [R0];
    ORR.W  R1,  #0x04;
    STR       R1, [R0];
    With Bit-Band:
     LDR      R0, =0x22000008;
     MOV      R1,  #1;
     STR       R1, [R0];
     读取地址0x20000000中的bit2,有位带与无位带操作的比较:
     无位带:
     LDR         R0, = 0x20000000;
     LDR         R1,  [R0];
     UBFX.W   R1, R1, #2, #1;
     有位带:
     LDR        R0, = 0x22000008;
     LDR        R1,   [R0];
     由上述可见,位带区操作使程序变的简洁,位带操作对于硬件I/O密集型的底层程序最有用处,另外还可以在多任务中,实现共享资源在多任务之间的“互锁”访问。
     但C编译器中没有直接支持位带操作,要在C语言中使用位带操作,可以定义如下两个宏:
     把“位带地址+位序号”转换成别名地址:
     #define   BITBAND(addr, bitnum)   ((addr & 0xF0000000) + 0x20000000 + ((addr & 0xFFFFF)<<5) + (bitnum<<2))
     把地址转换成一个指针:
     #define  MEM_ADDR(addr)    *((volatile unsigned long *) (addr))
     STM32的SRAM从0x20000000开始只有64K,可见整个内存区都支持位带操作。我在内存中定义一个变量uint32_t   Flag,然后取其地址,addr= &Flag;那么我可以通过位带操作(用上面的两个宏)对Flag的每一位进行独立操作,如此,我便获得了32个标志位,每个标志位有0x0, 或者0x1两种状态。这种操作,在实际使用中暂未发现有什么问题,很稳定。所以,不用再为如何设置标志位而烦恼了。
     另外,我们在阅读MCU的数据手册时,有时会发现其外设寄存器有些支持位操作,有些只能半字或者字访问,不知道跟位带区是否有关,这部分就没有细细去看了。有知道的朋友请赐教。
     上述,只是对位带操作进行了简单介绍,对于它的优越之处,及其他详细信息可以参考《Cortex-M3权威指南》和《Cortex-M3技术参考手册》。本文也是依据这两份资料而来。如有不对之处,欢迎批评指正。

回复评论 (2)

学习了,赞一个
点赞  2014-12-17 19:46
只是平时看资料的时候,觉得一些东西挺有意思的,便记录下来。既方便了大家,也留着自己以后查询。
点赞  2014-12-18 12:46
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复