micro:bitで本格的な組込みソフトウェア開発
micro:bitは、様々な方法で、組込みソフトウェア開発が可能です。
本記事では、リアルタイムオペレーティングシステムの実装であるApache Mynewt を使って、本格的な組込みソフトウェア開発環境を構築し、VSCodeでサンプルプログラムをデバッグ実行します。
Windows 10 (64bit版) 上での開発環境構築
次のドキュメントを参考にして、Windows 10 (64bit版) 上に開発環境を構築します。
Installing Newt on Windows
https://mynewt.apache.org/latest/newt/install/newt_windows.html
Installing the Cross Tools for ARM
https://mynewt.apache.org/latest/get_started/native_install/cross_tools.html
本記事では、具体的なダウンロード元やインストールフォルダを示していますので、将来、バージョンアップなどにより、動作しなくなる可能性があります(2020/07/04現在)。
MSYS2/MinGW のインストール
https://www.msys2.org/ からMSYS2のインストーラーをダウンロードし、インストールします。
→ msys2-x86_64-20200629.exe
MSYS2を最新化する為、スタートメニューからMSYS2 MSYS
を起動し、次のコマンドを実行します。
pacman -Syuu
さらに、次のコマンドを実行し、tar
ツールをインストールします。
pacman -Su tar
Windows 10 のシステム環境変数で、変数名MSYS2_PATH_TYPE
の変数値inherit
を追加します。
さらに、Windows 10 のシステム環境変数の変数名Path
の先頭に変数値C:\msys64\usr\bin
を追加します。
※ C:\msys64\
はMSYS2がデフォルトでインストールされるフォルダーです。
Mynewtのドキュメントやチュートリアルで指定されたコマンドを実行するには、MinGWターミナルを起動する必要がありますが、その際、スタートメニューからMSYS2 Mingw 64-bit
を起動します。
Git のインストール
https://gitforwindows.org/ からgitのインストーラーをダウンロードし、インストールします。
→ Git-2.27.0-64-bit.exe
newt のインストール(バイナリ版 1.8.0)
バイナリ版のnewtをインストールします。
まず、MinGWターミナルを起動し、次のコマンドで、バイナリ版のnewtをダウンロードし、展開後、/usr/bin
へ移動します。
wget -P /tmp https://ftp.riken.jp/net/apache/mynewt/apache-mynewt-1.8.0/apache-mynewt-newt-bin-windows-1.8.0.tgz
tar -xzf /tmp/apache-mynewt-newt-bin-windows-1.8.0.tgz -C /tmp
mv /tmp/apache-mynewt-newt-bin-windows-1.8.0/newt.exe /usr/bin
次のコマンドで、newtのバージョンを確認できます。
newt version
ARM Toolchain のインストール
gcc-arm-none-eabi-7-2018-q2-update-win32.exeをダウンロードし、インストールします。
インストールの最後で、Add path to environment variable
をチェックしてから、「完了」ボタンを押下してください。
MinGWターミナルを起動し、次のコマンドで、それぞれのツールのインストール先を確認することができます。
which arm-none-eabi-gcc
which arm-none-eabi-gdb
※ インストールするバージョンに関する注意事項
gcc-arm-none-eabi-7-2018-q2-update-win32.exeをダウンロードし、インストールしてください。
GNU Arm Embedded Toolchain: 8-2018-q4-major December 20, 2018
(gcc-arm-none-eabi-8-2018-q4-major-win32.exe) では開発中に次のエラーでビルドに失敗します。
When extracting code from .elf, objcopy reports "64-bit address 0x4b4fa300000000 out of range for Intel Hex file".
不具合情報:https://bugs.launchpad.net/gcc-arm-embedded/+bug/1810274
openocd のインストール
openocd-0.10.0.zipをダウンロードします。
C:\openocd-0.10.0\
フォルダへ展開します。
C:\openocd-0.10.0\bin
をシステム環境変数のPath
の先頭に追加します。
SEGGER J-Link デバッガ のインストール
「J-Link Software and Documentation pack for Windows」をダウンロードし、インストールします。
→ JLink_Windows_V680d.exe
micro:bitのファームウェア最新化(DAPLink)
次の手順で、micro:bitのフォームウェアを最新化します。
https://microbit.org/get-started/user-guide/firmware/
- 0253_kl26z_microbit_0x8000.hexファイルをダウンロードします。
- micro:bit本体のリセットスイッチを押しながら、USB通信ケーブルで、パソコンに接続します。
- micro:bitのストレージを
MAINTENANCE
ドライブとしてパソコンが認識していることを確認します。 - ダウンロードしたHEXファイルを
MAINTENANCE
ドライブへコピーします。
サンプルプログラム
開発環境が構築できたかどうかを確認する為、Lチカのサンプルプログラムを作成し、micro:bit本体で実行してみます。
https://mynewt.apache.org/latest/tutorials/blinky/nRF52.html
プロジェクトの作成とリポジトリの取得
MinGWターミナルを起動し、次の一連のコマンドを実行し、プロジェクトを作成(newt new myproj
)とリポジトリの取得(newt upgrade
)を行います。
mkdir ~/dev
cd ~/dev
newt new myproj
cd myproj
newt upgrade
ターゲットの作成
次のコマンドで、ブートプログラム(ubit_boot
)とLチカ本体(ubit_blinky
)のターゲットを作成し、設定します。
newt target create ubit_boot
newt target set ubit_boot app=@mcuboot/boot/mynewt
newt target set ubit_boot bsp=@apache-mynewt-core/hw/bsp/bbc_microbit
newt target set ubit_boot build_profile=optimized
newt target create ubit_blinky
newt target set ubit_blinky app=apps/blinky
newt target set ubit_blinky bsp=@apache-mynewt-core/hw/bsp/bbc_microbit
newt target set ubit_blinky build_profile=debug
newt target show
サンプルソースコードの差し替え(micro:bit LED)
Lチカ本体のソースコードは、~/dev/myproj/apps/blinky/src/main.c
です。
Windows10からは、C:\msys64\home\<アカウント名>\dev\myproj\apps\blinky\src\main.c
としてアクセスできます(<アカウント名>
はログオンユーザーアカウント)。
micro:bitのLEDマトリックスは、少し特殊な回路となっていますので、LEDマトリックスを点滅させるため、メモ帳などのテキストディタでmain.c
を開き、次のサンプルソースコードで上書き保存します。
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
# include <assert.h>
# include <string.h>
# include "sysinit/sysinit.h"
# include "os/os.h"
# include "bsp/bsp.h"
# include "hal/hal_gpio.h"
// LED pin Column
# define PIN_LED_COL1 4
# define PIN_LED_COL2 5
# define PIN_LED_COL3 6
# define PIN_LED_COL4 7
# define PIN_LED_COL5 8
# define PIN_LED_COL6 9
# define PIN_LED_COL7 10
# define PIN_LED_COL8 11
# define PIN_LED_COL9 12
// LED pin Row for LED toggling
# define PIN_LED_ROW_0 13
# define PIN_LED_ROW_1 14
# define PIN_LED_ROW_2 15
static volatile int g_task1_loops;
/**
* main
*
* The main task for the project. This function initializes packages,
* and then blinks the BSP LED in a loop.
*
* @return int NOTE: this function should never return!
*/
int
main(int argc, char **argv)
{
int rc;
sysinit();
// because the LEDs are multiplexed, we must ground the opposite side of the LED
hal_gpio_init_out(PIN_LED_COL1, 0);
hal_gpio_init_out(PIN_LED_COL2, 0);
hal_gpio_init_out(PIN_LED_COL3, 0);
hal_gpio_init_out(PIN_LED_COL4, 0);
hal_gpio_init_out(PIN_LED_COL5, 0);
hal_gpio_init_out(PIN_LED_COL6, 0);
hal_gpio_init_out(PIN_LED_COL7, 0);
hal_gpio_init_out(PIN_LED_COL8, 0);
hal_gpio_init_out(PIN_LED_COL9, 0);
// set LED pin to output mode
hal_gpio_init_out(PIN_LED_ROW_0, 1);
hal_gpio_init_out(PIN_LED_ROW_1, 1);
hal_gpio_init_out(PIN_LED_ROW_2, 1);
while (1) {
++g_task1_loops;
/* Wait one second */
os_time_delay(OS_TICKS_PER_SEC);
/* Toggle the LED */
hal_gpio_toggle(PIN_LED_ROW_0);
hal_gpio_toggle(PIN_LED_ROW_1);
hal_gpio_toggle(PIN_LED_ROW_2);
}
assert(0);
return rc;
}
ターゲットのビルドとアプリケーションイメージの生成
次のコマンドで、作成した2つのターゲットをビルドし、アプリケーションイメージを生成します。
newt build ubit_boot
newt build ubit_blinky
newt create-image ubit_blinky 1.0.0
micro:bit本体へのロード
次のコマンドで、micro:bit本体へ、実行に必要なイメージをロードします。
newt load ubit_boot
newt load ubit_blinky
VSCodeを用いた開発環境の構築
次のドキュメントを参考にして、Visual Studio Code (VSCode)を用いたに開発環境を構築します。
https://mynewt.apache.org/latest/misc/ide.html
VSCodeのインストール
https://code.visualstudio.com/Download のページから、Windows版のVSCodeをダウンロードし、インストールします。
VSCode拡張機能のインストール
VSCodeを起動し、次の2つの拡張機能をインストールします。
- C/C++ 拡張機能(Microsoft)
- Native Debug 拡張機能(webfreak)
C/C++ 拡張機能 のインストール
-
Ctrl-P
を押下し、VSCodeの検索ボックスを開きます。 - 検索ボックスに
ext install cpptools
と入力し、Enterキーを押下します。 - リストのトップに拡張機能の
C/C++
が表示されますので、インストール
ボタンでインストールします。
Native Debugger 拡張機能 のインストール
-
Ctrl-P
を押下し、VSCodeの検索ボックスを開きます。 - 検索ボックスに
ext install webfreak.debug
と入力し、Enterキーを押下します。 - リストのトップに拡張機能の
Native Debug
が表示されますので、インストール
ボタンでインストールします。
VSCode上でのワークスペースとタスクの関連付け
VSCodeには、次のような概念があります。
- ワークスペース - 開いているフォルダがワークスペースです。
- タスク - タスクを使用すると、プロジェクトのビルドやデバッグに使用される外部ツールとの操作をVisual Studio Codeに統合できます。
ワークスペースの関連付け
Lチカのサンプルプログラム(プロジェクト)をVSCodeのワークスペースとして関連付けます。
エクスプローラーを開き、~/dev/myproj/
であるC:\msys64\home\<アカウント名>\dev\myproj
フォルダを開きます。ファイル名やフォルダ名以外の空白の部分で、右クリックし、`Code で開く'で、VSCodeで開きます。
ワークスペース内でのタスクの定義
myproj
のワークスペースを開いた状態で、開発に必要なタスクを定義します。
tasks.jsonの追加
次の手順で、tasks.json
ファイルを追加します。
-
Ctrl-Shift-P
キーを押下し、表示された検索ボックスで、tasks
と入力すると候補が絞り込まれますので、タスク: タスクの構成 / Tasks:Configure Task
を選択します。 -
テンプレートからtasks.jsonを作成
をクリックし、リスト末尾のOthers
をクリックします。 -
tasks.json
ファイルが追加され、エディタに表示されます。
task.jsonの定義
tasks.json
の内容を次の定義内容で上書き保存します。
{
"version": "0.1.0",
"command": "newt",
"echoCommand": true,
"isShellCommand": true,
"tasks":[
{
"taskName": "build_ubit_boot",
"args": ["build", "ubit_boot"],
"suppressTaskName": true
},
{
"taskName": "build_ubit_blinky",
"args": ["build", "ubit_blinky"],
"isBuildCommand": true,
"suppressTaskName": true
},
{
"taskName": "create_ubit_blinky",
"args": ["create-image", "ubit_blinky", "1.0.0"],
"suppressTaskName":true
},
{
"taskName": "load_ubit_boot",
"args": ["load", "ubit_boot"],
"suppressTaskName":true
},
{
"taskName": "load_ubit_blinky",
"args": ["load", "ubit_blinky"],
"suppressTaskName":true
},
{
"taskName": "debug_ubit_blinky",
"args": ["debug", "ubit_blinky", "-n"],
"suppressTaskName": true
},
]
}
タスクの実行方法
例えば、build_ubit_blinky
タスクを実行するには、次の手順で操作します(他のタスクも同様)。
-
Ctrl-Shift-P
キーを押下し、検索ボックスを開きます。 -
tasks
と入力すると、候補が絞り込まれますので、タスク: タスクの実行 / Tasks: Run Task
をクリックします。 -
build_ubit_blinky
が実行するタスクの選択候補に表示されますので、それをクリックします。 - 下段のペインで、`newt build ubit_blinky'が実行されます。
また、タスクに定義されていなくてもnewt
コマンドを実行することができます。日本語キーボードの場合、Ctrl-@
(バッククォート)キーを押下すると下段のペインにターミナルが表示・非表示されますので、そこで直接、newt version
等のコマンドを入力し、実行することができます。
尚、build_ubit_blinky
タスクに関しては、その定義でisBuildCommand
がtrue
になっていますので、Ctrl-Shift-B
キーで、実行できます。
アプリケーションのデバッグ
micro:bit本体とUSB通信ケーブルで接続して、VSCodeからアプリケーションをデバッグすることができます。まずは、デバッグ環境の構成を定義します。
デバッグ環境構成の定義(GDB)
VScodeのメニューから[実行(Debug)]-[構成を開く(Open Configuration)]を選択し、環境の選択の中からGDB
を選択します。launch.json
ファイルが追加され、テキストエディタに表示されますので、次の内容で上書き保存します。
{
"version": "0.2.0",
"configurations": [
{
"name": "gdb_ubit_blinky",
"type": "gdb",
"request": "attach",
"executable": "${workspaceRoot}\\bin\\targets\\ubit_blinky\\app\\apps\\blinky\\blinky.elf",
"target": ":3333",
"cwd": "${workspaceRoot}",
"gdbpath": "C:\\Program Files (x86)\\GNU Tools ARM Embedded\\7 2018-q2-update\\bin\\arm-none-eabi-gdb.exe",
"remote": true
}
]
}
サンプルプログラムのデバッグ
サンプルプログラムのLチカをステップ実行でデバッグしてみます。
ブレークポイントの追加
main.c
を開き、行番号の左で、ブレークポイントを追加・削除できますので、例えば、図の行77に、ブレークポイントを追加します(赤い点)。
GDBサーバーの開始
次の手順で、GDB サーバー
を開始します。
-
Ctrl-Shift-P
キーを押下し、検索ボックスを開きます。 -
tasks
と入力すると、候補が絞り込まれますので、タスク: タスクの実行 / Tasks: Run Task
をクリックします。 -
debug_ubit_blinky
が実行するタスクの選択候補に表示されますので、それをクリックします。 - 下段のペインで、`newt debug ubit_blinky -n'が実行され、micro:bit本体裏の通信LED(オレンジ色)が激しく点滅します。
デバッグ実行の開始
次の手順で、デバッグ実行を開始します。
-
Ctrl-Shift-D
キーを押下し、左縦のアクティビティバーから「実行(Debug)」アイコンを選択し、左側のペインを切り替えます。 - 「実行(Debug)」ドロップダウンリストで、
gdb_ubit_blinky
を選択します。 - 「実行(Debug)」横の緑色の「デバッグの開始」ボタンをクリックするとGDBセッションが開始されます。
- すぐさま、デバッグが開始され、ブレークポイントで、一時停止しますので、変数
g_task1_loops
にカーソルを合わせると、現在値が表示されます。 - 「続行(F5)」で、処理が続行され、次のブレークポイントで一時停止します。
まとめ
micro:bitで本格的な組込みソフトウェア開発ができることを確認しました。
- リアルタイムオペレーティングシステムの実装であるApache Mynewt を使いました。
- C/C++による本格的な組込みソフトウェア開発環境を構築しました。
- サンプルプログラムのLチカをmicro:bit本体で動作させました。
- VSCodeでサンプルプログラムをデバッグ実行し、ステップ実行できることを確認しました。