« エレコム製マウス ホイールが不調 | トップページ | 電源スイッチを無くす 操作スイッチの長押しでon/off »

2024年6月 6日 (木)

最適化処理のせいで悩んだぞ 呪文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を付けなけりゃ
と注意します。
しかし、処理の流れが重要なら、計算途中で使う一時変数に
も付けておかないと、ということです。

「割り込み禁止時間が長いぞ」・・・この発見は
テストパルスをオシロで見てしかわかりません。
答えは合ってるし。


※スペルのミスを訂正 (恥ずかしいぞ)

|

« エレコム製マウス ホイールが不調 | トップページ | 電源スイッチを無くす 操作スイッチの長押しでon/off »

Arduino」カテゴリの記事

割り込み処理」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« エレコム製マウス ホイールが不調 | トップページ | 電源スイッチを無くす 操作スイッチの長押しでon/off »