1. ホーム

STM32でのビットバンド動作

2022-02-21 02:09:52
        ビットバンド演算をサポートすることで、通常のロード/ストア命令を用いて1ビット単位での読み書きが可能になります。CM3では、2つの領域でビットバンドを実装しています。1つはSRAM領域の最小1MBの範囲、もう1つはオンチップペリフェラル領域の最小1MBの範囲です。この2つのゾーンのアドレスは、通常のRAMと同様に使用できますが、各ビットを32ビットワードに展開した独自の"bitband alias zone"も持っています。ビットバンドエイリアス領域を介してこれらのワードにアクセスすると、元のビットにアクセスすることができます。
       ビットバンド動作の概念は、実は30年前に8051マイコンが先駆者として存在しており、今回のCM3はこの機能を進化させ、ビットバンド動作は8051のビットアドレス領域のパワーを大幅に強化したものとなっているのです。
       CM3では、ビットバンド記憶に関するアドレスを示すために、以下の用語を使用しています。
              ビットバンド領域:ビットバンド演算をサポートするアドレス領域
              ビットバンドエイリアス:エイリアスのアドレスへのアクセスは、最終的にはビットバンド領域へのアクセスに作用する(この途中にはアドレスマッピングの処理がある)
       ビットバンド領域では、各ビットはエイリアスアドレス領域のワードにマッピングされます。これは、LSBのみが有効なワードです。エイリアスアドレスがアクセスされると、まずビットバンドアドレスに変換されます。読み出しの場合、ビットバンドアドレスのワードを読み出し、目的のビットをLSBに右シフトし、LSBを返します。書き込みの場合は、書き込むビットを対応するビット番号に左シフトし、アトミックなquot;read-modify-write"処理が行われます。



       ビットバンド演算をサポートする2つのメモリ領域の範囲は
              0x2000_0000-0x200F_FFFF (SRAM領域で最小1MB)
              0x4000_0000-0x400F_FFFF (最小1MBのオンチップペリフェラル領域)
       SRAMのビットバンド領域のビットの場合、バイトアドレスA,ビット番号n(0<=n<=7)にあることに注意すると、エイリアス領域でのビットのアドレスは次のようになります。
              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"は1ワードが4バイトであることを意味し、"*8"は1バイトが8ビットであることを意味しています。

       冗長にならない程度に、別の例を挙げます。
       1. アドレス 0x20000000 に 0x3355AACC を書き込む。
       2. アドレス0x22000008を読み出す。この読み出しアクセスは、0x20000000を読み出し、値1のビット2を取り出す。
       この操作は、アドレス0x20000000へのquot;read-modify-write"操作(アトミック)としてマッピングされ、ビット2を0にクリアする。
       4. ここで再度0x20000000を読み込むと、0x3355AAC8(ビット[2]がクリアされている)が返されます。
       ビットバンドエイリアス領域のワードは、LSBにしか意味がありません。また、ビットバンドエイリアス領域にアクセスする場合、使用するデータ転送命令の長さ(ワード/ハーフワード/バイト)に関係なく、アドレスをワード境界に合わせないと、予期しない結果が生じる可能性があります。 

///
///Bitband operation, implementing 51-like GPIO control functions
/// For specific implementation ideas, refer to <<CM3 Authoritative Guide>> Chapter 5 (pages 87-92).
//IO port operation macro definition
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) 
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) 
//IO port address mapping
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08 
 
//IO port operation, only for a single IO port!
//Make sure the value of n is less than 16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //output 
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //input 

#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //output 
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //input 

#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //output 
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //input 

#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //output 
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //input 

#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //output 
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //input

#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //output 
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //input

#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //output 
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //input