mbedオフライン開発環境の構築

岡野さんのページを参考にmbedのオフライン開発環境を構築しました。

準備

パッケージ管理ソフトHomebrewとXcodeをインストールします。

App Storeを使ってXcodeをインストールした後、最新に更新してください。 mbed cliではXcode Command line Toolsも必要になりますが、mbed cliがインストールを促してくれます。

Homebrewのインストール

以下のコマンドでHomebewがインストールされます。

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

brewコマンドでpythonとnpmをインストールします。

$ brew install npm
$ brew install python

pythonのインストールで警告がでるので、以下のコマンドを実行します。

$ brew link --overwrite python

次にgit、Mercurial(hg)とGCCをインストールします。

$ brew tap PX4/homebrew-px4
$ brew update
$ brew install git hg gcc-arm-none-eabi

mbedオフライン開発環境mbed cliのインストール

mbed cliはpipコマンドを使ってインストールします。これでmbedオフライン開発環境が整いました。

$ pip install mbed-cli

動作確認

動作確認のために、Lチカのサンプル(blink)を作成します。

$ mbed new blink --mbedlib
[mbed] Creating new program "blink" (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...
[mbed] Auto-installing missing Python modules...

main.cppは、以下の様にしました。

In [4]:
%%writefile blink/main.cpp
#include "mbed.h"
 
DigitalOut led1(LED1);
 
int main()
{
    while (1) {
        led1 = !led1;
        wait_ms(500);
    }
}
Writing blink/main.cpp

blinkには、以下のディレクトリとファイルができています。 mbedディレクトリには、必要なライブラリやインクルードファイルがダウンロードされるので、Githubには含めていません。

In [3]:
!ls blink
main.cpp  mbed	mbed.bld  mbed_settings.py  mbed_settings.pyc

mbed LPC1768で動かす

手元の初期のmbed LPC1768をMacに接続してみます。

mbed cliが正しくmbed LPC1768を認識するかdetectコマンドで確認します。

以下の様に入力すると、LPC1768として認識されていることが分かります。

$ mbed detect

[mbed] Detected LPC1768, port /dev/tty.usbmodem1412, mounted /Volumes/MBED
[mbed] Supported toolchains for LPC1768
+---------+-----------+-----------+-----------+-----------+-----------+
| Target  | mbed OS 2 | mbed OS 5 |    ARM    |  GCC_ARM  |    IAR    |
+---------+-----------+-----------+-----------+-----------+-----------+
| LPC1768 | Supported | Supported | Supported | Supported | Supported |
+---------+-----------+-----------+-----------+-----------+-----------+
Supported targets: 1
Supported toolchains: 3

それでは、toolchainをGCC_ARM、ターゲットをLPC1768にセットします。

$ mbed toolchain GCC_ARM
[mbed] GCC_ARM now set as default toolchain in program "blink"
$ mbed target LPC1768
[mbed] LPC1768 now set as default target in program "blink"

mbed OS5では不要ですが、mbed OS2ではライブラリのアップデート(新規の場合ダウンロード)が必要です。

mbed 2.0 9bcdf88f62b0のバグでLPC1768のdefault targetが見つかりません。その場合には、以下のコメントに従ってください。

$ mbed update

準備が整ったのでコンパイルを実行します。

$ mbed compile
Building project blink (LPC1768, GCC_ARM)
Scan: .
Scan: mbed
Scan: env
Compile: main.cpp
Link: blink
Elf2Bin: blink
+-----------+-------+-------+------+
| Module    | .text | .data | .bss |
+-----------+-------+-------+------+
| Subtotals | 27529 |  2496 |  632 |
+-----------+-------+-------+------+
Allocated Heap: 2048 bytes
Allocated Stack: 3072 bytes
Total Static RAM memory (data + bss): 3128 bytes
Total RAM memory (data + bss + heap + stack): 8248 bytes
Total Flash memory (text + data + misc): 30025 bytes
Image: ./BUILD/LPC1768/GCC_ARM/blink.bin

正常にビルドが完了したので、Imageファイル(blink.bin)をmbedに書き込みmbedのリセットボタンを押します。LEDが1秒間隔で点滅したら成功です。

$ cp ./BUILD/LPC1768/GCC_ARM/blink.bin  /Volumes/MBED/

mbedのデバッグ

オフラインの特徴であるデバッグ機能について、順を追って説明します。

mbedのファームウェアの更新

私の使っていた初期のものでpyocdを使うには、ファームウェアの更新が必要でした。

更新が必要かどうかは、PCにmbedを差してマウントされたディスクにあるMBED.HTMをテキストエディタで開いて確認します。

<!-- mbed Microcontroller Website and Authentication Shortcut -->
<html>
<head>
<meta http-equiv="refresh" content="0; url=http://mbed.org/start?auth=101000000000000000000002F7F0369Ab9b009f73483a04d0f3d5cd7552c12f1&loader=11972&firmware=141212&configuration=4" />
<title>mbed Website Shortcut</title>
</head>
<body></body>
</html>

firmware=xxxxxの番号が1421212よりも小さい場合には、mbedのファームウェアの更新が必要です。

以下のサイトから最新ファームウェア(mbedmicrocontroller_21164.if)をダウンロードし、mbedに書き込んでmbedの電源を入れ直してください。

正常に更新されたら、MBED.HTMのfirmware=141212になっています。

デバッグオプションを付けてコンパイル

mbedのデバッグには、compile時にデバッグオプションを付けます。

mbed OS2の場合には、-o debug-infoを付けます。既にBUILDがある場合には、削除してからmbed compileを実行してください。

$ mbed compile -o debug-info

mbed 5.2以降の場合には、add --profile=debugを付けます

pyocdの起動

mbedのデバッグは、pyocdというPythonベースのOn-Chip Debuggerを使って行います。

ターミナルを開いて、以下のコマンドを入力してください。 pyocd-gdbserverが起動し、デバッグの準備をします。

$ pyocd-gdbserver
INFO:root:DAP SWD MODE initialised
INFO:root:ROM table #0 @ 0xe00ff000 cidr=b105100d pidr=0
INFO:root:[0]<e000e000: cidr=b105e00d, pidr=4002bb000, class=14>
WARNING:root:Invalid coresight component, cidr=0x0
INFO:root:[1]<e0001000: cidr=0, pidr=0, component invalid>
INFO:root:[2]<e0002000:FPB cidr=b105e00d, pidr=4002bb003, class=14>
WARNING:root:Invalid coresight component, cidr=0x0
INFO:root:[3]<e0000000: cidr=0, pidr=0, component invalid>
WARNING:root:Invalid coresight component, cidr=0x0
INFO:root:[4]<e0040000: cidr=0, pidr=0, component invalid>
INFO:root:[5]<e0041000: cidr=b105900d, pidr=4002bb924, class=9, devtype=13, devid=0>
INFO:root:CPU core is Cortex-M3
INFO:root:6 hardware breakpoints, 4 literal comparators
INFO:root:4 hardware watchpoints
INFO:root:Telnet: server started on port 4444
INFO:root:GDB server started at port:3333

OpenOCDと同様pyocdも以下の2つのポートを開いてデバッグコマンドを処理します。

  • pyocdを制御するポート: 4444
  • GDBサーバのポート: 3333

GDBの起動

次にARM用のDGB(arm-none-eabi-gdb)を起動します。

別のターミナルを開いて、mbedのプロジェクトのあるディレクトリに移動して、以下のコマンドを入力してください。

$ arm-none-eabi-gdb BUILD/LPC1768/GCC_ARM/blink.elf
GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160923-cvs
Copyright (C) 2015 Free Software Foundation, Inc.
途中省略
Reading symbols from BUILD/LPC1768/GCC_ARM/blink.elf...(no debugging symbols found)...done.

GDBが起動すると(gdb)のプロンプトが表示されますので、ここで以下のコマンドを入力します。

  • target remote :3333 : デバッグターゲットをリモートのgdb-serverとし、localhostの3333ポートに接続
  • load : プログラムをmbedに書込みます(loadします)
  • break main : main関数にブレークポイントをセット
  • c : mbedをDGBの元で実行(continueの略)
(gdb) target remote :3333
Remote debugging using :3333
0x0000082c in mbed_error_printf (format=0x0 <osRegisterForOsEvents>)
    at ../mbed-os/platform/mbed_board.c:72
72         mbed_error_vfprintf(format, arg);
(gdb) load
Loading section .text, size 0x6c3c lma 0x0
Loading section .ARM.exidx, size 0x8 lma 0x6c3c
Loading section .data, size 0x9c0 lma 0x6c44
Start address 0x4c0, load size 30212
Transfer rate: 8 KB/sec, 1777 bytes/write.
(gdb) br main
Breakpoint 1 at 0x6ca: file ./main.cpp, line 8.
(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at ./main.cpp:8
8            led1 = !led1;
(gdb)

以下のGDBコマンドを使ってblinkをデバッグします。

  • n(next): ステップオーバ
  • s(step): ステップイン
  • p(print): プリント
  • q(quit): GDBの終了

nを入力すると、次の行に進みます。

(gdb) n
9            wait_ms(500);

もう一度cを入力して、8行目で止め、今度はsを入力してみましょう。 DigitalOUt::operator intのreturn read();で止まりました。 led1で値を参照すると、内部ではled1.read()が呼び出されます。

(gdb) c
Continuing.

Breakpoint 1, main () at ./main.cpp:8
8            led1 = !led1;
(gdb) s
mbed::DigitalOut::operator int (this=0x10000bac <led1>)
    at ./mbed/25aea2a3f4e3/DigitalOut.h:117
117            return read();

upコマンドでmainの呼び出し元に戻り、プリントコマンドで値を見てみましょう。

(gdb) up
#1  0x000006d0 in main () at ./main.cpp:8
8            led1 = !led1;
(gdb) p led1.read()
$1 = 1

このようにデバッガ(GDB)を使って処理の流れを確認したり、値をみることができます。

デバッガを終了するには、qを入力してください。 本当に終了するか確認してきますので、yを入力するとGDBが終了し、合わせてpyocd-gdbserverも終了します。

(gdb) q
A debugging session is active.

    Inferior 1 [Remote target] will be detached.

Quit anyway? (y or n) y
Detaching from program: /Users/take/proj/jupyter/MySageMath/notebook/letsMbed/blink/BUILD/LPC1768/GCC_ARM/blink.elf, Remote target
Ending remote debugging.

Emacsのgdbモードを使う

コマンドベースのGDBでは、ソースのどの部分を実行しているのかが、いまいち掴みづらいので、Emacsのgdbモードを使ってみましょう。

通常だとEclipseを使ったデバッグに進むのですが、テキストベースのEmacsの方でも十分デバッグができます。

先ほどと同様にpyocd-gdbserverを起動した後、 別のターミナルを開いて、mbedのプロジェクトのあるディレクトリに移動して、以下のコマンドを入力してください。

$ emacs
Welcome to GNU Emacs, a part of the GNU operating system.
Emacsの使い方の説明画面が表示されます。

ここで、ESC xに続いてgdbを入力すると、以下の様に表示されますので、arm-none-eabi-gdb --annotate=1 BUILD/LPC1768/GCC_ARM/blink.elf と入力してください。

Run gdb (like this): gdb --annotate=1

gdbが起動しますので、先ほどと同様に、target remote :3333, load, br main, cを入力すると画面が上下に分割し、上部にgdbのコマンドが表示され、 現在停止している箇所のソースが表示されます。

gdbでデバッグを開始した直後の画面

ここで先ほどと同様にnコマンドを入力すると下部の画面の=>がwait_ms(500);に移動します。

続いて、p leと入力した後にTABを押すと補完され、led1が表示されます。続いて.reの後にTABを押すと.readがでるので、( )を追加して改行するとled1の値を確認することができます。

n, s, cを入力するとgdb画面でスクロールすので、以下の様に実行するとgdb画面には表示されずにnext, stepを実行できます。

  • next: Ctrl-a Ctrl-x Ctrl-n
  • step: Ctrl-a Ctrl-x Ctrl-s

詳しくはGDBモードのCheat Sheetを参照してください。

補完機能の他にCtrl-p, Ctrl-nで前のコマンドや次のコマンドに移動したり、 Ctrl-rで文字列検索で過去のコマンドを検索できるので、キー入力が大幅に省略できます。

Emacsを終了する前に、GDBにqを入力してデバッグを終了しましょう。 この後、Ctrl-x, Ctrl-cでEmacsを終了します。

In [ ]: