STM32 Simple BLE Beacon

はじめに

STM32リーフを使ったシンプルなBLE Beaconのサンプルデザインです。 「HELLO BEACON」という文字列を一定期間送信してからスリープを繰り返します。

サンプルのソースコード

使用するスケッチやツールのソースコードは下記のリポジトリで閲覧可能です。

Sample-Sketches/STM32_Simple_Beacon at master · Leafony/Sample-Sketches

用意するもの

使用するリーフ

動作方法

スケッチの解説

フローチャート

STM32_Simple_Beacon.inoloop()関数の動作は下図のように、STM32リーフとBLEリーフが交互にスリープ状態とアクティブ状態を一定の時間繰り返しながらBeaconのパケット(Advertising data)を送信することで、省電力なシステムを実現しています。

STM32リーフがStartAdvData()を実行すると、BLEリーフでブロードキャストしたいAdvertising dataを設定し、送信を開始するコマンドを送ります。

BLEリーフがAdvertising中、STM32リーフは何もしないため、LowPower.deepSleep()関数でディープスリープモードに移行し、WAKE_INTERVALで設定した時間が経過後、再びアクティブ状態に戻ります。この間、STM32リーフでは必要最小限の電力で動作できるように不要な回路ブロックの電源を落とす等をし、非常に省電力な状態で動作します。

STM32リーフがアクティブ状態に移行後、sleepBLE()関数を実行し、BLEリーフのAdvertisingを停止させ、BLEリーフをスリープモードに移行させます。その後すぐにSTM32リーフ自身もLowPower.deepSleep()関数でSLEEP_INTERVALで設定した時間ディープスリープモードに移行します。この状態においては極わずかな電力しか消費せず、SLEEP_INTERVALの時間を長くすればするほど電池の持ちを良くすることができます。

STM32リーフがディープスリープから復帰後、すぐにBLEリーフを起動させ、再びStartAdvData()を実行して最初の処理に戻ります。

Advertising dataの仕様

STM32_Simple_Beacon.inoStartAdvData()関数では、BLEリーフにAdvertising dataを設定し、BLE Client(PCやスマホ、Raspberry Pi等のLeafonyとBLE接続する機器)でLeafonyを検出した際に表示されるデバイス名を「Leaf_A」とし、ユーザデータとして「HELLO BEACON」という文字列を送信しています。

adv_data[]配列がAdvertising dataです。この配列はコメントに記載されているように、AD Structure 1AD Structure 3というデータの塊を繋げたデータとなっています。これらのデータの内容については後述します。

ble112.ble_cmd_le_gap_set_adv_data()adv_dataをBLEリーフに登録し、BLEリーフ側から登録完了の信号が来るのを待つために、ble112.checkActivity()を実行しています。

ble112.ble_cmd_le_gap_start_advertising()を実行することで、BLEがAdvertisingを開始して、先程設定したAdvertising dataをブロードキャストし始めます。LE_GA_SCANNABLE_NON_CONNECTALBEを設定したことで、BLE Client側はAdvertising dataをスキャンすることはできますが、このデバイスと接続を確立することは禁止しています。これは、接続要求が来た場合に発生するイベントの処理を減らして電力を削減するための設定です。

void StartAdvData()
{
  // Advertising data; 25byte MAX
  uint8_t adv_data[] = {
    // AD Structure 1: Flag
    (2),  //0: field length
    BGLIB_GAP_AD_TYPE_FLAGS,  //1: field type (0x01)
    (6),  //2: data
    // AD Structure 2: Complete local name
    (7),  //3: field length
    BGLIB_GAP_AD_TYPE_LOCALNAME_COMPLETE,  //4: field type (0x09)
    ('L'),  //5:
    ('e'),  //6:
    ('a'),  //7:
    ('f'),  //8:
    ('_'),  //9:
    ('A'),  //10:
    // AD Structure 3: Manufacture specific
    (13),   //11: field length
    (0xff), //12: field type (0xff)
    ('H'),  //13:
    ('E'),  //14:
    ('L'),  //15:
    ('L'),  //16:
    ('O'),  //17:
    (' '),  //18:
    ('B'),  //19:
    ('E'),  //20:
    ('A'),  //21:
    ('C'),  //22:
    ('O'),  //23:
    ('N'),  //24:
  };

  // Register advertising packet
  uint8_t stLen = sizeof(adv_data);
  ble112.ble_cmd_le_gap_set_adv_data(SCAN_RSP_ADVERTISING_PACKETS, stLen, adv_data);
  while (ble112.checkActivity(1000));

  // index = 0  LE_GAP_SCANNABLE_NON_CONNECTABLE / LE_GAP_UNDIRECTED_CONNECTABLE
  ble112.ble_cmd_le_gap_start_advertising(0, LE_GAP_USER_DATA, LE_GAP_SCANNABLE_NON_CONNECTABLE);
  while (ble112.checkActivity(1000));
}

下図はBLEのAdvertisingで使用される、Advertising dataのフォーマットを表しています。

Advertising dataは複数のAD Structureというデータの塊から構成されています。各AD Structureの中身はLengthDataに分けられ、Lengthには、Dataのオクテット数(何byteか)が登録されます。

Dataの中身は更に、AD TypeAD Dataに分けられ、AD TypeでこのAD Structureがどのような意味のデータなのかが分かるようになっています。

例えば、上記コードのAD Structure 2Lengthが7で、AD TypeBGLIB_GAP_AD_TYPE_LOCALNAME_COMPLETE (0x09)でデバイスのローカルネームであることがわかり、DataLeaf_Aと登録されています。

AD Structure 3AD Typeは0xffで、このAD Structureには任意のデータを登録することができます。Dataには「HELLO BEACON」というテキストが登録されていて、このデータを変えれば自由にデータをAdvertising dataに載せてブロードキャストすることができます。

BLEリーフの動作

  • 各種設定
  • イベントハンドラ

最終更新 October 16, 2020