Evaluating Nordic nRF52 with GCC and GNU MCU Eclipse.
今日は趣向を変えて、久々に Nordic 社の nRF52 を触ってみます。同社のマイコンは、Bluetooth LE(以下、BLE)など低消費電力の通信アプリケーションに特化していて、コイン電池などでも長時間動作させられるのが特徴です。
開発ツールですが、今回は Keil uVision (MDK-ARM) は使用せず、GNU toolchain と Eclipse ベースでやってみたいと思います。理由ですが、Keil 社のツールは高価であること。無償版もありますが、メモリサイズ制限が厳しいです。おまけに(IAR 社の Embedded Workbench もそうですが)、Windows でしか開発できないというのは辛いと思います。製品版の設計でやむを得ず Keil 社や IAR 社のサポートが必要になれば別ですが、まずは GNU toolchain で頑張ってみようと思います。
何をインストールしたら良いのか?
GNU toolchain による Nordic 社の公式資料(公式というよりブログですが)は、こちらにあります。
同社にとっても GNU toolchain(GCC) は無視できない存在のようで、かなり詳しく説明されているのは良いのですが、いかんせん内容が古くなっています。なにしろ、4年以上前の資料なのです。今回は同ブログを参考にしつつ、最新の状況を踏まえて評価してみたいと思います。
目標は以下の通りです。
- Linux あるいは Mac OS 上で評価できるようにする(もちろん、Windows でも大丈夫です)
- LED 点滅から始め、BLE peripheral のサンプルコードも動かせるようにする
- Eclipse 上でビルド、フラッシュの書き込み、デバッグができるようにする
必要なツールは以下の通りです。カッコの中に、今回使用したバージョンを示します。
- Eclipse(2019-09)
- CDT(CDT 9.9.0 for Eclipse 2019-09)
- GNU MCU Eclipse plug-in(4.7.1)
- xpack/xpm-js(0.5.0)
- xPack GNU Arm Embedded GCC(v9.2.1-1.1)
- nRF5 SDK(nRF5_SDK_15.3.0_59ac345)
- JLink(V6.40)
- nRF Command Line Tools(9.8.1)
このうち、意図的に最新版を避けているものについて説明します。もし、VMware や VirtualBox などを使い、Linux OS 上で開発できるのではあれば、このような苦労はないと思いますので、Linux での開発をお勧めします。その場合の Linux は、個人的には Ubuntu の新しいものが良いかと思います。
nRF5 SDK
最新版は 16.0.0 のようですが、メジャーバージョンが上がって最初の版なので避けました。
JLink
私の Mac OS X(El Capitan)では、最新版の V6.60a は segmentation fault で落ちるので諦めました。
nRF Command Line Tools
これも同様に、10.5.0 は segmantation fault を起こすので、わざと古いバージョンを使っています。
それでは順にインストールしよう
このように開発ツールのインストールはなかなか大変です。やはり、VMware や VirtualBox などを使い、開発ツールはパッケージ化しておき、ホスト OS(Windows や Mac OS)などのバージョンアップなどに引きずられないようにしておくと、後が楽です。例えば、設計プロジェクトを 1年後に再開しようとして、あのツールが動かない、このツールのダウンロード先が見つからない、などという面倒を避けることができます。
GNU MCU Eclipse 関連
まずは、GNU MCU Eclipse からインストールしましょう。これは、GUI ベースでソフトの開発やデバッグをするためのものです。
「私はコマンドラインで make するし、エディタは vi や Emacs なので GUI は要らない」という方は、ここをスキップして、別途 GNU toolchain をインストールしても良いでしょう。
インストール手順は、こちらが詳しいです。そこの順序に従い、xpm、GNU toolchain(xPack GNU Arm Embedded GCC)、(Windows Build Tools)、SEGGER J-Link、Eclipse & CDT、GNU MCU Eclipse plug-in をインストールします。(今回は OpenOCD、QEMU 等は使いません。)
Nordic 社のツール関連
続いて、Nordic 社のツールをインストールします。
最初に、SDK です。SDK はこちらからダウンロードできます。前述の通り、今回は 15.3.0 をインストールしました。SDK には、ライブラリや共通 Makefile に加えて、各種のサンプルプログラムが含まれ、展開すると 640Mバイトほどの大きさがあります。Nordic 社の説明では、この下でサンプルプログラムをビルドすることになりますが、今後自分のサンプルプログラムを書く際に、上記 640MB のツリーをあちこちにコピーするのは大変です。
お勧めとしては、どこか共通の場所に SDK を展開しておき、サンプルプログラム(プロジェクト)は自分の作業ディレクトリにコピーし、そちらで実験するのが良いでしょう。そうすれば、SDK 全体を Git などでバージョン管理するような煩雑さを避けられます。以下、SDK を展開したディレクトリを SDK_ROOT と呼びます。SDK_ROOT の下には、components や examples というディレクトリが来ることになります。
具体的には、Mac であれば SDK_ROOT は $(HOME)/nRF5_SDK_15.3.0_59ac345 というような場所になるでしょう。($(HOME) は、ホームディレクトリです。) Windows などを使っていて、よく分からない方は、C:\nRF5_SDK_15.3.0_59ac345 などに展開し、Makefile では SDK_ROOT := C:/nRF5_SDK_15.3.0_59ac345 というような形になるかと思います。(やっぱり Linux が楽だと思いますけどネ。)
次に nRF Command Line Tools をここからダウンロードします。最新版では自動的に実行パスを設定してくれるようですが、そうでない場合は適宜実行パス(環境変数 PATH)を設定し、コマンドラインから nrfjprog が実行できるようにしてください。Mac OS や Linux ですと、(太字の部分がコマンド入力。以下同様)
bash$ nrfjprog -v nrfjprog version: 9.8.1 JLinkARM.dll version: 6.40
という感じで実行できると思います。
まずはコマンドラインで blinky をビルドしてみよう
上記までインストールができたら、ようやくサンプルプログラムをビルドできるようになります。まずは、BLE の通信を伴わない、簡単な LED チカチカからやってみます。
上記 SDK_ROOT から、サンプルプログラム(プロジェクト)blinky だけを手元にコピーします。例えば作業ディレクトリが、my_nordic だとしましょう。以下、bash などコマンドプロンプトに対する操作です。コピペがしやすいように、プロンプトは省略します。シェルは bash とします。
export SDK_ROOT=$HOME/nRF5_SDK_15.3.0_59ac345 # 先の説明通りです cd どこかの/my_nordic cp -Rp $SDK_ROOT/examples/peripheral/blinky .
次に Makefile を修正します。最初に、blinky の下の Makefile からです。ここでは vi エディタを仮定してますが、もちろんお好きなエディタで結構です。(なお、pca10040 というのはボードの名称で、nRF52-DK の製品名です。blank というのは、次回説明する SoftDevice を「使わない設定」の意味です。armgcc は、GNU toolchain を使ってビルドする、という意味です。)
cd blinky/pca10040/blank/armgcc vi Makefile
上から 5行目辺りに SDK_ROOT := … という行がありますので、それを次のように修正します。
SDK_ROOT := $(HOME)/nRF5_SDK_15.3.0_59ac345
これは皆さんが SDK をインストールした場所に合わせてください。また、bash では $HOME で良いですが、Makefile では $(HOME) のようにカッコで囲まないといけません。
次に、SDK の中にある Makefile を修正します。今回は Mac OS なので
vi $SDK_ROOT/components/toolchain/gcc/Makefile.posix
とします。Windows の場合は Makefile.windows になるでしょう。
上記ファイルを次のように変更します。
GNU_INSTALL_ROOT ?= $(HOME)/Library/xPacks/@xpack-dev-tools/arm-none-eabi-gcc/9.2.1-1.1.1/.content/bin/ GNU_VERSION ?= 9.2.1 GNU_PREFIX ?= arm-none-eabi
これは、上述のように xpm インストールした xPack GNU Arm Embedded GCC(v9.2.1-1.1)を使う場合です。OS が異なる場合には、GNU_INSTALL_ROOT の場所が違ってくると思います。GNU_INSTALL_ROOT の行の末尾にスラッシュ(/)を忘れないようにしましょう。なんか、トリッキーですね。
GNU_VERSION には GNU toolchain のバージョンを指定します。
ここまでできたら、make してみましょう。先ほどのディレクトリ armgcc の中で実行します。入力するのは最初の make コマンドだけです。残りは表示結果です。
make mkdir _build cd _build && mkdir nrf52832_xxaa Assembling file: gcc_startup_nrf52.S Compiling file: nrf_log_frontend.c (略) Compiling file: main.c Compiling file: system_nrf52.c Linking target: _build/nrf52832_xxaa.out text data bss dec hex filename 2072 108 28 2208 8a0 _build/nrf52832_xxaa.out Preparing: _build/nrf52832_xxaa.hex Preparing: _build/nrf52832_xxaa.bin DONE nrf52832_xxaa
ビルドできたら、フラッシュメモリに焼いてみましょう。まず、Nordic nRF52 SDK を USB ケーブルで PC に繋ぎます。そしたら、make flash します。
make flash DONE nrf52832_xxaa Flashing: _build/nrf52832_xxaa.hex nrfjprog -f nrf52 --program _build/nrf52832_xxaa.hex --sectorerase Parsing hex file. Erasing page at address 0x0. Applying system reset. Checking that the area to write is not protected. Programming device. nrfjprog -f nrf52 --reset Applying system reset. Run.
もし nrfjprog の実行でエラーが出る場合には、実行パス(PATH)に nrfjprog が含まれていることを確認してください。また、JLink が正しくインストールされているかどうか確認してください。
うまく行くと、以下の写真のように右上の 4つの LED が順繰りに点滅していくはずです。
Eclipse 上でビルドできるようにする
このままでも開発はできますが、やはり IDE(統合開発環境)を使いたい、という方が多いでしょう。特にデバッグはそうですよね。
まずは Eclipse を起動し、適当な場所を workspace に設定します。先ほどの my_nordic と同じ階層か、それより上に workspace ディレクトリを作るのが良いでしょう。
そうしたら、先ほどの blinky プロジェクトを取り込み(import し)ます。
まず、Welcome to the Eclipse … というようなウィンドウが開いていたら、それを閉じます。画面上の Welcome というタブ右の「×」印をクリックします。ここから以降、Eclipse の基本的な操作は御存知という前提で進めます。
メニューから、File → New → Makefile Project with Existing Code を選びます。次のようなウィンドウ(ダイアログ)が開くはずです。
Project Name には blinky と入力しましょう。そして、Existing Code Location 右の Browse… ボタンを押します。
ファイルブラウザが開いたら、my_nordic/blinky/pca10040/blank/armgcc と辿り、armgcc(Makefile がある場所)が見えている状態で Open ボタンを押します。
Import Existing Code ウィンドウに戻ったら、Languages から C++ ボタンのチェックを消し、Toolchain for Indexer Settings では ARM Cross GCC を選びます。これが実は重要で、<none> でも良さそうに思えるのですが、Eclipse の中でいくつかの重要な設定がされなくなり、後のデバッグ操作で支障が出ます。(実行ファイルパスが自動的に見つからない、変数 cross_prefix が設定されないので、ARM 用の GDB でなくネイティブの GDB が起動されてしまう、など。)
Finish ボタンを押したら、Project Explorer ペインの blinky プロジェクト左の三角アイコンをクリックし、ツリーを広げてみましょう。このようになるはずです。
最初に、ちょっとした tweak(一ひねり)が必要です。Eclipse か CDT か MCU plug-in のバグだと思うのですが、このままビルドするとエラーになります。ちょっとやってみましょう。Project Explorer の blinky プロジェクトを右クリックし、プルダウンメニューから Build Project を実行します。
terminated with exit code 127 というエラーが出てしまいます。
これを解決するには、一度プロジェクトの properties を開き、何か変更を加えます。プロジェクトを再度右クリックしたら Properties を選び、ウィンドウを開きます。開いたウィンドウ左の C/C++ Build ツリーを開き、Settings を選びます。そうしたら、そのまま Apply & Close ボタンを押します。再度 Build Project を実行すると、正しくビルドできます。変なバグですね。
次の問題は、ソースコードが表示されていないことです。ソースが表示されてなくても、ビルドはできるのですが。。。
ソースコードを表示するには
これは、最初に説明した Nordic 社のブログで紹介されている方法です。
まず、プロジェクトに virtual folder を追加します。プロジェクトを右クリックして New → Folder します。ウィンドウが開いたら、Folder name には src などと入力し(どんな名前でも良いです)、Advanced ボタンを押してから Virtual Folder を選びます。最後に Finish をクリックします。
続いて、ソースファイル(今回は main.c)の追加です。プロジェクトツリーの下にできた src というフォルダを右クリックし、New → File とします。
ウィンドウが開いたら、Advanced を開き、main.c を探します。
main.c を選んだら Open します。次のようになるはずです。
Finish をクリックします。これで、ファイル main.c が開けるようになりました。
なお、main.c に赤い「×」印がつくかも知れません。これは、indexer というツールが、いくつかの include ファイルの検索に失敗した、という意味です。ビルドには支障ないのですが、デバッグ時には不便かも知れません。この解決方法は次回に回します。興味ある方は、こちらを参考にしてください。CDT User Setting Entries を選んで Add ボタンを押すと、個別に include パスを設定できます。もっとエレガント(?)な方法が、上記の Nordic 社ブログに紹介されているのですが、バージョンが上がっているので、そのままでは適用できません。次回への宿題にしましょう。
デバッグの方法
ようやくデバッグまでたどり着きました。
Eclipse でデバッグするには、debug configuration というものを設定する必要があります。上記 Nordic 社ブログにも説明がありますが、やってみましょう。
まず最初に、debug configuration を新規に作成します。Project Explorer から blinky を右クリックで選び、Debug As → Debug Configurations… を選びます。そうしたら、開いたウィンドウの左から「GDB SEGGER J-Link Debugging」という項目をダブルクリックします。
最初は、Main というタブが開くと思います。Project が blinky、C/C++ Application が _build/nrf52832_xxaa.out となるはずです。(上のほうの説明の操作で、Toolchain for Indexer Settings で <none> を選ぶと、ここがうまく表示されないはずです。)
次に、Debugger タブを開きます。上のほうの Actual executable が JLinkGDBServerCLExe となっていることを確認します。(OS によって異なるかも知れません。) 次に、下のほうの GDB Client Setup で Actual executables が arm-none-eabi-gdb となっていることを確認します。これが gdb しか表示されていないと、ARM 用ではない GDB が起動されてしまい、うまくデバッグできません。
最後に、Device name というところに nrf52832_xxaa と入力し、Apply ボタンを押します。続いて Debug ボタンを押すと GDB が起動します。
Confirm Perspective Switch というダイアログが出たら、Remember my decision にチェックを入れ、Switch ボタンを押します。
ここからは見慣れた画面だと思う方も多いかと思います。メニューから Run → Step Over を選ぶと、C 言語レベルで一行ずつ実行が進んでいきます。ただし、nrf_delay_ms() 関数の呼び出しを step over するとなぜかうまく行きませんので、それはやめて、bsp_board_led_invert() 関数にブレークポイントを設定し、Run → Resume を実行するほうが良いでしょう。
このあたり、組込系のデバッグでは、ある程度の試行錯誤が必要になるところです。理由は、(プログラムがフラッシュメモリに格納されているため)ステップ実行にハードウェアブレークポイントが必要になることと関係があると思うのですが、私も詳細は分かりません。
とりあえず、デバッグできましたね。今日はここまでにしましょう。
次回の宿題
- BLE 関連アプリをビルドして実行してみましょう
- Eclipse からフラッシュメモリにプログラムを書き込んでみましょう
- include ファイルへのパスを設定し、ソースコード上の「?」マーク(下図参照)を消しましょう