続報:CubeIDEで生成したコードが、初期化中にassertionに失敗する

先日見つけたこの問題ですが、その後STMH7だけではなく、おそらくはすべてのプロセッサに共通する問題だとわかりました。

STのコミュニティからは「次のファームウェアで修正する」と返事が来ています。実はV1.6で見つかったこの問題はv1.7では修正されていません。もっとも、返事が来てからファームのリリースまで短かったので致し方ないところでしょう。

昨日自分で掘り下げてみたのですが、思いの外いやらしい問題でした。以下のすべてが絡みあった問題です。

  1. HAL_InitTick()は複数回呼ばれる
  2. 2回めに呼ぶ時のために前回の呼び出し時の引数をグローバル変数に保存するという暗黙の機能がある
  3. HAL_InitTick()はweak宣言されており、SysTick以外のタイマーを使うときには、CubeIDEがHAL_InitTick()を生成する

もうおわかりだと思いますが、CubeIDEが生成するコードに暗黙の機能が実装されていません。結果として2回めの呼び出しは不正パラメータになります。

アサーションに引っかかるようグローバル変数のデフォルト値を不正パラメータ値にしておくまでは良かったのですが、本番でテストしなかったみたいですね。

さて、自分が実装するとしたらどうするかですが、抜本的修正ができず上の1,2を変更出来ないのなら、HAL_InitTick()のweak宣言をやめます。その上でSysTick()以外のタイマーを使うときには、HAL_InitTickSub()のような関数をCubeIDEで生成し、HAL_InitTick()の中から呼びます。そうすれば、HAL_InitTick()の暗黙の機能を暗黙のまま隠しおくことが出来ます。ついでに前回の呼び出し結果を再使用するときに引数にHAL_TICK_INHERITのような定数を与える仕様にすれば、前回の引数の保存先は(現在のような)グローバル変数ではなくスタティック変数として関数内に閉じ込めることが出来ます。

もっともこれはHAL_Tick()をユーザーにオーバーロードさせないことが前提です。HALの設計はCubeIDEを前提としていませんから、CubeIDE利用者以外の事を考えれば、HAL_APIの仕様変更はしないでしょう。CubeIDEが生成するHAL_InitTick()に暗黙の機能を実装して終わりになると思います。

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください