別シリーズにてMakeCode環境(JavaScript)でBBC micro:bit v2をプログラムしていたのですが問題に遭遇し、C/C++系に開発環境を変えてやり直してみるかと考えました。候補となる環境はArduino、Mbed、Zephyrなのですがそれぞれにまた一長一短あります。まずは前回に続きArduino環境を調べてみることにいたしました。
※「トホホな疑問」投稿順Indexはこちら
(今回使用の実験用コード全文は末尾にあります)
別シリーズでのMakeCode環境の問題というか、制限というかは、以下の疑いであります。
BBC micro:bit v2 のメモリ容量をフルに使いきれないのではないか?
MakeCode自体は v2 特有の機能にも対応しているのですが、生成するHEX形式コードは v1系、v2系の両方のコードを含むため、v1で走らせられる大きさに制限されているのではないかという疑いであります。状況証拠でしかないのですが、拡張モジュール、今回はBluetooth、をインストールするとプログラム可能な容量の上限にすぐに達し、コンパイル時エラーが発生しているように思われました。
micro:bit v2は、v1.xに比べるとFlash容量、RAM容量ともに数倍になっているので、v2専用にオブジェクトを作れれば、そのような問題が解消されるように思われました。しかし、MakeCodeでは今のところその方法が分かりません。
C/C++のビルド環境では、ビルド時にターゲットをnRF51(v1.x系)かnRF52(v2)の特定チップに決める必要があるので、nRF52のチップ指定すればちゃんと全部のメモリを使いきれるんでないか、という希望であります。
前回もちょっと書きましたが、候補は以下の3つの環境(プラットフォーム)です。
-
- Arduino
- Arm Mbed
- Zephyr
Arduinoは定番中の定番、一番お手軽な環境といっていいでしょう。前回すでに micro:bit v1.5 で吉例のLチカをビルドして動作確認しています。しかし、v2は v1.5 とまったく同じコードではうまく行かないことに気づきました。変更点要確認です。bluetoothに関しては、NordicのSDKベースで使えるようなのでなんとか成るかとは思いますが、MakeCodeで使ってきた「出来合い」のBLEサービス呼び出しのようには簡単にいきそうにありまっせん。トホホ。
Arm Mbedは、Arm社のOS環境です。micro:bit用のbluetoothモジュールの開発者?でもあるらしい英Lancaster大がmicro:bit用のC++のライブラリを提供してくれています。ターゲットはMbedです。Lancaster大のライブラリを使えば MakeCode上で使えていた各種BLEサービスがそのまま使えるみたいです。これはらくちん。個人的には、MbedOS は以前にそこそこ触ったことあり、なんとかなるでしょう(本当か?)その辺のらくちんさを考えるとMbedで決まりかと思ったのですが、1つ大きな問題があります。上記のライブラリをちょっと見てみると v1.x系のCPUであるnRF51 はサポートされているのですが、v2系のnRF52のサポートが見当たりません。v1.x系のmicro:bitでMbed使用するのはまったく問題なさそうですが、v2ではうまくいかない可能性がありそうです。Mbedの利用は、まずは確実に動くであろうv1.x系での修練を積んでからですな。
Zephyrは、nRF51でもnRF52でもサポートがあるとドキュメントにあります。しかし、個人的に慣れの問題が不安。以前に、ちょっとサンプルプログラムをビルドしたことはあるのですが、実際にZephyrを使って何か書いた経験ありません。OSそのものから勉強しないとならないので、ちと敷居が高いです。まあ、別シリーズでZephyrの初歩から学ぶことにいたしたい。
そんなこんな個人の事情なども並べたてました。まずはArduino環境での micro:bit v2のプログラミングです。以下の点をハッキリさせておかないと前回同様にハマります。
-
- Arduino環境でプログラミングに使う端子番号は v1.xとv2で異なる(チップのピン番号とはそもそも異なる)
- 回路もv1.xとv2で異なる
例えば、BBC micro:bitの一大特徴である5x5のLEDマトリクスはv1.x系にもv2にも存在します。しかし、v1.x系はROW3端子、COLUMN9端子の非対称な構成で12端子を使って制御、v2系はROW5端子、COLUMN5端子の直交的な配置で10端子で制御です。その違いを理解しておかないとLチカすらまともに動きませぬ。前回の経験があるので多少学びました(?)今回は最初から v2 用のArduinoプログラム端子番号の一覧表を作成いたしました。以下の通り。
micro:bit v2、Arduino環境でプログラミングに使う端子番号とその機能
Pxx番号 | 端子機能 |
---|---|
0 | A0, LEFT PAD |
1 | A1, MIDDLE PAD |
2 | A2, RIGHT PAD |
3 | A3, COL3 |
4 | A4, COL1 |
5 | BTN A |
6 | COL4 |
7 | COL2 |
8 | NFC2, GPIO1 |
9 | NFC1, GPIO2 |
10 | A5, COL5 |
11 | BTN B |
12 | SCK |
14 | MISO |
15 | MOSI |
16 | GPIO3 |
17 | 3.3V |
18 | 3.3V |
19 | SCL |
20 | SDA |
21 | ROW1 |
22 | ROW2 |
15 | ROW3 |
24 | ROW4 |
19 | ROW5 |
26 | LOGO (touch sensor) |
27 | SPEAKER |
28 | RUN_MIC |
29 | A6, MIC_IN |
30 | I2C_INT_SDA |
31 | I2C_INT_SCL |
32 | COMBINED_SENSOR_INT |
33 | RX |
34 | TX |
機能でAxなるものはアナログ入力可能な端子だと思います。また、P20までは micro:bit の「カードエッジ」に出力されていますが、21番から後はボード上のみでの接続です。
PlatformIOのプロジェクトコンフィグレーション
さて、BBC micro:bit v2のArduino環境でのビルドには ArduinoIDEではなく、VSCode + PlatformIO を使用いたしました。デバッガも使えるこちらの開発環境の方が今回よろしいかという判断であります。PlatfromIOは、ちゃんと BBC micro:bit V2をV1とは違うボードとして扱ってくれています。安心。V2についてのドキュメンテーションは以下に。
ビルド、アップロード、デバッグ等の設定のために使用する platformio.ini ファイルは以下の用にしてみました。アップロード、デバッグともデフォルトがcmsis-dapなので、明示的な指定不要かと思いましたが念のため。
[env:bbcmicrobit_v2] platform = nordicnrf52 framework = arduino board = bbcmicrobit_v2 upload_protocol = cmsis-dap debug_tool = cmsis-dap
さて、先に掲げたピン番号と機能の表を眺めつつ、作成したmicro:bit v2用のLチカのプログラムを末尾に掲げました。たまたまボードに書き込まれていた以前のプログラムが左上隅のLED1個を点滅させていたので、書き込んだ事がアカラサマに見えないと困るという事情から、左上からLEDを2個点滅させるようになっています。
ビルドは成功。アップロードもOK。動作しているところはアイキャッチ画像に。次回からは別シリーズに場所を移し、Arduino環境でBluetoothのSDKのお勉強ですな。先は長そう。
トホホな疑問(34) BBC micro:bitのピン番号にハマる。Arduino環境にて へ戻る
トホホな疑問(35) Mbed Studio、ビルドも実行もできるんですが。。。へ進む
BBC micro:bit V2 ArduinoフレームワークでのBlinkサンプル
#include <Arduino.h> /* ON BOARD LED MATRIX (micro:bit V2.0) */ #define ROW1 21 #define ROW2 22 #define ROW3 23 #define ROW4 24 #define ROW5 25 #define COL1 4 #define COL2 7 #define COL3 3 #define COL4 6 #define COL5 10 int counter = 0; void setup() { Serial.begin(9600); while(!Serial) {}; Serial.println("Start."); pinMode(ROW1, OUTPUT); pinMode(COL1, OUTPUT); pinMode(COL2, OUTPUT); digitalWrite(COL1, LOW); digitalWrite(COL2, LOW); } void loop() { Serial.println(counter++); digitalWrite(ROW1, HIGH); delay(1000); digitalWrite(ROW1, LOW); delay(1000); }