トホホな疑問(33) BBC micro:bitのピン番号にハマる。Arduino環境にて

Joseph Halfmoon

BBC micro:bitについては別シリーズ「ブロックを積みながら」でテキストでソースを書かずに使ってきました。デバッガ等も使用せず。もっぱらprintfデバッグ。しかし、だんだんとC/C++で「普通に」書かないとならない領分に踏み込みそうな気がします。それにデバッガも使いたい。PlatformIOあるし、簡単だし、などと思っていたらハマりました。単なるピン番号に。

BBC micro:bitの「主力」プログラミング環境である MakeCode エディタは表はVisualなGUI、裏ではJavaScript(実はTypeScript)またはPython(実は型のあるPython拡張)でプログラムができます。これはこれで相当なことまで出来るし、また新たなブロックなども定義はできるのですが、やはりプログラムが大きくなってくるとテキストベースかつ「プリミティブな」操作ができるものを使いたくなります。そんな場合に「使える」開発環境が、PlatformIOであります。こちらでは、

VS Code + PlatformIO

ということで使わせていただいております。PlatformIOは、必要なツールチェーンからライブラリ等のセットアップ、サンプルプログラムの取り込み、ビルド、デバッグにいたるまで至れり尽くせりな開発環境です。BBC micro:bit に関するフレームワークの対応状況は、BBC micro:bit と BBC micro:bit V2 ページを参照すると今のところ以下のようです。

フレームワーク V1系 V2
Arduino
Mbed ×
Zephyr

また、インタフェースCPU(NXP製)を搭載しているので、PlatformIO環境下では何もせずにデバッガも即使用できます。

Arduino環境でまずはLチカを

PlatformIOの使い方については過去にいろいろ投稿もしており、世間的にも情報が溢れているので省略します。とりあえず、

micro:bit V1.5 で Arduino環境つかってLチカしてみるか

ということで実施いたしました。本人的には一撃、一瞬のつもりであります。PlatformIOは偉いのでLチカのサンプルプログラムも自動生成してくれるのです。ただし、Nordic nRF51xxx系デバイスをCPUにいただく各種ボード共通のサンプルプログラムです。以下生成されたコードを引用させていただきます。

/*
 * Blink
 * Turns on an LED on for one second,
 * then off for one second, repeatedly.
 */

#include <Arduino.h>

#define LED_BUILTIN 13

void setup()
{
  // initialize LED digital pin as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  // turn the LED on (HIGH is the voltage level)
  digitalWrite(LED_BUILTIN, HIGH);
  // wait for a second
  delay(1000);
  // turn the LED off by making the voltage LOW
  digitalWrite(LED_BUILTIN, LOW);
   // wait for a second
  delay(1000);
}

このままビルド可能です。ただし、パッと見、BBC micro:bit V1.5 に不適な点に1点気が付きました。micro:bit V1.5の “BUILTIN” LEDは見た目が5×5、実は3×9のマトリックス構成なので、ROW側とCOLUMN側の2端子を同時に制御しないと点灯できないのです。ついでに

LED_BUILTIN

とされている「13番」端子について micro:bit V1.5の回路図を見てみました。この「13番」端子が、デバイスのP0.13端子ということであれば、回路図上 P0.13端子はLEDマトリックスのROW1に接続されています。これだけではLED点灯しません。どこかCOLUMN端子もドライブする必要があります。回路図上、COL1であればはP0.04端子に接続されています。COL1にLowを出しておいて、ROW1にHighを出せば見かけ5×5のLEDマトリックスの左上隅がLチカする筈。そう考えて接続しましたが、

しかしLチカしませぬ。

デバッガ使えるので、早速Lチカループ内にブレークかけてみるとちゃんと動作しているようです。それどころかエッジコネクタの「13番」端子に外付けLEDを接続すると見事に点滅します。

しばらく悩みました(グダグダ回路図を満遍なく読みました。)外付けLEDを取り付けるときに参照したピン配置図を公式サイトから引用させていただきます。

microbit_edge最終的に気付いたのは、

  • Arduino環境では上位の端子配置図にあるPxxという番号でプログラムする
  • カードエッジにはP0からP20までの信号が出ている
  • 上記のカードエッジに出ていない信号(Pxx相当の番号がある)も存在する
  • LEDマトリックスのROW信号はそのような信号である

そして

PlatformIOがダウンロードしてくれる、Arduinoプラットフォーム用のライブラリコードが直接扱っている端子番号は、nRF51zzzチップのP0.yy式の端子番号と1対1に対応しているが、これとPxx式の番号は違う

およよ、私は間違った番号で端子を制御しようとしていたのでした。以前にも何度も見たとおりArduinoプラットフォームの場合、各ボード固有の

variant.cpp

をよく眺めれば分かったことなのです。ただし今回のvariant.cppファイルの端子情報は、P0.yy式のyy部分の番号が列挙されているだけのものなのでパッ見で騙されていました。明示的にかかれていない配列添え字を想像すればよかったのです。それがPxx式のxx番号でした。トホホ。。。

備忘のため、以下に V1.5の端子機能とPxx(Arduino), P0.yy(nRF51xxx)の番号をまとめました。Arduino環境でコードを書くときは左のPxx式の番号で書く!

Pxx番号 P0.yy番号 端子機能
0 3 A0/left pad
1 2 A1/middle pad
2 1 A2/right pad
3 4 A3/COL1
4 5 A4/COL2
5 17 BTN A
6 12 COL9
7 11 COL8
8 18 digital I/O
9 10 COL7
10 6 A5/COL3
11 26 BTN B
12 20 digital I/O
13 23 SPI SCK
14 22 SPI MISO
15 21 SPI MOSI
16 16 digital I/O
17 3.3V
18 3.3V
19 0 SCL
20 30 SDA
21 25 RX
22 24 TX
23 7 COL4
24 8 COL5
25 9 COL6
26 13 ROW1
27 14 ROW2
28 15 ROW3
29 28 ACC INTR 1
30 27 ACC INTR 2
31 29 MAG INTR 2
32 19 RST

ううむ、これに気付かんとは浅墓な。。。

しかし、Arduinoは判明しつつも、MbedやZephyrが同じ番号であるのかどうかは分かりませぬ。もしかしてチップのピン番号かも。また確かめてみるしかありますまい。トホホ。

トホホな疑問(32) .inoファイル内のリソース参照、どうするのがよろしいの? へ戻る

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

ピン番号を誤解しているLチカと正しい番号のLチカ

「正しい」方はオンチップのLED、「誤解している」方はP13端子接続の外付けLEDが点滅します(アイキャッチ画像参照ください。)

#include <Arduino.h>

/* BAD PINS */
#define BAD_ROW1 13
#define BAD_ROW2 14
#define BAD_ROW3 15
#define BAD_COL1 4
#define BAD_COL2 5

/* ON BOARD LED MATRIX (micro:bit V1.5) */
#define ROW1  26
#define ROW2  27
#define ROW3  28
#define COL1  3
#define COL2  4
#define COL3  10
#define COL4  23
#define COL5  24
#define COL6  25
#define COL7  9
#define COL8  7
#define COL9  6

int counter = 0;

void setup()
{
  Serial.begin(9600);
  while(!Serial) {};
  Serial.println("Start.");
  pinMode(ROW1, OUTPUT);
  pinMode(BAD_ROW1, OUTPUT);
  pinMode(COL1, OUTPUT);
  pinMode(BAD_COL2, OUTPUT);
  digitalWrite(COL1, LOW);
  digitalWrite(BAD_COL2, LOW);
}

void loop()
{
  Serial.println(counter++);
  digitalWrite(ROW1, HIGH);
  digitalWrite(BAD_ROW1, LOW);
  delay(1000);
  digitalWrite(ROW1, LOW);
  digitalWrite(BAD_ROW1, HIGH);
  delay(1000);
}