The PCを自作する。その3: STMマイコン
The PCを自作するシリーズ。
今回は、使うマイコンを試してみる。
全ての作業はDebian Linuxが入ったPCでやってる。
BlackPill
使おうと画策してるマイコンはSTM社製STM32F1系統の開発基板BlackPillだ。
こちらはもう買ってあって未開封で手元にあった。
(左がBlackPillで、右がSTLinkV2)
STM32F103が乘った開発ボードは青い基板の通称BluePillと言われる基板が有名だが、 このBluePillにはUSBポートの抵抗値が間違っていて、 PCによっては通信できないという問題があって、 BlackPill基板はそこが解消されている。 Aliexpressで1つ2ドル弱(送料込み)で買った。
また同時に、デバッグツールのSTLinkV2も買った。 こちらも、Aliexpressで2ドルぐらい(送料込み)だった。
ツールチェイン
BlackPillが使えるツールチェインは各種あるけど、 今回はSTM32Duinoを使う事にした。
STM公式のCubeMXとか、ARM汎用のCMSISとか、MBedとかあるけど、 STM32Duinoが一番手軽っぽいので。 STM公式のツールを直に使うには、 ユーザー登録とか必要でめんどくさい。
接続
PCとBlackPillを接続したいんだけど、 繋いで何をしたいかというと次の3つの事をしたい。
- BlackPillにプログラムを書き込む
- BlackPillとPCの間で通信する
- BlackPillで動いてるプログラムをPCからデバッグする
調べた感じ、これを1種類でやる方法はないみたい。
BlackPillについてるUSBコネクタで、1と2は可能みたい。 また、STLinkV2をつかうと1と3はできる。
今回は、1と2をBlackPillについてるUSBポートで行い、 つまって3が必要だったらSTLinkV2を繋ぐ体制で行きたい。
下準備
STM32DuinoのスタックでBlackPillにプログラムを書き込む方法はいくつかあり、 どうもSTM32Duinoのイチオシは、 STM32CubeProgrammerっていうソフトを使う方法みたいなんだけど、 これはSTM公式サイトから別途ダウンロードしないといけないみたいでめんどい。
調べたらSTM32BootloaderというのをBlackPillに入れると、 BlackPillがDFUプロトコルをしゃべれるようになり、 PCからプログラムを送り込めるみたい。
しかし、STM32Bootloaderを入れるのは、STM32Bootloader無しでやらないといけない。 (缶詰の中の缶切り)
ここにSTM32CubeProgrammerが必要だと嫌だなと思ったが、 Debianだと、stlink-toolsパッケージにあるst-flashコマンドが使えた。
まず、最初に、ピンヘッダを半田付けした。
基板真ん中にあるジャンパは起動時に BlackPill内のどのプログラムから起動するかを選択する物みたい。 CPU自体は常に0番地から起動するので、 Flashをブート元として選んだら、Flash領域が0番地に見えるようにマップしてくれる。 STM32Bootloaderを使うためにFlash領域を選ぶには2つとも0にする。 この辺はDEKOさんのページを参考にした。 STLinkV2からプログラムを書く場合はどこに設定していても大丈夫だと思う。
STLinkV2とBlackPillを線4本で繋ぐ。 STLinkV2に書かれている説明と、BlackPillのシルクにあわせて繋げばよかった。
ブートローダのバイナリはここからダウンロードした。 BlackPillはLEDがPB12というピンに繋ってるので、 generic_boot20_pb12.binにした。
STLinkV2をPCのUSBポートにつないで、 次のコマンドを実行して書き込んだ。
sudo apt install stlink-tools
st-flash write generic_boot20_pb12.bin 0x8000000
フラッシュ領域のアドレスは0x8000000から初まるらしい。でかい。
書き込んだ後に、STLinkV2を外して、BlackPill側のUSBをPCに接続して、 LEDが6回高速に点滅したら成功。
STM32duinoのセットアップ
次はアプリケーションプログラムを書きこんでみる。
まず、ArduinoIDEをセットアップする。 これは展開するだけ。
ArduinoIDEにSTM32Duinoのプラグインする。 説明するのが面倒になってきたので、このページを見るといいと思う。 JSONはこのURLを指定した。
https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json
Boardで”Generic STM32F1 Series”を、 Upload methodで、”Maple DFU Bootloader 2.0”を選んだ。 2.0じゃないのとどう違うのかわからない。
あと、udevのルールを書く必要がある。 このページを参考にして書いた。
アップロードを押すとコンパイルが走って、書き込み処理が走るんだけど、 うまくいかない事がある。
トラブル1 書き込み
たぶん、正常に動作してる時は、 自動で書き込みモードに入って、 書き込みが完了するんだけど、 これは、BlackPillでCDCを監視するプログラムが動いてないと駄目っぽい。 最初に書き込む時とか、 スケッチがCDCで通信できないような状況(何かバグって暴走してるときとか)だと、 書き込みモードに手でする必要がある。
DEKOさんのページでは、永続ブートローダーモードを使うと書いてあるけど、 BlackPillにはそのピンがない。
タイミングを見て、コンパイルが完了する直前にBlackPillのリセットボタンを押せばいいんだけど、 何回かやらないと成功しない。
トラブル2 LTOが動かない
最適化の設定をLTO(リンク時最適化)付きにすると、 そもそも全く動かない。 STM32Duinoのフォーラムで聞いてみたけど、 いまのところLTOを切るしかないようだ。
デバッグ
STLinkV2を使うとGDBでデバイスをデバッグできる。
STLinkV2をPCとBlackPillにつないでデバッグするんだけど、 うっかりBlackPillに複数箇所から電源を入れると良くない事がおきそうなので、気をつけたい。 BlackPillのUSBは外してSTLinkV2からだけ電源をもらうか、 STLinkV2とBlackPillの間の電源の線は繋がないようにするか。
ソフトウエア側は次のようにしたらできた。
sudo apt install openocd gcc-arm-none-eabi binutils-arm-none-eabi libnewlib-arm-none-eabi gdb-multiarch
openocd -f /usr/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/share/openocd/scripts/target/stm32f1x_stlink.cfg
gdb-multiarch
target remote localhost:3333 # GDBのプロンプトで
openocdはSTLinkV2と通信するが、自身はフロントエンドがなく、3333ポートでgdbからの通信を受けつけるみたい。
LTOが動かないのをこれで見てみた。 変なところで割り込みがおきて、無限ループしてるのが観測できて、 優秀だなと関心していたが、問題は解決できてない。