トホホな疑問(34) BBC micro:bit V2のArduinoピン番号はまた違う

Joseph Halfmoon

別シリーズにて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つの環境(プラットフォーム)です。

    1. Arduino
    2. Arm Mbed
    3. 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のプログラミングです。以下の点をハッキリさせておかないと前回同様にハマります。

    1. Arduino環境でプログラミングに使う端子番号は v1.xとv2で異なる(チップのピン番号とはそもそも異なる)
    2. 回路も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についてのドキュメンテーションは以下に。

BBC micro:bit 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);
}