以下サンプルコードの4行目の処理を、一般的に「レジスタのダミーリード」と言います。
|
1 2 3 4 |
/* レジスタ REG_EVENT_Xに書き込み */ REG_EVENT_X = 0x01 ; /* ダミーリード */ (void)REG_EVENT_X ; |
レジスタに値を書き込みしているわけでもなく、レジスタの値を取っているわけでもなく、ただレジスタに参照しているだけの処理です。
これを初めて見たとき、一体何のための処理か分からないと思いますので、この記事ではレジスタのダミーリードがどんな意味があるのかを解説していきます。
1. レジスタの書き込み待ちのため
1つ目は、レジスタが書き込みを待つためです。
例えば、以下のようなコードがあったとします。
|
1 2 3 4 5 |
/* REG_EVENT_Xに書き込み */ REG_EVENT_X = 0x0001 ; /* 10us待機してからREG_EVENT_Yに書き込み */ wait_10us() ; REG_EVENT_Y = 0x0002 ; |
やりたいことは、以下の3つです。
- REG_EVENT_Xに書き込み
- 10us待機関数実行
- 10us経過後に、REG_EVENT_Yに書き込み
ここで注意したいのが、CPUが
|
1 |
REG_EVENT_X = 0x0001; |
という書き込み命令を実行したからといって、その瞬間に周辺回路のレジスタまで値が反映されているとは限らないということです。
CPUから周辺レジスタへのアクセスでは、バスや書き込みバッファなどを経由する場合があります。
そのため、CPU側では次の処理へ進んでいても、REG_EVENT_Xへの書き込みがまだ完全に反映されていない場合があります。
そうなると、REG_EVENT_Xに書き込み値が反映されてから、実際には9usほどしか待機せずにREG_EVENT_Yに値を書き込むといったことが発生します。
もし、「10us経過してからREG_EVENT_Yにアクセスすること」といった制約があるのであれば、これは満たさない可能性が出てくるということです。
そこで、マイコンや対象レジスタの仕様によっては、書き込み後にレジスタをダミーリードすることがあります。
|
1 2 3 4 5 6 7 |
/* REG_EVENT_Xに書き込み */ REG_EVENT_X = 0x0001 ; /* ダミーリード */ (void)REG_EVENT_X ; /* 10us待機してからREG_EVENT_Yに書き込み */ wait_10us() ; REG_EVENT_Y = 0x0002 ; |
4行目の処理ではREG_EVENT_Xを実際に読み出していますが、読み出した値そのものは使用せず捨てています。
このような処理を「ダミーリード」と呼ぶことがあります。
対象CPUやレジスタの仕様によっては、この読み出しによって、それより前に行った書き込みの反映を待つことができます。
ただし、ダミーリードを行えば必ず書き込み完了が保証されるわけではありません。
CPUによってはメモリバリア命令や同期命令が必要な場合もあります。
そのため、実際のソフトウェアでは必ずマイコンのハードウェアマニュアルに記載されている手順に従う必要があります。
まぁ、レジスタの書き込みの後にダミーリードがあったら、「書き込み反映待ちなんだな」と思っておけばOKです。
2. レジスタのクリアのため
例えば、よくあるのが割り込みのステータスレジスタで、レジスタにアクセスすることによって、割り込みフラグがクリアされる仕様のレジスタがあります。
割り込みフラグクリア目的のためだけにレジスタにアクセスする必要があるため、こういったときにダミーリードを行うことがあります。
そういったレジスタであれば、仕様にそう書かれているはずですので、もし出会ったらレジスタの仕様を見てみてください。
レジスタのダミーリードはちゃんと意味がある
ダミーリードを見つけても、「不要そうだから消していい」と判断してはいけません。
書き込み同期、ハードウェア固有のアクセス手順など、明確な理由がある可能性があります。
まずは対象レジスタのハードウェアマニュアルを確認しましょう。

