打印

【原创】]讲一讲BIT__BAND

[复制链接]
4018|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
chuzhujun_|  楼主 | 2008-9-9 15:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
AN, RAM, se, SRAM, TE

看见cm3的BIT_BAND很有意思,仔细琢磨了一下,和大家一起分享!
首先追溯到51,51单片机RAM内从从20H往后到3FH是位访问区,每一个字节的每一个位也对应有从00h开始的的每一个字节的最后一位,例如20H.0对应00h,20H.1对应于01h,.....其中00h,01h中起作用的也只是最后一位,其他位都是没意义的,又如FLAG1 BIT 00H,这样的话如果Setb FLAG1 这条语句执行,实际上市对RAM中20H这个字节的Bit0置一了,由此看来,这能ARM也是受Intel的影响和启发啊!
其次:开始讲cm3的BIT_BAND,处理器存储器映射包括两个 bit-banding 区域。它们分别为 SRAM 和外设存储区域中的最低的 1MB。这些 bit-band 区域将存储器别名区的一个字映射为 bit-band 区的一个位。 请看下图:file:///C:/Documents%20and%20Settings/jishu/桌面/isp/未命名.jpg
图中1M的  bit  band区域的每一个字节的每一位分别有 bit  band别名区的每一个字(四字节)对应,那么,这是不是和51的位区原理一样啊?呵呵,但是我们要知道,这里的位区可不是51里面的那么几十个字节啊,而是偌大的空间,很多人会认为,这样好浪费啊,每一个位对应一个字,那么这个字的其他剩余31个字节就等于是浪费的啊,虽然这是对的,是有点浪费,但是这样做的好处是不可估量的,想象看吧,我们这么举个例子来看看,就比如说现在忘SRAM的首地址写一个字节吧,也就是地址:0x2000 0000 ,但是我们想往0x2000 0000 这个字节的bit 3写1而保证其他的位都不发生变化,我们会怎么做,当然了,这肯定都会,就是一个读-修改-写的过程嘛,首先读出来这个字节给一个temp临时字节类型变量,然后同11110111b相与,然后再把temp给0x2000 0000完成位修改的操作 ,这样麻烦啊,还要定义一个变量,还一不小心把别的位也改变了,岂不出问题?现在好了,我们知道0x2000 0000这个字节对应的bit 0位是对应在别名区的0x2200 0000 往后的一个字(四字节)中,那么,我现在直接像这个别名区写一个最后一位为1就可以了的一个字:(*(u32 *) 0x2200 000b) = 1,这样一条语句就可以往0x2000 0000 这一字节的bit 3写1了,不用定义变量,不用担心会影响其他位,这样带来的好处同刚才我们认为的浪费空间的想法来比,不言而喻啦!
第三:方法和思想都清楚啦,接下来就是要寻找一个有效的方法来高效的写入啦,否则要是这样写一个位都算老半天该往那一个别名区的地址里写数,那可就麻烦了,所以请大家先看一个图,我手画然后扫描上去的,不是很好看,大家将就着看吧,别因为我图画的不好就认为我人品不好啊,我可是花了半天时间扫描的呢:
C:Documents and Settingsjishu桌面isp1.jpg
Cortex-M3 存储器映射有 2 个 32MB 别名区,它们被映射为两个 1MB 的 bit-band 区: 32MB SRAM 别名区和32MB 外设别名区,我这里图示的是SRAM位区同他们的别名区所对应的关系:
SRAM是从0x2000 0000 开始的,他的别名区是从0x2200 0000 开始的,这一点首先要弄清楚,0x2000 0000的每一个位对应于0x2200 0000 往后的一个一个字,如:(0x2200 0000).0对应0x2200 0000 ~0x2200 0003这一个字空间,你只需要定义一个指向32位地址的指针:(u32 *) 0x2200 0000,往这个指针对应的地址中写1就是对:(0x2200 0000).0这一位置一,写0就是清零,诚然,这个别名区的一个字中,1到31位都没有用到,也就是我们先前所说的浪费空间问题,不过优点已经很明显了!依此类推,向图中的0x2000 4001的第 3位,图上是BIT 3(我这里没有将第一位写成BIT0)写1,那么由途中对应的关系,我们就应该向0x2208 0024地址往后的四个字节中写1即:
   *((u32 *)0x2208 0024)=1;这怎么用公式算呢,很好算,首先我们先确定两个区的基地址,我现在要向
 0x2000 4001的第三位写一,它偏移了0x2000 0000 一共是(0x2000 4001 -0x2000 0000)个字节外加3位,而图中我们可以看到,位区的每一个字节的每一个位对应别名区中四个字节,所以总的表达式是:
0x2200 0000 +(0x2000 4001 -0x2000 0000)*8*4  +3*4   这样表达式就小荷才露尖尖角啦:会变的部分有两个:
1.(0x2000 4001 -0x2000 0000),我们称其为字节偏移,用byte_offset表示
2. 3  ,这个我们称其为比特偏移,用bit_offset表示,
那么通用表达式就是:
0x2200 0000 +(byte_offset*32)+(bit_offset*4),得出的便是在别名区中相对于首地址0x2200 0000偏移的字节数。
当然啦,我们这里是对SRAM而言的,如果对外设位区的话,那么以上式子中就不是0x2200 0000了,而应该改成0x4200 0000 啦,说到这里,大家都应该龇牙笑了吧?因为都懂了,不会吧?你为什么不笑,还不懂?那和我联系好了:chuzhujun@foxmail.com
 
 
沙发
chuzhujun_|  楼主 | 2008-9-9 15:11 | 只看该作者

讲一讲BIT__BAND

还有一个图,这个图我弄不好啊,不是在应该放的位置,斑竹可以的话,帮忙编辑一下哈!

使用特权

评论回复
板凳
lut1lut| | 2008-9-9 16:34 | 只看该作者

关键是要灵活运用bit banding的特性,怎么它用起来

合理的使用Bit-band功能,将大大简化操作。
例如:将以下定义的数组中的数据通过GPIOA的PIN0口输出:

1,在SRAM的0x20004000地址定义个长度为512字节的数组。
     #pragma location=0x20004000
    __root __no_init u8 Buffer[512]; 
    
    该数组的首字节的BIT0对应的Bit-band地址为:
    0x22000000 + (0x4000 × 32) + (0 × 4) = 0x22080000
    该数组的第二个字节的BIT3对应的Bit-band地址为:
    0x22000000 + (0x4001 × 32) + (3 × 4) = 0x2208002C

2, GPIOA的Port output data寄存器位于地址0x4001080C,那么对于GPIOA的PIN0来说,控制其输出电平的比特位的Bit-band地址为:
    0x42000000 + (0x1080C × 32) + (0 × 4) = 0x42021018

3.不使用Bit-band功能:

for(u16 cnt=0; cnt<512; cnt++) {
   for(u8 num=0; num<8; num++) {
      if((Buffer[cnt] >>num) 
        & 0x00000001) {
         GPIOA->BSRR = 1;
      }
      else {
         GPIOA->BRR = 1;
      }
   }
}

4.使用Bit-band功能:

u32 *pBuffer = ((u32*)0x22080000;
u16 cnt = 512 * 8;

While (cnt--){
   (*((u32*) 0x42021018)) = *pBuffer++;
}

使用特权

评论回复
地板
chuzhujun_|  楼主 | 2008-9-9 17:58 | 只看该作者

讲一讲BIT__BAND

对,关键是灵活运用,楼上说的好,您给出了ST研讨会的那几个例子,我本来也准备给出来,后来想准备放到下次贴出来吧,呵呵,没想到楼上帮我贴上了,谢谢啊!

使用特权

评论回复
5
ifree64| | 2008-9-10 00:08 | 只看该作者

very cool

使用特权

评论回复
6
chuzhujun_|  楼主 | 2008-9-11 09:38 | 只看该作者

回7楼的

你的unsigned是什么意思啊?应该注明到底是字节  半字  或者是字啊   这样定义有错的!
不过你的想法我知道了,你定义了一个结构体首先必须要定位好你的结构体在RAM中什么地方,你可以通过两种方法:
1:自己把它放到自己想放的RAM中的地方
比如:
   #pragma location=0x20004000
    __root __no_init u8 Buffer[512]; 
2:定义一个同你的数据类型一致的指针,比如你的那个结构体的话,
  即可以:th_bb  *p_th_bb;
  然后你取&p_th_bb  得到的地址便是你结构体的首地址,
接下来就需要用到上面的公式算出其别名区所在的地址了,接下来可以参照4楼的例子进行对结构体中的单独一位进行置位或者复位



然后再定义一个字指针:u32 * IOA_Point;
并且IOA_Point = (u32 *) (0x42000000 + (0x1080C × 32) + (0 × 4));
这就将GPIOA的位带别名区的首地址给了IOA_Point ,

使用特权

评论回复
7
yjtks| | 2008-9-11 15:35 | 只看该作者

回复

光讲这些有什么用啊 关键是要怎么象51那样能直接定义位变量才有用

使用特权

评论回复
8
浪淘沙| | 2008-9-11 21:26 | 只看该作者

说了这么多怎么还不开窍,自己定义一个u32的数组不就是位

使用特权

评论回复
9
calvinxxw| | 2015-12-16 09:18 | 只看该作者
刚刚才看到,来迟了,太感谢,太有用。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

55

帖子

0

粉丝