前回オンラインエディタで micro:bit のプログラムをビルドして動作させてみましたが、 micro:bit は mbed にも対応しているので、今回は mbed を使ってオフライン環境で CLI からビルドしてみたいと思います。 mbed の Web IDE もかなり優秀だと思うのですが、意図せずブラウザバックしてしまったりなどブラウザの操作性に依存するところがあるのと、今まで CLI で vim を使ってコードを書いていたので、継続的にコードを書いていくのであればやはりオフラインビルド環境を作りたくなってしまいます。
mbed CLI だとエラー
まずは以前 BLE Nano の時に使った mbed CLI を使おうと色々と試してみました。
micro:bit は mbed OS 5 に対応していないので、 mbed OS 5 のプロジェクトとして作成してターゲットを micro:bit にしていると、コンパイル時に怒られます。
[vagrant@localhost vagrant]$ mbed new microbit_sample [mbed] Creating new program "microbit_sample" (git) [mbed] Adding library "mbed-os" from "https://github.com/ARMmbed/mbed-os" at branch latest [mbed] Updating reference "mbed-os" -> "https://github.com/ARMmbed/mbed-os/#6e0d01cd13e8aca7bf4d697c3699ec9225386881" [vagrant@localhost vagrant]$ [vagrant@localhost vagrant]$ cd microbit_sample/ [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed toolchain GCC_ARM [mbed] GCC_ARM now set as default toolchain in program "microbit_sample" [vagrant@localhost microbit_sample]$ mbed target NRF51_MICROBIT [mbed] NRF51_MICROBIT now set as default target in program "microbit_sample" [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed compile Building project microbit_sample (NRF51_MICROBIT, GCC_ARM) Scan: . Scan: env Scan: mbed Scan: FEATURE_BLE Could not compile for NRF51_MICROBIT: Target does not support mbed OS 5
次に BLE Nano の時と同様に、 mbed OS 2 のプロジェクトとして mbed のライブラリを落としてくる方法を試してみましたが、コンパイル時にエラーになってしまいます。
[vagrant@localhost vagrant]$ mbed new microbit_sample --mbedlib [mbed] Creating new program "microbit_sample" (git) [mbed] Adding library "mbed" from "https://mbed.org/users/mbed_official/code/mbed/builds" at latest revision in the current branch [mbed] Updating reference "mbed" -> "https://mbed.org/users/mbed_official/code/mbed/builds/tip" [mbed] Couldn't find build tools in your program. Downloading the mbed 2.0 SDK tools... [vagrant@localhost vagrant]$ [vagrant@localhost vagrant]$ cd microbit_sample/ [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed deploy [mbed] Updating library "mbed" to branch tip [mbed] Downloading library build "fb8e0ae1cceb" (might take a minute) [mbed] Unpacking library build "fb8e0ae1cceb" in "/vagrant/microbit_sample/mbed" [mbed] Updating the mbed 2.0 SDK tools... [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed add http://mbed.org/teams/Lancaster-University/code/microbit/ [mbed] Adding library "microbit" from "https://mbed.org/teams/Lancaster-University/code/microbit" at latest revision in the current branch [mbed] Adding library "microbit/microbit-dal" from "https://developer.mbed.org/teams/Lancaster-University/code/microbit-dal" at rev #eb91bba49623 [mbed] Adding library "microbit/microbit-dal/BLE_API" from "https://developer.mbed.org/teams/Lancaster-University/code/BLE_API" at rev #dd2f69fad8c6 [mbed] Adding library "microbit/microbit-dal/mbed-dev-bin" from "https://developer.mbed.org/teams/Lancaster-University/code/mbed-dev-bin" at rev #768173a57492 [mbed] Adding library "microbit/microbit-dal/nRF51822" from "https://developer.mbed.org/teams/Lancaster-University/code/nRF51822" at rev #b84f72a53341 [mbed] Adding library "microbit/microbit-dal/nRF51822/nrf51-sdk" from "https://developer.mbed.org/teams/Lancaster-University/code/nrf51-sdk" at rev #54ddd6f8268c [mbed] Updating reference "microbit" -> "https://mbed.org/teams/Lancaster-University/code/microbit/#4b89e7e3494f" [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed toolchain GCC_ARM [mbed] GCC_ARM now set as default toolchain in program "microbit_sample" [vagrant@localhost microbit_sample]$ mbed target NRF51_MICROBIT [mbed] NRF51_MICROBIT now set as default target in program "microbit_sample" [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed compile Building project microbit_sample (NRF51_MICROBIT, GCC_ARM) Scan: . Scan: mbed Scan: env Compile [ 1.0%]: main.cpp [Error] MicroBitMatrixMaps.h@73,49: 'p13' was not declared in this scope [Error] MicroBitMatrixMaps.h@74,49: 'p4' was not declared in this scope [ERROR] In file included from ./microbit/microbit-dal/inc/core/MicroBitDevice.h:42:0, from ./microbit/inc/MicroBit.h:33, from ./main.cpp:1: ./microbit/microbit-dal/inc/drivers/MicroBitMatrixMaps.h:73:49: error: 'p13' was not declared in this scope #define MICROBIT_DISPLAY_ROW1 p13 ^ ./microbit/microbit-dal/inc/drivers/MicroBitMatrixMaps.h:155:5: note: in expansion of macro 'MICROBIT_DISPLAY_ROW1' MICROBIT_DISPLAY_ROW1, ^ ./microbit/microbit-dal/inc/drivers/MicroBitMatrixMaps.h:74:49: error: 'p4' was not declared in this scope #define MICROBIT_DISPLAY_COL1 p4 ^ ./microbit/microbit-dal/inc/drivers/MicroBitMatrixMaps.h:156:5: note: in expansion of macro 'MICROBIT_DISPLAY_COL1' MICROBIT_DISPLAY_COL1, ^ [mbed] ERROR: "/usr/local/pyenv/versions/anaconda2-4.4.0/bin/python" returned error code 1. [mbed] ERROR: Command "/usr/local/pyenv/versions/anaconda2-4.4.0/bin/python -u /vagrant/microbit_sample/.temp/tools/make.py -t GCC_ARM -m NRF51_MICROBIT --source . --build ./BUILD/NRF51_MICROBIT/GCC_ARM" in "/vagrant/microbit_sample" ---
これは mbed のライブラリと micro:bit のライブラリでピンの定義が異なっているためです。 mbed のライブラリでは下記のように GPIO ピンが大文字で定義されています。
//MCU PINS P0_0 = 0, P0_1 = 1, P0_2 = 2, P0_3 = 3, P0_4 = 4, P0_5 = 5, P0_6 = 6, P0_7 = 7, P0_8 = 8, P0_9 = 9, P0_10 = 10, P0_11 = 11, P0_12 = 12, P0_13 = 13, P0_14 = 14, P0_15 = 15, P0_16 = 16, P0_17 = 17, P0_18 = 18, P0_19 = 19, P0_20 = 20, P0_21 = 21, P0_22 = 22, P0_23 = 23, P0_24 = 24, P0_25 = 25, P0_26 = 26, P0_27 = 27, P0_28 = 28, P0_29 = 29, P0_30 = 30,
mbed - a mercurial repository | Mbed
それに対して、 micro:bit のライブラリでは小文字でアサインされていることを期待しているためです。
#define MICROBIT_DISPLAY_ROW1 p13 #define MICROBIT_DISPLAY_COL1 p4
microbit-dal - a mercurial repository | Mbed
調べてみた限りでは、 micro:bit のライブラリの最終更新は15ヶ月前なのですが、その後の mbed のライブラリの更新で、ピンの定義が小文字から大文字に変更されたようです。
なので今度は mbed の公式ライブラリを使わず、 micro:bit が fork しているライブラリが使われるように、 mbed new
の際に --create-only
オプションをつけて mbed ライブラリを使わずにプロジェクトを作成し、後から micro:bit 用に用意されているライブラリを mbed add
してみました。
[vagrant@localhost vagrant]$ mbed new microbit_sample --create-only [mbed] Creating new program "microbit_sample" (git) [mbed] Couldn't find build tools in your program. Downloading the mbed 2.0 SDK tools... [vagrant@localhost vagrant]$ [vagrant@localhost vagrant]$ cd microbit_sample/ [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed add http://mbed.org/teams/Lancaster-University/code/microbit/ [mbed] Adding library "microbit" from "https://mbed.org/teams/Lancaster-University/code/microbit" at latest revision in the current branch [mbed] Adding library "microbit/microbit-dal" from "https://developer.mbed.org/teams/Lancaster-University/code/microbit-dal" at rev #eb91bba49623 [mbed] Adding library "microbit/microbit-dal/BLE_API" from "https://developer.mbed.org/teams/Lancaster-University/code/BLE_API" at rev #dd2f69fad8c6 [mbed] Adding library "microbit/microbit-dal/mbed-dev-bin" from "https://developer.mbed.org/teams/Lancaster-University/code/mbed-dev-bin" at rev #768173a57492 [mbed] Adding library "microbit/microbit-dal/nRF51822" from "https://developer.mbed.org/teams/Lancaster-University/code/nRF51822" at rev #b84f72a53341 [mbed] Adding library "microbit/microbit-dal/nRF51822/nrf51-sdk" from "https://developer.mbed.org/teams/Lancaster-University/code/nrf51-sdk" at rev #54ddd6f8268c [mbed] Updating reference "microbit" -> "https://mbed.org/teams/Lancaster-University/code/microbit/#4b89e7e3494f" [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed toolchain GCC_ARM [mbed] GCC_ARM now set as default toolchain in program "microbit_sample" [vagrant@localhost microbit_sample]$ mbed target NRF51_MICROBIT [mbed] NRF51_MICROBIT now set as default target in program "microbit_sample" [vagrant@localhost microbit_sample]$ [vagrant@localhost microbit_sample]$ mbed compile Building project microbit_sample (NRF51_MICROBIT, GCC_ARM) Scan: . Scan: mbed Scan: env Compile [ 1.0%]: main.cpp Compile [ 2.0%]: BLE.cpp Compile [ 3.0%]: DiscoveredCharacteristic.cpp Compile [ 4.0%]: GapScanningParams.cpp Compile [ 5.1%]: DFUService.cpp [Error] ble_dfu.h@190,44: 'ble_evt_t' has not been declared [Error] device_manager.h@509,25: variable or field 'dm_ble_evt_handler' declared void [Error] device_manager.h@509,0: 'ble_evt_t' was not declared in this scope [Error] device_manager.h@509,37: 'p_ble_evt' was not declared in this scope [ERROR] In file included from ./microbit/microbit-dal/nRF51822/nrf51-sdk/source/nordic_sdk/components/libraries/bootloader_dfu/dfu_app_handler.h:57:0, from ./microbit/microbit-dal/BLE_API/ble/services/DFUService.h:26, from ./microbit/microbit-dal/BLE_API/source/services/DFUService.cpp:19: ./microbit/microbit-dal/nRF51822/nrf51-sdk/source/nordic_sdk/components/ble/ble_services/ble_dfu/ble_dfu.h:190:44: error: 'ble_evt_t' has not been declared void ble_dfu_on_ble_evt(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt); ^ In file included from ./microbit/microbit-dal/nRF51822/nrf51-sdk/source/nordic_sdk/components/libraries/bootloader_dfu/dfu_app_handler.h:60:0, from ./microbit/microbit-dal/BLE_API/ble/services/DFUService.h:26, from ./microbit/microbit-dal/BLE_API/source/services/DFUService.cpp:19: ./microbit/microbit-dal/nRF51822/nrf51-sdk/source/nordic_sdk/components/ble/device_manager/device_manager.h:509:25: error: variable or field 'dm_ble_evt_handler' declared void void dm_ble_evt_handler(ble_evt_t * p_ble_evt); ^ ./microbit/microbit-dal/nRF51822/nrf51-sdk/source/nordic_sdk/components/ble/device_manager/device_manager.h:509:25: error: 'ble_evt_t' was not declared in this scope ./microbit/microbit-dal/nRF51822/nrf51-sdk/source/nordic_sdk/components/ble/device_manager/device_manager.h:509:37: error: 'p_ble_evt' was not declared in this scope void dm_ble_evt_handler(ble_evt_t * p_ble_evt); ^ [mbed] ERROR: "/usr/local/pyenv/versions/anaconda2-4.4.0/bin/python" returned error code 1. [mbed] ERROR: Command "/usr/local/pyenv/versions/anaconda2-4.4.0/bin/python -u /vagrant/microbit_sample/.temp/tools/make.py -t GCC_ARM -m NRF51_MICROBIT --source . --build ./BUILD/NRF51_MICROBIT/GCC_ARM" in "/vagrant/microbit_sample" ---
ですが ble_evt_t が定義されていないということでコンパイルエラーになってしまいました。解決方法も探してみたのですが、この問題を直接的に解決する方法が見つからなかったので、一旦 mbed CLI を使う方法は諦めます。
yotta 環境構築
上記エラーの解決方法を探していたところ、 Lancaster University の github で環境構築についてのドキュメントが公開されていました。
lancaster-university.github.io
その中で yotta を使ってオフラインビルドする方法が公開されていました。
Offline Development - micro:bit runtime
なのでまずは下記ドキュメントに沿って yotta の環境を構築します。今回は Vagrant を使って ubuntu の VM上に環境を構築しました。
詳細な手順は上記サイトをご覧いただくとして割愛しますが、大まかな内容としては python や pip、 yotta に必要なライブラリ、コンパイラをインストールした上で、 pip で yotta をインストールします。
プロジェクトの作成とビルド
yotta の環境が構築できたらまずはシンプルなプロジェクトを作成してビルドしてみます。最初にプロジェクトのディレクトリを作成して初期化します。
vagrant@vagrant:/vagrant$ mkdir microbit-init-sample vagrant@vagrant:/vagrant$ vagrant@vagrant:/vagrant$ cd microbit-init-sample/ vagrant@vagrant:/vagrant/microbit-init-sample$ vagrant@vagrant:/vagrant/microbit-init-sample$ yotta init Enter the module name: <microbit-init-sample> Enter the initial version: <0.0.0> Is this an executable (instead of a re-usable library module)? <no> yes Short description: microbit sample Author: Akanuma Hiroaki What is the license for this project (Apache-2.0, ISC, MIT etc.)? <Apache-2.0> vagrant@vagrant:/vagrant/microbit-init-sample$
そしてビルドターゲットを micro:bit に設定します。
vagrant@vagrant:/vagrant/microbit-init-sample$ yt target bbc-microbit-classic-gcc info: get versions for bbc-microbit-classic-gcc info: download bbc-microbit-classic-gcc@0.2.3 from the public module registry info: get versions for mbed-gcc info: download mbed-gcc@0.1.3 from the public module registry
次に micro:bit のライブラリをインストールします。
vagrant@vagrant:/vagrant/microbit-init-sample$ yt install lancaster-university/microbit info: microbit, lancaster-university/microbit info: get versions for microbit info: download microbit@v2.0.0-rc9 from GitHub lancaster-university/microbit info: dependency microbit: lancaster-university/microbit written to module.json info: get versions for microbit-dal info: download microbit-dal@v2.0.0-rc9 from GitHub lancaster-university/microbit-dal info: get versions for mbed-classic info: download mbed-classic@microbit_hfclk+mb6 from GitHub lancaster-university/mbed-classic info: get versions for ble info: download ble@v2.5.0+mb3 from GitHub lancaster-university/BLE_API info: get versions for ble-nrf51822 info: download ble-nrf51822@v2.5.0+mb7 from GitHub lancaster-university/nRF51822 info: get versions for nrf51-sdk info: download nrf51-sdk@v2.2.0+mb4 from GitHub lancaster-university/nrf51-sdk
ビルドするプログラムとして下記のように簡単なコードを書いてみました。「Hello, world!!」という文字列をスクロールで一度表示するだけのものです。
ainclude "MicroBit.h" MicroBit uBit; int main() { uBit.init(); uBit.display.scroll("Hello, world!!"); release_fiber(); }
そして下記コマンドでビルドします。
vagrant@vagrant:/vagrant/microbit-init-sample$ yt build
無事にコンパイルが完了すると下記のように .hex ファイルが作成されます。
vagrant@vagrant:/vagrant/microbit-init-sample$ ls -l build/bbc-microbit-classic-gcc/source/microbit-init-sample-combined.hex -rw-r--r-- 1 vagrant vagrant 494768 Nov 1 21:26 build/bbc-microbit-classic-gcc/source/microbit-init-sample-combined.hex
この .hex ファイルを micro:bit にコピーするとプログラムが動作します。
vagrant@vagrant:/vagrant/microbit-init-sample$ cp build/bbc-microbit-classic-gcc/source/microbit-init-sample-combined.hex /media/vagrant/MICROBIT/.
焦電センサーとの組み合わせ
とりあえずオフラインビルドができるようになったので、前回ブロックエディタでやった焦電センサーとの組み合わせを、 mbed で実装してみたいと思います。センサー等の配線は前回と同様で、コード全体は下記の通りです。
#include "MicroBit.h" MicroBit uBit; MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ANALOG); MicroBitPin P1(MICROBIT_ID_IO_P1, MICROBIT_PIN_P1, PIN_CAPABILITY_DIGITAL); MicroBitImage smiley("0,255,0,255, 0\n0,255,0,255,0\n0,0,0,0,0\n255,0,0,0,255\n0,255,255,255,0\n"); MicroBitImage closing_eyes("0,0,0,0, 0\n255,255,0,255,255\n0,0,0,0,0\n0,255,255,255,0\n0,0,0,0,0\n"); int pyro_value = 0; int main() { uBit.init(); uBit.serial.send("Starting micro:bit pyroelectric.\r\n"); uBit.display.scroll("HELLO!"); while(true) { pyro_value = P0.getAnalogValue(); uBit.serial.printf("%d\r\n", pyro_value); if (pyro_value >= 500) { P1.setDigitalValue(1); uBit.display.print(smiley); } else { P1.setDigitalValue(0); uBit.display.print(closing_eyes); } uBit.sleep(1000); } }
まず使用するピンを初期化しています。 P0 は焦電センサーからアナログ値を読み取るため PIN_CAPABILITY_ANALOG を指定し、 P1 はブレッドボード上の LED の点灯/消灯のデジタル出力なので PIN_CAPABILITY_DIGITAL を指定しています。
MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ANALOG); MicroBitPin P1(MICROBIT_ID_IO_P1, MICROBIT_PIN_P1, PIN_CAPABILITY_DIGITAL);
焦電センサーでの検知時/非検知時に表示する顔のイメージもあらかじめ定義しておきます。
MicroBitImage smiley("0,255,0,255, 0\n0,255,0,255,0\n0,0,0,0,0\n255,0,0,0,255\n0,255,255,255,0\n"); MicroBitImage closing_eyes("0,0,0,0, 0\n255,255,0,255,255\n0,0,0,0,0\n0,255,255,255,0\n0,0,0,0,0\n");
デバッグ用にシリアル接続も使用しています。 uBit.serial.send()
もしくは uBit.serial.printf()
で文字列を出力しておくと、 screen コマンドで micro:bit に接続して出力を確認することができます。
uBit.serial.send("Starting micro:bit pyroelectric.\r\n");
あとは無限ループの中で焦電センサー(P0)からアナログ値を読み取り、その値によってブレッドボード上の LED と micro:bit 上の LED の表示を切り替えます。
while(true) { pyro_value = P0.getAnalogValue(); uBit.serial.printf("%d\r\n", pyro_value); if (pyro_value >= 500) { P1.setDigitalValue(1); uBit.display.print(smiley); } else { P1.setDigitalValue(0); uBit.display.print(closing_eyes); } uBit.sleep(1000); }
これをビルドして .hex ファイルを micro:bit にコピーすると、焦電センサーの検知状態によって micro:bit の LED の表示が切り替わります。
まとめ
micro:bit は元々の目的が教育用なので、 CLI でがっつり開発することはあまり想定されていないかもしれませんが、色々な機能を持っているので、 mbed から色々試してみるのも面白そうです。とりあえず今回の環境構築に使った Vagrantfile などを下記リポジトリに公開しましたので、参考にしていただければと思います。
ハロウィンも終わって次はクリスマスですねー。