ページ

2013年11月20日水曜日

STM32F303のUSART1割り込みのバグ?

以前、STM32F3Discoveryで割り込みを使ったシリアル通信のコードを書きました。
あのコード使って色々とシリアル通信を行なっていたのですが、どうもある特定条件下においてマイコンがスタックする現象に見舞われれました。

自分の環境では、STM32F3DiscoveryをFT232RLにつないで、PCと仮想COMポートを用いて通信しています。
PC側はUbuntu 12.04LTSで、フロー制御はなし、8N1の115200ボーで通信を行いました。
マイコン側はUSARTをPA9とPA10で使用し、RXNE割り込みを許可して割り込みハンドラ内でデータをリングバッファに貯める処理を行なっています。

ここで、PC側から100ms周期で300byteぐらいのデータを送信すると、「シリアルの割り込みハンドラが許可していない要因で連続発生する」というちょっと意味がわからない状況に陥りました。
割り込みハンドラ内でGetITStatusを使って割り込み要因を調べてもどれにも該当せず、ハンドラから抜けると再度割り込みに入るので他の処理がブロックされてしまいます。
処理がスタックします。
また、TxRxの信号線は停止したままで、FT232を引っこ抜いてもマイコンはスタックしたままでした。

※スタックオーバーフローも疑いましたが、デバッガで見てもかなり余裕はあるようでした。
※送信に関しては全く問題ありませんでした。

結論としては、どうもこれはSTM32F303のUSART1割り込み周りのバグに思えます。
これに対処するために、割り込みハンドラ内で要因不明の割り込みを検知した場合にUSART1をDISABLEしたあとにENABLEするコード追加したところ、現象は再現しなくなりました。

void Serial::InterruptHandler()
{
  //Receive
  if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
  {
    _rbuf.push_back(static_cast(USART_ReceiveData(USART1)));
    return;
  }

  //Send
  if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
  {
    if (!_wbuf.empty())
    {
      USART_SendData(USART1, _wbuf.front());
      _wbuf.pop_front();
    }
    else
      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

    return;
  }

  //Interrupts which is not permitted raised!
  //This happens when so many packetes are received.
  //Something is wrong... reset USART module.
  USART_Cmd(USART1, DISABLE);
  USART_Cmd(USART1, ENABLE);
}

この修正を以前書いたエントリのコードにも反映しておきましたので、
STM32F3Discoveryでの割り込みを利用したシリアル通信のコード全体に関してはそちらをごらんください。

--

[追記]
バグの原因を調査するべく、C言語で割り込みを用いたシリアル通信のコードを書きました
しかし、C言語で書いたものではこのような現象は再現しませんでした…

そのため、コードが悪いか、もしくはコンパイラに何らかの問題があるか、のどちらかの線が濃厚です。

0 件のコメント:

コメントを投稿