はじめに
趣味で宇宙開発を行う団体「リーマンサット・プロジェクト」がお送りする新春アドベントカレンダーです。
この記事は8日目です。
リーマンサット・プロジェクトは「普通の人が集まって宇宙開発しよう」を合言葉に活動をしている民間団体です。
他では経験できない「宇宙開発プロジェクト」に誰もが携わることができます。
興味を持たれた方は https://www.rymansat.com/join からお気軽にどうぞ。
この記事は
この記事ではWEB開発や組み込み開発などのシステム開発をしたことがある方(シェルやプログラムが使えること)を前提にしています。
僕はリーマンサットで超小型人工衛星である「RSP-00」と「RSP-01」の無線通信のソフトウェア開発を担当しています。
RSP-01の無線通信制御には STM32(arm)マイコン
とオープンソースな組み込み開発環境である mbed
を採用しました。 STM32(arm)マイコン
はマイコンの中でも比較的スペックが高く、 mbed
のAPIがハードウェアを抽象化してくれるためソフトウェア開発が進めやすいといった利点がありました。また、使用したマイコンは宇宙環境を想定した恒温槽試験や放射線試験で問題がなかったことも選定に至った理由です。
リーマンサット・プロジェクトは文理問わず様々な職業の方が参加しており、事前知識やスキルはメンバー毎に大きく異なります。普段開発に関わることの無いメンバーでも組み込み開発を体験もらうために、メンバーの某御方が BluePill
という格安の開発ボードを大量入手して教材として配布していました。そこで今回はこの BluePill
向けに mbed
の開発環境を構築してみました。
BluePillって
BluePill
は STM32F103C8T6
を搭載した開発ボードです。この開発ボードはとても安くで200円ほどで買えてしまい、なぜかIC単体で買うよりも安いといった不思議なボードです。
また、 STM32F103C8T6
はデータシート上64KByteの Flash Memory
を搭載しているとありますが、なぜか ```BluePill`` では128KByte搭載されているとの噂です。不思議ですねー。記事の下部で検証してみましたが、手元のものも128KByte扱うことができました。
BluePill
の開発方法ですが Arduino IDE
を使うことが多いようです。 Arduino
は情報量が多いので、使い方を調べやすいといった利点があり、 BluePill
の Arduino IDE
開発環境の構築も調べるといくつか出てきます。
一方で mbed
を使用した方法はあまり情報がありませんが、 mbed
の内部では HAL
というベンダーが提供しているライブラリが使われているため、 BluePill
の能力を最大限まで引き出すことができると考えています。
また、 OpenOCD
PyOCD
といったデバッグツールも用意されているため、一度環境を整えてしまえば最近流行りの Visual Studio Code(VSCode)
を操作するだけで BluePill
のソフト開発・ファームウェアの書き込み・ステップ実行までをおこなう事ができて非常に便利だったため記事に残してみました。
開発環境
ハードウェア
- Macbook Pro(Retina, 13-inch, Late 2013)
- BluePill
- STLink v2
ソフトウェア
- macOS Catalina v10.15.1
- Visual Studio Code v1.41.1
- Mbed CLI v1.10.2
- gcc-arm-none-eabi 9-2019-q4-major
- OpenOCD v0.10.0
今回はmacOS上で構築しましたが、 VSCode
Mbed Cli
gcc-arm-none-eabi
OpenOCD
はWindowsやLinux上でも動作しますので、インストールすれば同様に構築可能と考えています。
ブロック図
OpenOCD
arm-none-eabi-gdb
はVSCodeから起動されます。
各ツールのインストール
Visual Studio Code
こちらからインストーラー経由でインストールします。
また、 VSCode上の拡張機能の追加から C/C++
のプラグインをインストールしておきます。
C/C++
プラグインがあると、GDB
を使ったデバッグ実行や、ソースコード上の 定義
宣言
参照
に素早くアクセスしたり、構文エラーにいち早く気付けます。
Mbed CLI
Windowsの場合はインストーラーでインストールするのが簡単でした。
macOSの場合はインストーラーでインストールすると専用のシェルが立ち上がり、普段の環境を汚さないようになっています。サクッと試すのであればインストーラーの方が簡単ではありますが、使い慣れたシェル上で扱えない上、この後のVSCodeからの呼び出しでパスが通っていなかったりするため、個人的にはマニュアルインストールの方がおすすめです。
$ brew install python@2
$ pip install mbed-cli
gcc-arm-none-eabi
インストーラー経由の場合、 gcc-arm-none-eabi
は自動でインストールされますが、マニュアルインストールの場合は別途インストールする必要があります。
$ brew tap ArmMbed/homebrew-formulae
$ brew install gcc-arm-none-eabi
OpenOCD
$ brew install OpenOCD
Windowsのインストール方法はまだ調べれてないです。。
プロジェクトのセットアップ
下記のコマンドでプロジェクトをセットアップします。
$ mbed new bluepill_first_project
$ cd bluepill_first_project
$ mbed toolchain GCC_ARM
$ mbed target BLUEPILL_F103C8
-
mbed new
: プロジェクトの作成 -
mbed toolchain
: 使用するコンパイラ、今回はGCC_ARMを指定する -
mbed target
: 開発ボードの指定
そして main.cpp
ファイルを下記内容で作成します。組み込み開発の Hello World!
、Lチカのソースコードです。
#include "mbed.h" // mbed OSの読み込み
DigitalOut led1(LED1); // mbed target BLUEPILL_F103C8でボード上のLEDがLED1と定義される
int main() {
while (true) {
led1 = !led1; // 出力のHIGH/LOWをトグル
wait_us(1 * 1000 * 1000); // 1秒
}
}
あとは下記コマンドでコンパイルすると、開発ボードに書き込むファームウェア(バイナリ)が生成されます。
$ mbed compile
正常終了時は以下のように出力されます。
Link: bluepill_first_project
Elf2Bin: bluepill_first_project
| Module | .text | .data | .bss |
|------------------|--------------|------------|-------------|
| [fill] | 46(+22) | 8(+0) | 21(+9) |
| [lib]/c.a | 17428(+0) | 2472(+0) | 56(+0) |
| [lib]/gcc.a | 3104(+0) | 0(+0) | 0(+0) |
| [lib]/misc | 180(+0) | 4(+0) | 28(+0) |
| main.o | 64(+0) | 0(+0) | 28(+0) |
| mbed-os/drivers | 74(+0) | 0(+0) | 0(+0) |
| mbed-os/hal | 1356(+0) | 4(+0) | 66(+0) |
| mbed-os/platform | 2646(+316) | 260(+0) | 220(+10) |
| mbed-os/rtos | 6380(+6380) | 168(+168) | 5973(+5973) |
| mbed-os/targets | 6046(+690) | 4(+0) | 368(+0) |
| Subtotals | 37324(+7408) | 2920(+168) | 6760(+5992) |
Total Static RAM memory (data + bss): 9680(+6160) bytes
Total Flash memory (text + data): 40244(+7576) bytes
Image: ./BUILD/BLUEPILL_F103C8/GCC_ARM/bluepill_first_project.bin
一般的なmbedの開発ボードであれば開発ボード上に mbed interface
と呼ばれるICが乗っており、開発ボードをUSB接続するとドライブがマウントされるので、先程生成された ./BUILD/BLUEPILL_F103C8/GCC_ARM/bluepill_first_project.bin
をドラッグ・アンド・ドロップ(コピー)すればファームウェアの書き込みができます。
ですが、 BluePill
には mbed interface
が搭載されておらず、その機能がありません。
VSCode(OpenOCD)を使った書き込みとデバッグ
BluePill
では mbed interface
が搭載されていないため、代わりに STLink v2
という書き込み機器を使用してファームウェアを書き込みます。
BluePill
と STLink v2
の 3.3V
GND
SWDIO
SWCLK
をそれぞれ接続します。
下記コマンドで VSCode用の設定ファイルを出力します。
$ mbed export -i vscode_gcc_arm
生成された .vscode/launch.json
に下記修正を加えます。
@@ -11,11 +11,11 @@
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": false,
- "debugServerArgs": "",
+ "debugServerArgs": "-f /usr/local/Cellar/open-ocd/0.10.0/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/local/Cellar/open-ocd/0.10.0/share/openocd/scripts/target/stm32f1x.cfg",
"serverLaunchTimeout": 20000,
"filterStderr": true,
"filterStdout": false,
- "serverStarted": "GDB\\ server\\ started",
+ "serverStarted": "openocd",
"preLaunchTask": "make",
"setupCommands": [
{ "text": "-target-select remote localhost:3333", "description": "connect to target", "ignoreFailures": false },
@@ -41,7 +41,7 @@
"osx": {
"MIMode": "gdb",
"MIDebuggerPath": "arm-none-eabi-gdb",
- "debugServerPath": "pyocd-gdbserver"
+ "debugServerPath": "openocd"
},
"windows": {
"preLaunchTask": "make.exe",
以上で準備は完了です。
VSCodeの「デバッグと実行」からコンパイル・書き込み・デバッグを開始してみます。
無事 BluePill
へ書き込みができ、ステップ実行やローカル変数への参照ができました!
おまけ
BluePillのFlashサイズ
STM32F103C8T6
は公式で64KByteの Flash Memory
を搭載しているとありますが、128KByte搭載されているとの噂があるため、実際に検証してみました。
やり方は簡単で、 printf
とかで10000文字くらいの文字列を適当に追加していきます。
Lチカのソースコードをコンパイルすると約44KByteでした。10000文字で約10KByteなので8行ほど追記してみます。(同じ文字列だとコンパイラに最適されるため少しだけ文字を変えてます。)
printf("1aaaaaaaaaa...");
printf("2aaaaaaaaaa...");
...
これでコンパイルして書き込めば・・・と思ったのですが、想定外にもコンパイルの時点でエラーが発生しました。
Link: bluepill_first_project
/usr/local/Cellar/arm-none-eabi-gcc/9-2019-q4-major/gcc/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: ./BUILD/BLUEPILL_F103C8/GCC_ARM/bluepill_first_project.elf section `.text' will not fit in region `FLASH'
/usr/local/Cellar/arm-none-eabi-gcc/9-2019-q4-major/gcc/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: region `FLASH' overflowed by 58112 bytes
collect2: error: ld returned 1 exit status
どうやら64KByteの制限がかかっているようです。
下記ファイルで64KByteの制限をかけているようなので、力技ですが直接編集してしまいます。(mbed-os
ディレクトリは基本的にgit管理外とするため注意)
./mbed-os/targets/TARGET_STM/TARGET_STM32F1/TARGET_BLUEPILL_F103C8/device/TOOLCHAIN_GCC_ARM/STM32F103XB.ld
@@ -9,7 +9,7 @@
MEMORY
{
- FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (rwx) : ORIGIN = 0x200000F0, LENGTH = 20K - (0xEC+0x4)
}
上記修正を加えた後、コンパイルと書き込みを試したところ無事書き込むことができました!この時のバイナリサイズは126KByteでしたので、噂は本当でした!
Mbed OS bare metalを試してみる
Mbed OS
では、スペックの低いマシンでも一部の機能(主にRTOS)を無効にすることで、 Mbed OS
を使うことができるbare metalと呼ばれる仕組みがあります。
BluePillには Mbed OS 5
の記載がないため Mbed 2
や bare metal
での実行が必要だろうなと予想していましたが、上記で試したLチカは Mbed OS 5
で問題なく動いてしまいましたw
ただ、せっかくなので bare metal
でもコンパイルしてみたいと思います。
mbed_app.json
を下記のように編集して、後はいつも通りにコンパイルするだけでした。
{
"requires": ["bare-metal"]
}
Mbed OS 5
時のバイナリサイズが44Kbyteに対し、 bare metal
時のバイナリサイズが35Kbyteと少しだけダイエットに成功です。恩恵はあまり多くありませんが、少しでもバイナリを小さくする必要があったり、RTOSを意図的に無効にしたい場合の選択肢になるのかなと思います。
今後の目標
シリアル通信
今回は VSCode上で BluePill
のコンパイルと書き込み・デバッグまでできることが確認できました。
これだけでも開発をすすめるには十分ですが、printf
といった標準入出力の対応も検討したいと考えてます。
mbed interface
が搭載されている開発ボードであれば、USBからシリアル通信で標準入力・出力へのアクセスが可能ですがSTLink
には同等の機能が搭載されていないため以下の三種類の方法が検討されます。
- FT234X 超小型USBシリアル変換モジュールのような外部のUSB・シリアル通信変換モジュールを使う
-
STLink
のSWO
機能を使う -
BluePill
上のUSBにシリアル通信の機能を実装する
外部のUSBシリアル通信変換を用いれば他のmbed開発ボードと同様に標準入出力が利用できますが、ケーブル2本用いるためスマートとは言えません。
SWO
を使えば追加のモジュールやケーブルは不要となるためスッキリとしますが、環境の用意が少し手間取りそうだったため今回は深追いできてません。。
環境構築
開発環境の構築は既存マシンの環境に依存する箇所があるため、上記手順でうまく構築できない場合もあると思います。
そういった所をDockerで置き換えていけたら環境構築のトラブルを減らせるのかななんて考えてます。(DockerではUSB周りがうまく動作しないと思うので、 OpenOCD
と GDB
を Docker Network
で繋げるのがいいのかななんて妄想しています。)
参考記事
STM32F103C8 で遊ぶ
Arm Mbed CLIの環境構築 for Windows
mbed CLI (コマンドライン・インタフェース)を Mac OS X で使ってみる
Visual Studio Codeでmbed OSプログラムをデバッグする方法(STM32)
STM32F103C8T6 board, alias Blue Pill
おわりに
リーマンサット・プロジェクトは「普通の人が集まって宇宙開発しよう」を合言葉に活動をしている民間団体です。
他では経験できない「宇宙開発プロジェクト」に誰もが携わることができます。
興味を持たれた方は https://www.rymansat.com/join からお気軽にどうぞ。
次回は @ytakuro0926 さんの「C# & Unityで小型衛星姿勢制御ツールを作ってみた①」です。楽しみですね!