久々に Nordic nRF52 を触ってみる(GCC + Eclipse 編)

(更新

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 を実行するほうが良いでしょう。

このあたり、組込系のデバッグでは、ある程度の試行錯誤が必要になるところです。理由は、(プログラムがフラッシュメモリに格納されているため)ステップ実行にハードウェアブレークポイントが必要になることと関係があると思うのですが、私も詳細は分かりません。

とりあえず、デバッグできましたね。今日はここまでにしましょう。

次回の宿題

お問い合わせはお気軽に!

お問い合わせを頂いた後、継続して営業活動をしたり、ニュースレター等をお送りしたりすることはございません。
御返答は 24時間以内(営業時間中)とさせて頂いております。必ず返信致しますが、時々アドレス誤りと思われる返信エラーがございます。返答が届かない場合、大変お手数ではございますが別のメールアドレスで督促頂けますと幸いです。