最適化処理のせいで悩んだぞ 呪文volatile再び
割り込みに絡む処理で、「C」が良かれと思って
やった最適化処理のせいで悩んでしまいました。
簡略化して説明するとこんな流れ。
intr_aは割り込み内で処理されるデータ。
2バイト値なんでメイン側では割込禁止で書き込む
必要がある。
hoge()という関数の中でそれを実行する。
~~~~~~~~~~~~~~~~~~~~~~~~~
// 割り込みで読み出し処理される2バイトデータ
volatile int intr_a;
// aをあれこれ計算してintr_aを更新
void hoge(int a)
{
int d; ★1 一時変数
d = a * なんたら (1)
d += あれこれ (2) そこそこ時間のかかる計算
cli(); // 割込禁止にして
intr_a = d; (3) // intr_aに計算結果を書いて
sei(); // 割込有効に戻す
} // リターン
~~~~~~~~~~~~~~~~~~~~~~~~~
走らせてみると、思いのほか割り込みが禁止されて
いる時間が長いのです。
割り込み禁止期間は計算結果を書く(3)の一瞬だけ
のはず。
しかし、禁止時間から考えて計算途中も割り込み
禁止になっている様子でなのです。
その原因は最適化処理。
別行に書いている(1)と(2)の処理を、(3)のところに
コンパイラがまとめてしまっていたのです。
Cコンパイラの気持ち:
「一時変数なんか使わんでも処理できるぜい」と
そのため、計算が始まる直前に割込禁止にして
しまっていて、時間のかかる計算が割り込み
禁止状態で行われていたのです。
で、対策。
・その1
一時変数int dの前に「volatile」を前置。
これで(1)(2)(3)が記述どうりの順序で進む
ので、(3)だけが割り込み禁止になります。
・その2
hoge()を戻り値を持たせるようにして、
その値を割り込み禁止でintr_aに書く。
int hoge(int a) とし、hoge()の中で
intr_aを書くのではなく、外の処理として
b = hoge(a);
cli();
intr_a = b; (4)
sei();
とすると、(4)だけが割り込み禁止になって
思惑どうりに処理が流れます。
ひょっとしたらこのbにもvolatileが
必要かもしれない。
※過去記事
・2018年10月11日:魔法の言葉「volatile」
割り込みで直接操作されるintr_aはvolatileを付けなけりゃ
と注意します。
しかし、処理の流れが重要なら、計算途中で使う一時変数に
も付けておかないと、ということです。
「割り込み禁止時間が長いぞ」・・・この発見は
テストパルスをオシロで見てしかわかりません。
答えは合ってるし。
※スペルのミスを訂正 (恥ずかしいぞ)
| 固定リンク
「Arduino」カテゴリの記事
- パルスジェネレータをI2C液晶で動かす(2025.01.28)
- EEPROMを使ったシリアル受信バッファ 512kバイトに増設(2024.12.26)
- 1/nカウント方式とDDS方式の2相パルス発生回路(2024.10.13)
- おっと。map関数の計算桁に注意(2024.10.06)
- DDS方式の2相パルス発生回路、周波数スキャン機能を付ける(2024.10.05)
「割り込み処理」カテゴリの記事
- 1クロックでも速くしたい 割込を「ISR_NAKED」で(2024.09.30)
- 1クロックでも速くしたい DDS方式の2相パルス発生器(2024.09.27)
- 最適化処理のせいで悩んだぞ 呪文volatile再び(2024.06.06)
- I2C液晶のアクセス、割り込みで処理しないようにすると(2024.04.12)
- I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの(2024.04.07)
コメント