stm32 でのビットバンド操作
1. 基本概念の見直し
1…ビット演算とは何ですか?
ビット演算とは、1 つのビットを個別に読み書きできることを意味します。ビット バンド操作をサポートした後は、通常のロード/ストア命令を使用して単一ビットの読み取りおよび書き込みを行うことができます。CM3 では、ビットバンディングは 2 つのゾーンで実装されます。1 つは SRAM 領域の下位 1MB 範囲であり、2 つ目はオンチップ周辺領域の下位 1MB 範囲です。通常の RAM と同様に使用されることに加えて、これら 2 つのビット バンドのアドレスには、各ビットを 32 ビット ワードに拡張する独自の「ビット バンド エイリアス領域」もあります。ビットバンド エイリアス領域を介してこれらのワードにアクセスすると、元のビットにアクセスできます。3. ビットバンド領域とは何ですか? ビットバンド領域とは、単独で動作させたいIOの領域、つまりPAやPBなどのメモリとこのIOポートの束が配置されている領域のことです。エイリアスエリア? ビットバンドエイリアス領域は、各ビットに新しい名前を付けるアドレス領域です5. ビットバンド領域とビットバンドエイリアス領域の演算式1. SRAM ビットバンド領域の特定のビットに対して、ワードを記録しますセクション アドレスが A、ビット番号が n (0<=n<=7) である場合、エイリアス領域内のこのビットのアドレスは次のようになります。
AliasAddr=0x22000000+((A-0x20000000)*8+n)*4 =Ox22000000+ (A-Ox20000000)*32 +n*4
2. 内蔵周辺ビットバンド領域の特定のビットについて、そのビットが配置されているバイトのアドレスを A、ビットシーケンス番号を n (<=n<=7) として記録し、そのビットのアドレスを記録します。エイリアス領域には次のものがあります。
AliasAddr=0x42000000+((A-0x40000000)*8+n)*4 =0x42000000+ (A-Ox40000000)*32 +n*4
5. ビットバンド領域とビットバンドエイリアス領域の演算式はなぜこのようになるのですか?
5.1 まずメモリイメージを見てみましょう.
上の図 6.4 では、FLASH、RAM、FSMC、および制御ユニット (つまり、オンチップ周辺機器) の AHB から APB へのブリッジ、これらの機能コンポーネントが 4GB のアドレス空間にまとめて配置されています。プログラミングするときは、アドレスでそれらを見つけて操作できます。(C 言語によるデータの読み書き)
この 4GB のアドレス空間では、ARM は大きく 8 つのブロックに分割されており、各ブロックは 512MB であり、各ブロックには独自の目的があります。具体的な分類については、表 6 を参照してください。各ブロックのサイズは 512MB で、これは明らかに非常に大きいです。
CM3 では、ビット バンドが 2 か所に実装されていることがわかります。1 つは SRAM 領域の最小 1MB スペースです。1 つは、周辺領域に最低 1MB のスペースが必要です。
AliasAddr=0x22000000+((A-0x20000000)*8+n)*4 =Ox22000000+ (A-Ox20000000)*32 +n*4
/*
则在SRAM区
AliasAddr是别名区的地址
0x22000000是SRAM位带别名区的起始地址
A是SRAM位带区的某个比特,记它所在字节的地址为A,位序号为n(0<=n<=7)
(A-0x20000000)代表该比特前面有多少个字节,一个字节8位所以乘以8,
一个位膨胀后是4字节,所以乘以4.n表示该比特在A地址的序号,因为一
个位膨胀后是4字节,所以也*4
*/
2. ビットバンド演算のやり方
IO ポートの特定のビットを操作するビット バンド操作を実行する場合、STM32 環境では、そのビットに対応するエイリアス領域のアドレスを見つけて、このアドレスを見つけて、このアドレスで操作する必要があります。実際、上記はこのビットを操作することです。
2.1 統一された公式:
1 //把"位带地址+位序号"转换成别名地址的宏
2 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+ ( (addr & 0x00FFFFFF)<<5)+(bitnum<<2))
/*
addr & 0xF0000000是为了区别SRAM还是外设,实际效果就是取出4或者2,如果是外设则取出4+0x02000000就是0x42000000
addr & 0x00FFFFFF 屏蔽了高三位,相当于减去0x20000000或者0x40000000
为何屏蔽高三位?
因为外设地址最高地址是:0x20100000,和起始地址0x20000000之间相减时候
总是低五位才有效,所以才把高三位屏蔽来达到减去地址的效果,而<<5相当于
*4*8.<<2相当于*4
*/
2.2GPIOビットバンド動作例
ここでは GPIOx_IDR (ポート入力データ レジスタ) と GPIOx_ODR (ポート出力データ レジスタ) を設定して動作します。
データマニュアルによると、GPIOx_IDR のオフセット アドレスは0x10 (16)、GPIOx_ODRのオフセット アドレスは0x14 (20)です
。
#ifndef __LED_H__
#define __LED_H__
//IO口操作宏定义
#define BITBAND(addr, bitnum) (0x42000000 +((addr-0x40000000)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr (GPIOB_BASE+20) //0x40020414
#define GPIOC_ODR_Addr (GPIOC_BASE+20) //0x40020814
#define GPIOD_ODR_Addr (GPIOD_BASE+20) //0x40020C14
#define GPIOE_ODR_Addr (GPIOE_BASE+20) //0x40021014
#define GPIOF_ODR_Addr (GPIOF_BASE+20) //0x40021414
#define GPIOG_ODR_Addr (GPIOG_BASE+20) //0x40021814
#define GPIOH_ODR_Addr (GPIOH_BASE+20) //0x40021C14
#define GPIOI_ODR_Addr (GPIOI_BASE+20) //0x40022014
#define GPIOA_IDR_Addr (GPIOA_BASE+16) //0x40020010
#define GPIOB_IDR_Addr (GPIOB_BASE+16) //0x40020410
#define GPIOC_IDR_Addr (GPIOC_BASE+16) //0x40020810
#define GPIOD_IDR_Addr (GPIOD_BASE+16) //0x40020C10
#define GPIOE_IDR_Addr (GPIOE_BASE+16) //0x40021010
#define GPIOF_IDR_Addr (GPIOF_BASE+16) //0x40021410
#define GPIOG_IDR_Addr (GPIOG_BASE+16) //0x40021810
#define GPIOH_IDR_Addr (GPIOH_BASE+16) //0x40021C10
#define GPIOI_IDR_Addr (GPIOI_BASE+16) //0x40022010
//单一IO口操作
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n)
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n)
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n)
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n)
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n)
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n)
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n)
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n)
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n)
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n)
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n)
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n)
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n)
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n)
#define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n)
#define PHin(n) BIT_ADDR(GPIOH_IDR_Addr,n)
#define PIout(n) BIT_ADDR(GPIOI_ODR_Addr,n)
#define PIin(n) BIT_ADDR(GPIOI_IDR_Addr,n)
//°´¼ü³õʼ»¯º¯Êý
void led_init(void);
#endif
main関数で呼び出すだけです
#include "stm32f4xx.h"
#include "led.h"
//延时
void delay(int x)
{
int i,j;
for(i=0;i<x;i++)
for(j=0;j<10000;j++);
}
int main()
{
led_init();
while(1)
{
PAout(6)=0;//设置PA6为低电平,点亮led灯
delay (100);
PAout(6)=1;//设置PA6为高电平,熄灭led灯
delay (100);
}
}