mcpField
M
mmio-and-bit-manipulation

mmio-and-bit-manipulation

github.com/mohitmishra786開発269305 回インストール18 週間前に更新
リポジトリ

mmio-and-bit-manipulation について

低レベルコードやベアメタルコードの MMIO とレジスターアクセスを扱うエージェント向けスキルです。volatile、安全なビット操作、アラインメント、エンディアン、メモリバリアを解説します。

主な機能

  1. 01volatile によるレジスターアクセス
  2. 02読み取り・変更・書き込みパターン
  3. 03明示的なマスクとシフト
  4. 04アラインメントとエンディアンの指針
  5. 05メモリバリアの使用方法

活用シーン

  1. 01HAL を使わないペリフェラルドライバーの作成
  2. 02断続的なレジスター破損の調査
  3. 03移植性の低い C ビットフィールドの置き換え
  4. 04ISR とメイン処理のレジスターアクセス確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill mmio-and-bit-manipulation

インストール後、Claude Code で/mmio-and-bit-manipulationを入力して読み込まれたか確認します。

詳細

MMIO とビット操作

目的

メモリマップド I/O を安全に扱う方法をエージェントに案内します。volatile のセマンティクス、読み取り・変更・書き込みのパターン、ビットフィールドの落とし穴、アラインメントとエンディアン、ベアメタルドライバー向けの移植可能なレジスターアクセスマクロを扱います。

使用する場面

  • HAL を使わずにペリフェラルのレジスタードライバーを作成するとき
  • レジスターの破損や古い値の読み取りが断続的に発生する問題を修正するとき
  • C のビットフィールドを明示的なマスクに置き換えるとき
  • リトルエンディアンの MCU 間でドライバーを移植するとき
  • ISR とメイン処理間のレジスターアクセスを監査するとき

ワークフロー

1. MMIO の基本

ペリフェラルのレジスターは、CPU のメモリーマップ内の固定アドレスに配置されています。コンパイラーによる読み取りや書き込みのキャッシュを防ぐ必要があります。

#include <stdint.h>

#define PERIPH_BASE   0x40000000U
#define GPIOA_MODER   (*(volatile uint32_t *)(PERIPH_BASE + 0x20000U))
修飾子効果
volatileアクセスごとにロード/ストアを強制します。ハードウェアには必須です
const volatile読み取り専用のハードウェア(まれです)
通常の uint32_t *誤りです。コンパイラーが最適化によってアクセスを省略する可能性があります
2. 読み取り・変更・書き込みマクロ
#define REG32(addr)        (*(volatile uint32_t *)(addr))
#define REG_SET(addr, mask)   (REG32(addr) |= (mask))
#define REG_CLR(addr, mask)   (REG32(addr) &= ~(mask))
#define REG_TOGGLE(addr, mask) (REG32(addr) ^= (mask))
#define REG_WRITE(addr, val)  (REG32(addr) = (val))
#define REG_READ(addr)        (REG32(addr))

適切 — レジスターが対応している場合、単一ビットの更新をアトミックに行う意図を示します。

#define GPIOA_BSRR  REG32(0x40020018U)
GPIOA_BSRR = (1U << 5);        /* set PA5 */
GPIOA_BSRR = (1U << (5+16));   /* reset PA5 — STM32 BSRR pattern */

不適切 — 割り込みと共有するレジスターに対する非アトミックな RMW です。

uint32_t v = REG_READ(GPIOA_MODER);
v |= (1U << 10);
REG_WRITE(GPIOA_MODER, v);  /* ISR may interleave — lost update */

対処法:IRQ を短時間無効にする、ハードウェアのセット/クリアレジスターを使う、または利用可能な場合は LL アトミックビットバンドを使います。

3. ビットフィールドの落とし穴
/* Bad — layout is implementation-defined, not portable */
typedef struct {
    uint32_t mode  : 2;
    uint32_t type  : 1;
    uint32_t speed : 2;
} gpio_moder_bits_t;

明示的なマスクを使用してください。

#define GPIO_MODER_MODE0_SHIFT   0
#define GPIO_MODER_MODE0_MASK    (3U << GPIO_MODER_MODE0_SHIFT)
#define GPIO_MODER_MODE0_VAL(n)  ((n) << GPIO_MODER_MODE0_SHIFT)

REG32(GPIOA_MODER) = (REG32(GPIOA_MODER) & ~GPIO_MODER_MODE0_MASK)
                   | GPIO_MODER_MODE0_VAL(1);  /* output */
4. エンディアンとアラインメント
  • Cortex-M とほとんどの MCU はリトルエンディアンです。uint32_t の MMIO にはワード境界にアラインされたアドレスを使います
  • アラインメントされていない uint32_t アクセスは、ARMv7-M 以降でフォルトする場合があります
  • 8 ビットレジスターには、正しいバイトレーンアドレスで volatile uint8_t を使います
#define REG8(addr)  (*(volatile uint8_t *)(addr))
5. メモリーバリア(必要な場合)
/* After configuring peripheral before first use */
__DSB();
__ISB();

/* After DMA setup, before enabling channel */
__DMB();

Cortex-M では CMSIS バリア(core_cm4.h)を使用してください。

6. エージェントの使用例
/mmio-and-bit-manipulation Safe pattern to set bit 3 without affecting other bits in ISR context
/mmio-and-bit-manipulation Why must peripheral pointers be volatile?

よくある問題

症状原因対処法
レジスターへの書き込みが無視されるアドレスが間違っている/クロックが無効になっている先にペリフェラルクロックを有効にする
ビットがランダムに反転するISR との RMW 競合BSRR 形式のアトミックレジスターまたはクリティカルセクションを使う
アクセス時に HardFault が発生するアラインメントされていない、またはバスが保護されているデータシートに合わせてアクセス幅を指定する
読み取りが最適化で省略されるvolatile がないvolatile uint32_t を使う
ビットフィールドの値が間違っているコンパイラーが予期しない形式でパッキングするシフト/マスクマクロを使う

関連スキル

  • skills/baremetal/peripherals-from-datasheet — レジスターマップの抽出
  • skills/baremetal/gpio-baremetal — GPIO レジスターのパターン
  • skills/low-level-programming/assembly-arm — インライン asm バリア
  • skills/embedded/linker-scripts — ペリフェラルのメモリーマップ領域

コメント