Nordic nRF52 を GCC で開発する(通信アプリ編)

(更新

Building a Nordic nRF52 BLE app by GCC and Eclipse.

前回は、とりあえず GCC と Eclipse をインストールし、Nordic nRF52 DK ボード上で「LED チカチカ」プログラムを動かしてみました。前回できなかったテーマ(宿題)を、今回は進めて行きましょう。

Eclipse 上からフラッシュ ROM に書き込もう

前回は、make コマンドでフラッシュ ROM にプログラムを書き込みましたが、実は Eclipse CDT(C/C++ Development Tooling)では、IDE 上から makefile の target を指定して make コマンドを実行する機能があります。

target とは何でしょう?  makefile を見ると、次のような構文が目に入るはずです。

flash: default
        @echo Flashing: $(OUTPUT_DIRECTORY)/nrf52832_xxaa.hex
        nrfjprog -f nrf52 --program $(OUTPUT_DIRECTORY)/nrf52832_xxaa.hex --sectorerase
erase:
        nrfjprog -f nrf52 --eraseall

この flash とか erase のように行頭に記述されているものが target です。例えば、make flash というコマンドを実行すると、make コマンドは、「flash という target を生成するんだな」というふうに解釈します。(詳しくは make のマニュアルを参照してください。)

Eclipse CDT では、この make target を GUI から実行するように設定できます。Nordic 社のブログの「Flash download」というセクションでも説明されているように、 まず、Build Targets というウィンドウ(ペイン?)を開きます。画面上に見当たらない場合は、メニューから Window → Show View → Build Targets をクリックすると開きます。そうしたら、プロジェクト名(例えば先週使った blinky)を右クリックし、New… を選びます。ウィンドウが開いたら、Target name のところに flash と入力し、OK ボタンを押します。

すると、Build Targets の Blinky の下に(ツリーの下階層に)flash というアイテムができるはずです。これをダブルクリックすると、make flash が実行されます。

なお、もしかすると make flash 時に

nrfjprog -f nrf52 --program _build/nrf52832_xxaa.hex --sectorerase
/bin/bash: nrfjprog: command not found
make: *** [flash] Error 127

のようにエラーとなるかも知れません。これは、make 実行時の環境変数 PATH にnrfjprog が含まれていないことが原因です。Eclipse CDT が make 実行時に、意図的に PATH をオーバーライドしているようです。その場合は Makefile の先頭に次のような行を追加してください。

SHELL := /bin/bash
PATH := (nrfjprogのありか):$(PATH)

下記のように、うまくフラッシュ書き込みできたでしょうか?

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.

BLE サンプルアプリを動かしてみよう

前回のように blinky アプリをビルドできれば、あとは同様に BLE(Bluetooth Low Energy)のサンプルプログラムをビルドすることができるのですが、一つだけ注意点があります。それは、SoftDevice です。

Nordic nRF5 シリーズの SDK では通常、ユーザーのアプリケーションプログラムに加えて、SoftDevice というものをフラッシュメモリに書き込む必要があります。SoftDevice というのは Nordic 社からバイナリ形式で提供される「プロトコルスタック」のソフトウェア(ライブラリ)で、そのライブラリ中で Bluetooth LE などの通信プロトコルを実現しています。つまり、通信系のアプリケーションを動かすためには、SoftDevice を併せてフラッシュメモリに書き込む必要があります。

前回の blinky のパスを覚えていらっしゃる方は、次のようなディレクトリ中の Makefile を使ったことに気づくかと思います。

blinky/pca10040/blank/armgcc

ここで blank というのは、SoftDevice を使わないという意味です。LED チカチカのためには BLE のプロトコルスタックは不要なので、SoftDevice がなくても動作する訳ですね。一方で、今回試してみる BLE サンプルアプリでは、SoftDevice を書き込まないと正しく動作しません。その点に注意して、試してみましょう。

前回と同様、ディレクトリ my_nordic の下にサンプルプロジェクトをコピーします。今回は、ble_peripheral/ble_app_hrs というプロジェクトにしましょう。HRS というのは Heart Rate Service の略で、BLE で決められた標準的な通信プロファイルの一つです。

BLE では GATT(Generic Attribute Profile)というものが定義されていて、Battery Service(バッテリーの残量等を知らせる)、Cycling Speed and Cadence Service(自転車の速度やペダルの回転速度を知らせる)のような標準的なサービス(プロファイル)を規定しています。これによって、標準的なアプリケーションであれば、ユーザーが専用のソフトウェアを用意しなくても良いという訳です。

ちょっと例えは変ですが、インターネットでは HTTP や FTP という標準的なプロトコルが定義されているので、標準的なブラウザソフトさえ用意すれば、どんなウェブサービスにも接続できるのに似ています。GATT の例は、こちらにリストがあります。一度見てみると参考になるでしょう。なお、もちろんこのような標準的なプロトコルで規定されていないアプリケーションも動作させることができますので、心配は不要です。

コピーしたら、前回と同様に Eclipse に取り込んでビルドしてみましょう。Makefile の場所は、 pca10040/s132/armgcc です。無事にビルドできましたでしょうか?

(略)
Compiling file: oberon_backend_hmac.c
Linking target: _build/nrf52832_xxaa.out
   text	   data	    bss	    dec	    hex	filename
 104548	    228	   5780	 110556	  1afdc	_build/nrf52832_xxaa.out
Preparing: _build/nrf52832_xxaa.hex
Preparing: _build/nrf52832_xxaa.bin
DONE nrf52832_xxaa

10:38:40 Build Finished. 0 errors, 0 warnings. (took 27s.959ms)

さて、まずは SoftDevice からフラッシュに書き込みましょう。SoftDevice の書込には、make コマンドで

make flash_softdevice

とします。これは、先ほど説明したように Build Targets に追加すれば、Eclipse 中からも可能です。

make flash_softdevice 
Flashing: s132_nrf52_6.1.1_softdevice.hex
nrfjprog -f nrf52 --program /Users/yokoyama/nRF5_SDK_15.3.0_59ac345/components/softdevice/s132/hex/s132_nrf52_6.1.1_softdevice.hex --sectorerase
Parsing hex file.
(略)
Erasing page at address 0x25000.
Applying system reset.
Checking that the area to write is not protected.
Programming device.
nrfjprog -f nrf52 --reset
Applying system reset.
Run.

10:41:02 Build Finished. 0 errors, 0 warnings. (took 3s.896ms)

続いて、make flash です。アプリケーションの書込ですね。

Flashing: _build/nrf52832_xxaa.hex
nrfjprog -f nrf52 --program _build/nrf52832_xxaa.hex --sectorerase
Parsing hex file.
(略)
Erasing page at address 0x3F000.
Applying system reset.
Checking that the area to write is not protected.
Programming device.
nrfjprog -f nrf52 --reset
Applying system reset.
Run.

10:42:35 Build Finished. 0 errors, 0 warnings. (took 2s.998ms)

フラッシュ書込が完了すると自動的にアプリケーションが起動します。nRF52 DK ボード上の LED 1 が 1秒程度の間隔で点滅しているのが分かりますでしょうか。

スマホアプリから接続してみよう

さて。実際にアプリが動作しているかどうか調べてみましょう。そのためには、対向して動作する通信機器が必要ですが、今回は Android スマートフォンを使います。2つのアプリを紹介しておきましょう。

前者は一般的な BLE テストアプリで、後者は Nordic 社の nRF5x デバイス用テストアプリです。

BLE Scanner: Read, Write, Notify

まずはこちらの BLE Scanner です。ボード上の LED が点滅している状態で起動してみましょう。

一番下に表示されているのが nRF52 DK ですね。CONNECT ボタンを押すと接続ができます。接続中の画面で、HEART RATE を開き、HEART RATE MEASUREMENT 横の「N」(notification)ボタンを押すと、現在の測定値(ここでは 150bpm)が読み出せます。

BLE の通信というのは、このようなデータベースへのアクセスのような形となっていて、データベース中のデータを BLE ペリフェラル(今回は nRF52 DK)から書き換えたり、読み出したり、また逆に、BLE セントラル(今回は Android スマートフォン)から書き換えたり読み出したりすることができます。上で notification と書いたように、データが変更された時点で BLE セントラルにイベント通知を上げることもできます。

nRF Toolbox for BLE

続いて nRF Toolbox for BLE です。こちらのソフトは癖があり、Google Play ストアでもいろいろと問題がレポートされていますが、私が試したところでは、Android 9 では動作しました。ただし、ペアリングをしてあげないと nRF52 を検出できないようです。Android の設定画面から Bluetooth を開き、ペアリングしてあげましょう。

そして、アプリを開きます。

このような画面から、HRM というボタンをタップします。新しい画面に切り替わったら、CONNECT ボタンを押します。BONDED DEVICES という中から Nordic_HRM を選びます。次のような画面が表示されるはずです。

ここでは、Battery Service と Heart Rate Service のデモになっています。測定値は擬似的なものですが、デモとしては十分でしょう。

ソースコードを少し眺めてみよう

ble_app_hrm のソースコードは大きめで、詳細を理解するには Nordic 社のサイトで確認するしかないのですが、ちょっとだけソースを覗いてみましょう。

main.c を見ると、次のようなコードが見つかります。

154 static ble_uuid_t m_adv_uuids[] =                                   /**< Universally unique service identifiers. */
155 {
156     {BLE_UUID_HEART_RATE_SERVICE,           BLE_UUID_TYPE_BLE},
157     {BLE_UUID_BATTERY_SERVICE,              BLE_UUID_TYPE_BLE},
158     {BLE_UUID_DEVICE_INFORMATION_SERVICE,   BLE_UUID_TYPE_BLE}
159 };

ここが、使用する GATT のサービスを列挙しているところですね。Battery Service や Heart Rate Service(HRS)が見つかります。

HRS の心拍数の上下をシミュレーションしているのはどこかというと、こんなコードが見つかります。

277 static void heart_rate_meas_timeout_handler(void * p_context)
278 {
279     static uint32_t cnt = 0;
280     ret_code_t      err_code;
281     uint16_t        heart_rate;
282 
283     UNUSED_PARAMETER(p_context);
284 
285     heart_rate = (uint16_t)sensorsim_measure(&m_heart_rate_sim_state, &m_heart_rate_sim_cfg);

sensorsim_measure() というのがそれっぽいですが、main.c の中にはありませんね。デモコードなのだからサンプルプロジェクト中で定義すれば良いと思うのですが、これはライブラリとして提供されています。ソースは components/libraries/sensorsim/sensorsim.c というところにあります。sensorsim_init() で初期化時に、最高心拍と最低心拍数を渡しているようですね。再度 main.c のほうを確認すると、

100 #define MIN_HEART_RATE         140
101 #define MAX_HEART_RATE         300
102 #define HEART_RATE_INCREMENT   10

という定義が見つかりました。

参考資料

ちなみに、Nordic 社では以前、非常によく書けているアプリケーションノートがあったのですが、最近は全然アップデートされていないようです。

半導体メーカーでは、こういうドキュメントをしっかりアップデートしていくことが本当に大切なんですけどね。こちらの議論を見ていると、おそらくこのドキュメントを書いた優秀な社員は Nordic 社を辞めてしまったか、ポジションを外れてしまったような印象を受けます。サンプルコードはアプリケーションノートの代わりにはなりません。残念なことです。

優秀な社員はお金だけでは集まりません。市場経済の中では、人をぞんざいに扱えば企業は必ず衰退していきます。

愚痴っぽくなってきたので、今日はここまでにしましょう。