今日ハマった事。
Cubeが吐くHAL初期化コードはいくつかの種類があるが、ペリフェラルの初期化を行う際はグローバル変数を使用している。
一方、クロックの初期化(SystemClock_Config関数)はローカル変数を使用して、パラメータを設定後に初期化関数を呼び出す。この際、構造体のすべてのメンバを使用するわけではないので、Cubeは必用なメンバのみを設定する。が、本来は必用なメンバまでも設定しないで初期化関数に渡すことが有る。
どうなるかと言えば、ローカル変数は初期値が不定で、不定な設定のまま初期化するわけだから、正常に初期化されない場合がある。場合がある、というのが面倒で、例えば完全に電源を落としてメモリを初期化すると、また新たな不定値が設定されて、運が良ければ正常に初期化できたようにみえる。
普通、StdPeriphLibとか、HALもそうだけど、USE_FULL_ASSERTを定義した上で適切にassert_failed関数を作っておけば、StdPeriphLib、あるいはHALの関数内で異常値を検出してメッセージを出すことができる。が、今回は新しく作ったプロジェクトのため、まだassert_failedの中身を作っていなかった。なので気がつくまで時間がかかった。
クロックの初期化でコケると、UARTも正常に動作しない(そもそもUART初期化前にコケる)ので、どこにメッセージを出すかが問題。
とりあえず、char *p = (char *)0x20000000でメモリの先頭のポインタを作って、そこにsprintfでメッセージを保存することにした。assert_filedが呼ばれたらそこで無限ループに入れるようにしたので、メモリを破壊してもかまわない。メモリの中に入ったままでは読み出すことができないが、とりあえずST-Link(Nucleoについてたやつ)をSWDで接続して、メモリ先頭の数百バイトを表示すれば読むことができる。
なんか様々な不具合をすべてCube/HALに丸投げしたくなってきた。でもHALのほとんどはグローバル変数だから、未初期化はあんまり問題にならないんだよなぁ。グローバル変数でメモリを大量に消費する vs 未初期化問題が起こりづらいグローバル変数。
***
小ネタ。
STBee F4miniの大きさだとロジアナのピンヘッダに直接挿せる。
周辺回路が一切使えないけど、ソースコード中にGPIOをトグルするコードを追加してどこまでコードが進んでるかを確認するのに便利。ちゃんとデバッガを整えてやればこんなことしなくても良いんだろうけどなぁ。
でもピンヘッダ直差しの恩恵を十分に受けるには32chのモデルが必要になる。16chだとピンヘッダの片側しか読めない。
ロジアナはいちいちジャンパワイヤを接続するのが非常に面倒なので、基板を発注するレベルで大規模な物を作る時は、ロジアナのコネクタを直結できるデバッグコネクタを付けておけば楽かなぁ、とか思ったり。こんな大きさのコネクタを付けれるってどんなデカい基板になるのか知らんが。
0 件のコメント:
コメントを投稿