8
static void RadioReleaseSPI(void) {
    __disable_interrupt();
    spiTxRxByteCount &= ~0x0100;
    __enable_interrupt();
}

複数のタスクが SPI リソースを使用しようとする可能性があることを理解しています。spiTxRxByteCountSPI が現在別のタスクによって使用されているかどうかを追跡するために使用されるグローバル変数です。タスクが SPI を必要とする場合、タスクのステータスをチェックしてspiTxRxByteCount、SPI が使用されているかどうかを確認できます。SPI を使用してタスクが完了すると、この関数が呼び出されてビットがクリアされ、SPI が現在解放されていることが示されます。しかし、なぜ最初に割り込みを無効にしてから、再度有効にするのでしょうか? ただのパラノイア?

4

2 に答える 2

16

&= は読み取り-変更-書き込み操作を行います - それはアトミックではありません。その途中で何かを変更する割り込みが必要ないため、誤った値で書き込みが上書きされます。

于 2012-11-28T21:04:18.710 に答える
10

アトミック アクセスを確保するには、割り込みを無効にする必要があります。読み取り中に他のプロセスがその変数にアクセスして、潜在的に変更することは望ましくありません。

組み込みコンピューティングの紹介から:

アトミック アクセスの必要性

このシナリオを想像してみてください: 8 ビットの uC で実行されているフォアグラウンド プログラムは、16 ビットの変数を調べる必要があり、それを X と呼びます。重要ではありません)、16 ビット値を調べます。ここで、その 16 ビット変数を変更する関連付けられた ISR による割り込みを想像してください。さらに、変数の値が、プログラム実行中のある時点で 0x1234 になったとします。起こりうる非常に悪いことは次のとおりです。

  • フォアグラウンドは上位バイト (0x12) をロードします
  • ISR が発生し、X を 0xABCD に変更します
  • フォアグラウンドは下位バイト (0xCD) をロードします
  • フォアグラウンド プログラムは、0x12CD の 16 ビット値を認識します。

問題は、変数 X にアクセスするための CPU 命令が割り切れる可能性があるため、分割できないと思われるデータの一部である変数 X が、実際にはアクセスの過程で変更されたことです。したがって、変数 X のロードは破損しています。変数の読み取り順序は関係ないことがわかります。この例で順序を逆にすると、変数は 0x12CD ではなく 0xAB34 として誤って読み取られます。いずれにせよ、読み取られた値は古い有効値 (0x1234) でも新しい有効値 (0xABCD) でもありません。

ISR 参照データを書き込むのは良くありません。今回は、フォアグラウンド プログラムが ISR のために以前の値 0x1234 を書き込んだ後、新しい値 0xABCD を書き込む必要があると仮定します。この場合、VBT は次のようになります。

  • フォアグラウンドは新しい上位バイト (0xAB) を格納します
  • ISR が発生し、X を 0xAB34 として読み取る
  • フォアグラウンドは新しい下位バイト (0xCD) を格納します

コード (今回は ISR) は、以前の有効な値 0x1234 も新しい有効な値 0xABCD も認識せず、無効な値 0xAB34 を認識します。

C では 1 つの命令のように見えるかもしれませspiTxRxByteCount &= ~0x0100;んが、実際には CPU にとっては複数の命令です。GCC でコンパイルすると、アセンブリ リストは次のようになります。

  57:atomic.c      ****     spiTxRxByteCount &= ~0x0100;
  68                    .loc 1 57 0
  69 004d A1000000      movl    _spiTxRxByteCount, %eax
  69      00
  70 0052 80E4FE        andb    $254, %ah
  71 0055 A3000000      movl    %eax, _spiTxRxByteCount
  71      00

これらの命令のいずれかの間に割り込みが発生し、データが変更された場合、最初の ISR が誤った値を読み取る可能性があります。そのため、割り込みを操作する前に割り込みを無効にし、変数を宣言する必要がありますvolatile

于 2012-11-28T21:23:43.990 に答える