2018年3月14日水曜日

STM32 HALのタイムアウト

 HALのタイムアウト処理にガッツリはまって原因が判明するまでものすごい時間かかったのでメモ。


 HALのブロッキングな関数は引数の最後にタイムアウト時間を指定できる。これは典型的にミリ秒を指定する。以降とりあえずミリ秒とする。
 この値は例えば5を指定すると、ブロック時間は「5ミリ秒未満」という処理になる。「5ミリ秒以上」では無い点に注意する必要がある。
 より正確的に言えば、「5回目のTickでタイムアウトする」という処理になる。

 例えば、SPIで1バイトずつポーリングする場合、HAL_SPI_Receive(&hspi1, &buff, 1, 1);というようなコードになる。この場合、1ミリ秒未満、あるいは1回目のTickでタイムアウトする。大抵の場合はこの処理で問題ないが、ある程度の確率で、Receiveを呼んだ直後にTick割り込みが発生する場合があり、その場合はSPIの1バイトを受信する前にタイムアウトエラーでSPI通信処理が終了する。この場合、当然ながら通信が正常に行われていないから、buffには何も書き込まれず、不正な値となってしまう。
 buffのデフォルト値としてビジーの値を書き込んでいると、相手はビジー終了を通知しているにもかかわらず、自分側はビジー値を読んでしまう、という結果になる。
 これはTick割り込みが発生する直前にReceiveを呼んだ場合にのみ発生するから、ある程度確率的な話になる。ということで、それなりの高頻度で発生しながら、よくわからない挙動を示す、という結果になる。


 まとめると、タイムアウトの値には 最低限待っていてほしい時間 + 1 を渡してあげようね、という話でした。


 ちなみに今回は10.5MHzでSPIを動かしてましたが、8bitの転送には760nsecくらいの時間で終わります。1msecの間の特定の760nsecの間で処理が行われるとエラーになる、なので、1300分の1くらいの確率でしょうか。1秒間に14回程度の処理を行い、1回の中でビジーチェックが30回程度行われるとすると、1秒に420回程度の機会があります。ということで、3秒程度でエラーが発生する計算です。実際には10秒前後でエラーを起こしていましたから、当たらずとも遠からず、といった感じです。

 しばらく調べていて、ようやくビジーチェックが怪しいぞ、とあたりを付けた時はSPIクロックを下げたりも試したのですが、一向に改善しませんでした。外の問題ではなく、内の問題だったので、全く見当違いのところを調べていたことになります。

0 件のコメント:

コメントを投稿