ビット制御のBITBANDは超便利
投稿:2012-12-07
例えばポートの中の1ビットをH/L制御しようとすると、1ポートに32ビットあるので
現在値をポートから取得して対象のビットだけ0にして出力したいビットをORしますよね。
こんな感じ(あくまで例)
uint32_t port = LPC_GPIO0->FIOPIN; port &= ~0x00000100; port |= newval << 8; LPC_GPIO0->FIOPIN = port;
論より証拠、このコードをご覧ください。
*(uint32_t *)0x233802A0 = newval;たった1行でできちゃいました。
通常は32ビットがひとかたまりですけれど、これを1ビットずつに分離、左にダミーの31ビットをくっつけて32ビットとした写像です。
読み出すと値が0x00000000か0x00000001のどちらかで、書き込む値の左の31ビットは無視されて最右の1ビットだけが反映されます。
このBITBANDを上手い事使うためにマクロを用意しました。
typedef volatile uint32_t *BITBAND; #define BITBAND_GENERIC_ADDR(base, addr, bitnum) (BITBAND)(base + 0x02000000UL + sizeof(uint32_t) * (((uint32_t)&addr - base) * 8 + bitnum)) #define BITBAND_AHB_ADDR(addr, bitnum) BITBAND_GENERIC_ADDR(0x20000000UL, addr, bitnum) #define BITBAND_APB_ADDR(addr, bitnum) BITBAND_GENERIC_ADDR(0x40000000UL, addr, bitnum) #define BITBAND_GENERIC(base, addr, bitnum) *BITBAND_GENERIC_ADDR(base, addr, bitnum) #define BITBAND_AHB(addr, bitnum) BITBAND_GENERIC(0x20000000UL, addr, bitnum) #define BITBAND_APB(addr, bitnum) BITBAND_GENERIC(0x40000000UL, addr, bitnum)BITBANDの対象がAHBとAPBの2領域でベースアドレスが異なるため2種類用意してあります。 GPIOはAHBでペリフェラルはAPBです。 冒頭の例をマクロを使って書き直すとこんな感じに。
BITBAND_AHB(LPC_GPIO0->FIOPIN, 8) = newval;
LPC1769はGPIOポートが5個もあって、ポートとビットの組み合わせになります。
プログラムで「ポート0の場合…ポート1の場合…ポート2の場合…」と場合分けをするのはスマートじゃない。
GPIOのマッピングを見ると先頭のポート0からポート5まで連続だからFIOPINのBITBANDも連続することに気付きました。
ポート0のビット0のBITBAND、つまり「BITBAND_AHB_ADDR(LPC_GPIO0->FIOPIN, 0)」を基準にすると場合分けが不要になります。
全ポート、全ビットを個別に設定できる関数です。第1パラメタがFIOPINのBITBANDになっています。
void ksrk_gpio_setup(BITBAND GpioPin, uint32_t dir, uint32_t mode, uint32_t drain) { uint32_t pin_offset = GpioPin - BITBAND_AHB_ADDR(LPC_GPIO0->FIOPIN, 0); // Funcを00に設定 BITBAND_APB(LPC_PINCON->PINSEL0, 2 * pin_offset + 0) = 0; BITBAND_APB(LPC_PINCON->PINSEL0, 2 * pin_offset + 1) = 0; // モード(プルアップ/プルダウン/レピータ/スリーステート)を設定 BITBAND_APB(LPC_PINCON->PINMODE0, 2 * pin_offset + 0) = mode >> 0; BITBAND_APB(LPC_PINCON->PINMODE0, 2 * pin_offset + 1) = mode >> 1; // 出力を0に(GPIOのピンはAHB) BITBAND_AHB(LPC_GPIO0->FIOPIN, pin_offset) = 0; // 入出力を設定 BITBAND_AHB(LPC_GPIO0->FIODIR, pin_offset) = dir; // オープンドレインの有無を設定 BITBAND_APB(LPC_PINCON->PINMODE_OD0, pin_offset) = drain; }ピンの指定をパラメタとして保持できて、こんなコードを書けるようになりました。
*pHgl->pGpioPin[GPIO_DB4] = cdata >> 4;
このページ自体が鉄ゲタですよホントにもう(ぐすん)。
あと公式資料での表記は「BIT BAND」なので間にスペースあります。BITBANDと思い込んでPDFの検索できずに頭抱えました。
まあ、どうせ話が通じないと思うので、あとはソース見てください(^^;
yrntrlmnmnt20121207.zip
yrntrlmnmnt20121207.zip