nRF52からアドバタイズしてesp32でスキャンする

isp1807(nRF52)とESP32

概要

  • ISP1807(nRF52840) にはチップ温度を測るためのセンサーTEMPが載っているので、その測定結果をBLEでアドバタイズするスケッチを作成。
  • ESP32 Arduino coreに付属のいくつかのサンプルをもとに、スキャンしたデータをシリアルモニタにダラダラと表示したり、nRF52からの温度を表示したりするスケッチを作成。
  • 当初、nRF52からアドバタイズした温度データの経時変化をPCやスマホ(Android)で観測しようとしたが、適当なアプリが見当たらないので、しばらくお蔵入りしていたESP32 DevKit-C互換品を使いシリアルモニタに表示することにした。

ビルドはArduino IDE (1.8.15)で行い、nRF52用には Adafruit nRF52 BSP (1.1.0)スイッチサイエンス nRF52 BSP (0.1.9)を、ESP32用にはArduino core ESP32 (2.0.0) をおのおの導入した。

ISP1807(nRF52840)用Arduino BSPについて

BSPというのは、Arduino Board Support Package のことで、Arduino IDEの ツール/ボードマネージャ でインストールするターゲットボード用のサポートファイルである。

ISP1807用のBSPの導入方法については、こちらの投稿を参照のこと。Adafruit  nRF52 BSPは比較的頻繁に更新されていて、現時点での最新バージョンは1.1.0 になっていたので、これをインストールして利用した (スイッチサイエンスのISP1807 Microボード用BSPは0.19版)。

ESP32用BSP2.0.0を導入

ESP32に触るのは3年ぶりになる。Arduino IDEにBSPを組み込むための、環境設定/追加のボードマネージャのURL  も以下のように変わっていたので設定し直した。

以前は、 https://dl.espressif.com/dl/package_esp32_index.json だった。

esp32 arduino 2.0.0

最新版の2.0.0を導入して ターゲットボードを選択しようとすると、ESP32C3やS2のDev Moduleが追加されていた。うちにあるのは Not recommend for new design のクラシックモジュール なので、以前と同じくESP32 Dev Module を選択した。

esp32側スケッチの動作

ESP32をつないだシリアルモニタには、こんな感じでスキャン結果を表示し続ける(リセットから開始)。

fb:d1:6e:41:xx:xx が ISP1807からのもので、ご近所のGoogle製BLE機器からのデータも混じっている。また、以下のようにnRF52温度データ用にあわせた表示も可能(シリアルモニタに”2″を送信)。

nRF52のTEMPセンサーはデバイスダイの温度を測るために載っているものらしく、気温を測るための環境センサーではない。だが、だいたい室温+3~4℃で安定しているようだった。

このやり方で温度データがセントラル側にうまく伝わるのなら、ちゃんとした環境センサーをI2Cなどでいくつかぶら下げて温度湿度その他の測定に使えるだろう。

esp32側スケッチ

以下のようなスケッチを用意した。

ESP32用スケッチの概略

BLEScan() によってアドバタイジングデータのスキャンを開始する。見つかると BLEAdvertisedDevice クラスのインスタンスに内容が格納されてコールバックされる。それを構造体 (adv_device_data_t) に格納してリンクリストに保存すると共にシリアルモニタに表示する。

リンクリストには最大500件まで格納するようにし、シリアルモニタへの操作(文字の送信)で、リスト内の全データを再表示できるようにした。

BLEAdvertisedDeviceには、なぜか getADType() というメンバがないのでアドバタイジングデータのタイプは格納していないが、BLEビーコン相当(アドレス、メーカーID 、マニュファクチャラーデータおよびrssi)のデータは記録/表示するようにした。 複数ブロックのデータには対応していない。

過去データを保存するにあたり、WiFiを使ってntpサーバーに接続して現在時刻を取得するようにした。Arduino IDEのシリアルモニタには、タイムスタンプを表示 というオプションがあるので表示するだけなら不要なのだが、受信ログをフラッシュに保存しておく場合を考えて時刻も記録するようにした。

WiFiはすぐ切るようにしているので、長期間使っていると誤差がでてくる。そのため、シリアルモニタへの操作(“9″の送信)で時刻の再取得を行うようにした。

ビルド結果およびパーティションスキーマ

ビルドすると以下のようになった。

スケッチが1,375,449バイト使っている。なんでこんなに大きいんだろう。OTA可能なパーティションスキーマではダメで、2MB APP/2MB SPIFFS という構成でビルドする必要があった。

ISP1807 (nRF52)側スケッチ

定期的にアドバタイズを行うスケッチとして、AdafruitのnRF52ライブラリに含まれている、beacon.inoやadv_advanced.ino といったサンプルスケッチを参考に以下を用意した。

nRF52用スケッチの概略

setup() でアドバタイジングのためのいろいろなフラグや種別の設定を行い、loop() 内で10秒ごとに adv_temp() を呼ぶことで温度データの送信を行っている。

セントラル側(esp32)がスキャンしている期間に送信しないとデータが失われてしまうので、Bluefruit.Advertising.start()  に指定するタイムアウト時間(秒)と、Bluefruit.Advertising.setIntervalMS()  や Bluefruit.Advertising.setFastTimeout() で指定する送信間隔などは実際のスキャン結果を見ながら、頻繁になりすぎず欠報も増えすぎずといった値に設定した。

このスケッチを動かしているときの消費電流はテスター読みで約4.6mA (PCに接続したUSBケーブルのVBUSの電流) だった。もうちょっと少なくてもいいんじゃないの、と思って以下のようなスケッチも用意してみた。

suspendLoop を使ったスケッチ

こちらも約10秒間隔で温度測定とアドバタイジングを行うが、suspendLoop() によってloopタスクをサスペンド状態にしている。その代わり、アドバタイジング期間が終了するごとに  adafruit_ble_taskadv_stop_cb() をコールバックしてくれるので、連続的なアドバタイジングが持続する。ただ、タスクのコールバック内で10秒間もdelay() してしまうのは、好ましくはないだろう。

こちらのスケッチの方がFreeRTOSのタスクが1つ止まる分だけ有効かと思ったが、テスター読みの消費電流はやはり4.6mA程度だった。0.1mA以上の効果があるわけはないか。

アドバタイジングデータの中身

このスケッチは、以下のようなデータを含むペイロードを飛ばしている。

ペイロード

このペイロードの内容は構造体 adv_data_t として定義してあって、測定機会ごとにSeqnoとtempを更新する。

ペイロードは最大31バイトで、アドバタイジングデータの長さ、種別、メーカーIDを除くと27バイトまで任意のデータを格納できるので、この構造体をさらに拡張して複数のセンサーから得た値を飛ばすこともできるだろう。

pid は、複数のnRF52からアドバタイジングするようなとき、測定点の識別用に定義した。

seqno は、測定するごとにインクリメントしている。受信側は、同じタイミングで測定したデータを何度も受け取る可能性があるので、前回のseqnoと比較して一致している場合は重複とみなせるようにした。esp32側スケッチの show_item() にそのための処理を入れた。

ビルド結果

それなりに大きくはなったが、esp32と比べるととてもコンパクトだろう。

きょうのまとめ

当初の目的は、アドバタイジング時の消費電流を測ることだった。そのためには、スケッチが安定してアドバタイジングデータを飛ばしていることを確認する必要があって、esp32側のスケッチも用意することになった。

今回のスケッチ動作中のUSB経由での消費電流はテスター読みで約4.6mA だった。テスター読みなので瞬間的にはもっと流れているのかもしれない。それにしても、ちょっと電流が大きすぎる印象なので、もうちょっと調べてみることにした。

もっとも、PC(ハブ)とUSBケーブルで接続しシリアル通信もできる状態のままで電流の多い少ないを考えてもあまり意味がないのかもしれないが。次回は、ISP1807のいろいろとポイントで消費電流を測定してみた以下の話になります。

ISP1807 Microボードの消費電流を測ってみた