叶鋼は午前1時に計算をする

電子工作と計算の記録

【BLEを使う】mbed HRM1017サンプルプログラムのプロトコル解析 その2

それは私の竪琴から

はじめてこの世に現れた

それ以来

たくさんの鼻でゆっくりと

自分の子どもを引き連れて

ナゾベームは歩く

鼻行類」より引用

いままでの記事はこちらをご覧ください。

 

前回はHRM1017がadvertisingパケットをひたすら周囲に送信し、ipadのnRF Toolboxがそれを検知してスキャンパケットの送受信をするところまでを解析しました。

この時点では、まだHRM1017とipadは接続されておらず、ipadは周期的に周囲のデバイスのスキャンを繰り返しています。  

HRM1017はスキャン応答を受けてしばらくは、ipadからの接続開始要求を待ちますが、一定時間経過しても接続開始要求がない場合は、advertisingパケットの送信を再開します。  

実際に、接続開始をしないと、advertisingパケットの送信とスキャンパケットの送受信が延々と繰り返されます。    

④ 接続要求パケット  

本記事は主に以下を参考にしました。例のごとく、そちらを読んだ方が正確で勉強になります。

http://reinforce-lab.github.io/blog/2013/08/13/blebook-ch2-ble-spec/

BLUETOOTH SPECIFICATION Version4.1 [Vol6] 2.3

BLUETOOTH SPECIFICATION Version4.1 [Vol6] 4.5  

nRF ToolboxはHRM1017のadvertisingパケットを検知して、画面上に検知したnRF5を表示しています。これを選択することで接続開始され、以下のパケットを取得します。

f:id:yegang:20140801212724j:plain

Adv PDU TypeがADV_CONNECT_REQの接続要求パケットが確認できます。

これはipad(central)からHRM1017(peripheral)へ送信されています。  

Access AddressやPDU Headerの意味は以前と同様です。

Lengthが34なのでpayloadが34bytesであることが分かります。

payloadはInitA(6bytes)とAdvA(6bytes)、それにLLData(22bytes)で構成されています。

f:id:yegang:20140801213433j:plain

InitAは、Initiator's addressのことで、接続要求を出すipad(central)側のアドレスです。これはScanAと同じになります。

AdvAは同様に先ほど確認したAdvAと同じHRM1017(peripheral)側のアドレスです。  

次に、LLDataについて解析してみます。  

・AccessAddr(4bytes)

f:id:yegang:20140801212833j:plain

接続先であるCentralのAccess Addressです。毎回ランダムに決められています。

以降のデータパケットのAccess Addressがこれと同じ値になっていることが確認できます。  

・CRCInit(3bytes)

f:id:yegang:20140801213200j:plain

以降のデータパケットのCRCの計算で使うシフトレジスタの初期値です。接続を確立するたびに毎回ランダムに決められます。

プログラミングの際は、CRCの計算は自動的に行われるので、特に意識する必要はない数字です。  

CRCはPDUの通信エラーの検出に使われます。通信が正常に行われたかを確認する仕組みです。詳細は省きますが、計算方法はシフトレジスタと EX-OR を使用します。データパケットで使われるシフトレジスタの初期値がこのCRCInitです。

ちなみにAdvertisingパケットのCRC計算で使われるシフトレジスタの初期値は0x555555と決まっています。  

・WinSize、WinOffset、Interval

f:id:yegang:20140801213246j:plain

接続要求パケット以降のデータパケットの送受信タイミングを設定しています。

f:id:yegang:20140801213310j:plain

WinSize ×1.25msec = transmit Window Sizeです。

WinOffset×1.25msec = transmit Window Offseです。

接続要求転送後、遅くともtransmit Window Size + transmit Window Offsetの時間以内に1回目のデータパケット送受信を開始します。  

今回の設定では、transmit Window Sizeが3.75msec、transmit Window Offsetが8.75msecに設定されています。

実際に接続要求終了から1回目のM->S(マスターからスレーブへの通信)が始まるまでの時間を見ると10.992msecになっているので、3.75+8.75=12.5msec以内に開始できています。  

また、Interval×1.25msec = connInterval sizeです。

connIntervalは、マスター(central)からスレーブ(peripheral)へデータパケットが送信されてから、次のマスター(central)からスレーブ(peripheral)の転送が開始されるまでの周期を意味します。

ちなみに仕様書ではM->SとS->Mの送受信をコネクション・イベントと呼んでいます。  

今回の設定では、connInterval は30msecに設定されています。

実際に1回目のM->Sが終了してから、2回目のM->Sが開始するまでの時間が279+29,720=29,999usecで、connInterval設定値の約30msecとほぼ等しくなっているのが確認できます。

f:id:yegang:20140801213626j:plain

・Latency

f:id:yegang:20140801213645j:plain

Latency(connSlaveLatency)はスレーブがマスターからのデータ送信を無視できる回数のことです。

これは消費電力削減のための仕組みです。

スレーブ側に送信すべきデータがない時、それにも関わらずデータ送信するのは電力の無駄です。だからスレーブにデータがなければ、M->Sを無視して、S->Mのデータ送信をしない方が電力節約になります。それならばスレーブにデータがない時は常にマスターからの送信を無視すればいいと考えるかもしれません。

ですが、そうすると困ることがあります。スレーブ側からの反応がない場合、マスターはスレーブが意図的に無視しているのか、それとも接続が切断されてしまったのかを区別できないからです。

そのため、スレーブはデータがなくても、いつかはマスターにデータ送信をする必要があります。 そのいつかが、いつであるかを決める設定がLatencyです。

スレーブにデータがないときは、Latencyに設定した回数だけM->Sを無視し、Latency+1回目のM->Sはデータの有無に関わらず必ずS->Mのデータ送信をします。  

今回は設定値が0なのでスレーブは1回たりともM->Sを無視しません。  

以下において具体的な数値での計算例が提示されているのでご参照ください。

http://reinforce-lab.github.io/blog/2013/08/13/blebook-ch2-ble-spec/

 

・Timeout

f:id:yegang:20140801213744j:plain

マスターがスレーブからデータを受信してから、Timeout時間が経過してもスレーブから次のデータ送信がない場合、マスターは接続が切断されたと判定します。  

この値は最小でも(Latency + 1)回×1.25msecである必要があります。つまり、スレーブがデータ送信を無視できる回数分の時間を、マスターは必ず待ってやります。

ですがこの計算値ギリギリでは、設定時間を目一杯使った直後のM->S通信に失敗すると、やり直す間もなく通信切断となってしまいます。

そこで設定値は最小値に余裕を持たせた値にします。  

ここではLatencyが0だったので、そういうことは考慮する必要もなく、72×1.25msec = 90msecが設定されています。

もしここでLatencyが10だったりしたら、(10+1)×1.25+90=103.75msecにしたりするわけです。(推奨設定値は(Latency + 1)回×1.25msec×6だそうです。)  

ChM

f:id:yegang:20140801213816j:plain

データパケット転送に使用可能なchを選択します。

GAPの解説記事でも書いたようにadvertisingパケットの転送には37ch,38ch,39chを使用し、データパケットの転送には0ch~36chの37個を使用します。

ChMはLSB、つまり1bit目が0chを意味し、37bit目が36chを意味します。各bitを1に設定すると、対応するchを使用します。0なら使用禁止です。

今回は37bitsの全てが1なので全chを使用します。  

・Hop

f:id:yegang:20140801213842j:plain

コネクション・イベントでは、毎回同じchの周波数を使用しません。M->S、S->Mの通信が終わると、次のM->S、S->Mの通信では別chを選択します。

これにより他周波数との干渉を避けやすくなります。頻繁に通信周波数を変更することで周波数が重複しにくくなり、例え重複してもすぐに切り替わるので重複期間が一瞬で済むようになります。  

この周波数の切り替えをどのように行うかを設定するのがHop(hopIncrement)です。

計算は (次回のch) = (今回のch + Hop )mod 37です。modは剰余のことです。

実際に上の例ではch=0x0Dの次のchは、(0x0D+0x0D)% 37 = 0x1A になっています。  

・SCA

f:id:yegang:20140801213915j:plain

マスターのスリープクロックの精度です。

BLUETOOTH SPECIFICATION Version4.1 [Vol6] 2.3によれば、0x05は31~50ppm(百万分の1)になります。

BLEの時間を計る発振回路は高精度ですが、わずかなずれがあります。このずれを放置すると、ずれが蓄積してパケットの送受信ができなくなってしまいます。

これを回避するため、マスターがパケットを送信するとき、スレーブはこのずれの分だけ受信時間を前にずらします。そのずれの値がSCAのようです。(詳しく調べていないので間違っている可能性があります。)     このようにAdvertisingの最終段階である接続要求では、以降のデータパケットの送受信の設定やタイミングを決めています。  

次回はデータパケットの送受信について解析します。