2014/07/30

[ble]ClientとServer

1ヶ月も経たないのに、もう忘れてしまった・・・。
が、あのときは調べるだけで手一杯だった。
今度は、吸収する番だ!

 

image

MasterとCentral、SlaveとPeripheralについては、同じになると思っている。

Core_v4.1の図で、Initiatingになった方がMaster、Advertisingになった方がSlave。
Vol.6 Part Bの図。

image

 

こちらは、Vol.3 Part Cの図。
AがInitiatedしているので、Masterと言えよう。あるいは、AがInitiatedしたいので、L2CAPではMasterになるというのか。

image

 

それに対して、ServerとClientは意味合いが異なる。
Vol.3 Part Gの図を見るとよいか。

image

だいたい上記の作りにする場合、SensorがPeripheralでComputerがCenterになるだろう。
でも、データを持っているのはSensorの方で、Computerはそれを取得しに行くことになる。
つまり、SensorがServerで、ComputerがClientだ。

でもこれが、Sensorとなっている方がComputerの状態を定期的に監視してブザーを鳴らすデバイスだったらどうだろうか。
やはりSensorとなっている方はPeripheralでComputerはCentralになるだろうけど、データを持っているのはComputerで、Sensorがそれを取得しに行くことだろう。
そうなると、SensorがClientで、ComputerがServerだ。

ってことでいいんだよね。

2014/07/29

[nfc]HCEがキーワードらしい

http://itpro.nikkeibp.co.jp/atcl/news/14/072400197/

2014年のキーワードは、HCEらしい。
まあ、もう2014年も半分が終わったのに・・・とか言っても仕方が無い。
それに、どのクオーターで数えるのかは人それぞれなので、細かいことは捨て置け。

私は、HCEっていうのはAndroidの機能名だと思っていた。
TgInitAsTargetコマンドとかでR/Wをターゲット状態にしたとき、そのコマンドをさばくのはホストだ。
だから、カードエミュレーションする≒ホストがカードエミュレーションする、という認識だったのだ。
もちろん、モバイルのFeliCaチップのようなセキュアエレメントを使うようになっているものは、チップとセキュアエレメントが勝手に通信しあって解決してしまう。
そこがセキュアエレメントのセキュアエレメントたるゆえんだ。

HCEすると、ホストが全部やるので、データはつーつーになる。
だから極端に言えば、適当なところでメモリを抜き取ると、通信したデータが取得できるだろう。
でもまあ、そんなことをいえば、HTTPSとかの通信だってどこかでメモリに落としてるんだから、拾おうと思えば拾えるんじゃないかと思う。
課題は色々あるんだけど、私はあまりセキュリティに詳しくないせいもあって、楽観的だ。
なんとかなるんじゃないのー、という感じ。
いや、詳しくなった方がいいんだろうけど、もう私の許容範囲を超えてますわ。

 

そういうのはよいとして、HCEってなんだろう?というのがもやもやとしている。
私の認識は、今のところ、こう。

  • NFC Forumのカードエミュレーション
    • 特に機能を限定せず、タグ以外のものがカードエミュレーションすること全般を呼んでいる
  • AndroidのHCE
    • 今までCardEmulation機能をユーザに提供していなかったAndroidが、Type4かつSEなしで可エードエミュレーションできるようになった
  • NFC ForumのHCE
    • SE必須となっていた内容についてカードエミュレーションすること?

私はNFC Forumのメンバーじゃ無いので、内部でどういう話が進んでいるのかはわからない。
非メンバーが見ることができる技術仕様書には、SEが絡みそうな話は出てきてなかったと思う。
だから、NFC ForumがHCEの話をすると「?」と思ってしまうのだった。

http://nfc-forum.org/newsroom/nfc-forum-statement-regarding-host-card-emulation-hce/
こちらを読むと、NCIにHCE実装について書いてあるようだ。
NCIは・・・読んでない・・・。

ただ興味深いのは、上記リンクにはNFC-A, B, FのようなNFC Forumの区分ではなく、ISO 14443やJIS X6319-4のような規格名になっていることだ。
ISO 14443は見たことがないのだが、JIS X6319-4はこちらから見ることができる。
X6319だと、Read w/o Encryptionとか、Write w/o Encryptionじゃない、ReadやWriteというコマンドがある。
これは、認証しないと使えないコマンドで、確か通信経路も含めて符号化されるんじゃ無かったっけ。

NFC Forumの、非会員で見ることができる技術仕様書には、データの保護を行うための符号化については取り決めが無い。
だからかねー、というところだ。
私の予想では、LLCPSでセキュアなP2Pをする方向になるかと思ってたけど、やはり既存の資産は優先されますわな。

2014/07/27

[ble][nrf51]Write w/o Encで書き込んだUUIDをiBeaconする

FeliCa PlugからUUIDを書き込み、そのUUIDでAdvertisingというかiBeaconというかをするようにできた。
https://github.com/hirokuma/nrf51822_felicaplug/commit/3b8bb6329223354209f7531836184650a800d30b

今朝まで、なぜかAdvertisingさせようとするとHardFaultしていたのだが、なぜか直った・・・。
Eclipseかgdbか・・・。

ブロック0に1ブロック書き込みすると、そのデータをそのままUUIDとしてiBeaconのデータを投げる。
Major, Minor, RSSIなどは固定だ。
もう1ブロック増やして、そこも可変にしてもよいのだけど、手元に1ブロックアクセスするNFCアプリしか作っていなかったので、もういいや。

なんでこんなもん作ったかというと、FLASH書き込みを行わずに外部からUUIDを書き換えられると便利かも、と思ったからだ。
iBeaconアプリの評価とかによいかもね。

image

まあ、私自身はiBeaconにあまり興味を持ってないのだけど、OSが動作確認に使えるという点では便利だ。
SNEP実装したときにAndroid Beamで動作確認するような、そんな感じだ。

image

LEDは3つ。
搬送波検知が左、Advertising中が真ん中、エラー発生が右。
まあ、本当に運用するならAdvertising中のLEDは無しだな。

 

さて、簡単そうなところは動かせたので、次はGATTとかそういうやつかな。

AutoHotkey

Windowsでキーカスタマイズするのに、AutoHotkeyを使っている。

最近になって思うのだが、作業を便利にするのはいいとしても、キーカスタマイズはあまりやらない方がよいな、と。
一度キーカスタマイズしてその環境に慣れてしまうと、他の環境でも同じキーカスタマイズにしないとストレスがたまってくる。

  • 一時的に他のPCを使うとき、疲れる
  • 一時的に人にPCを貸すとき、びくびくする
  • PCをセットアップするのに時間がかかる
  • 気に入るカスタマイズが見つかるまで、いろいろ試して時間がかかる

などなど、弊害多数。
にもかかわらず・・・一度やって慣れてしまうと、もうだめなのだ・・・。

以前までは、窓使いの憂鬱とか、猫まねきとかを使ってたんだけど、Windows7になってから使えなかったので、AutoHotkeyに乗り換えた次第だ。
レジストリの書き換えが無いので、アプリさえ立ち上げなければ元の環境に戻れるというのが助かる。
CtrlとCapsLockの変更については、このツールではできなかった気がする。

^h::Send,{backspace}
$^f::Send,{right}
^b::Send,{left}
^n::Send,{down}
^p::Send,{up}
sc029::Send,{Esc}
^+f::Send,^{f}

私はEmacsは使えないのだけど、カーソルをCtrlキーのキーバインドで実現できるのは気に入ったので、そこだけ採用した。

そうすると、検索をCtrl+Fに割り当てているソフトが使いにくくなる。
では、ほとんど使わないCtrl+Shift+Fを押すとCtrl+Fになるようにしておこう、というのが上記だ。
$^fと$を付けないと、^+fによる^fがrightに置き換えられてしまうようだ。

2014/07/26

[nrf51]FeliCa Plugの時間

ロジアナが来たので、FeliCa Plugの通信速度などを計測。
SPIは1Mbpsにしている。

image

最初の2byteから184us空いてデータ受信をしている。
これは、FeliCa Plugが送ってくるデータサイズがわからないので、1byte目のコマンドと、2byte目のブロック数を読んでから全体の受信サイズを決めているところなので、そこの間だ。
まあ、本当はブロックリストエレメントが2byteなのか3byteなのかをさばかないといけないのだけど・・・省略した。
だって、2byteのブロックエレメントくらいしか使わんやん!

そのあとは、nRF51 SDKに任せているところだ。
データ間隔は12.2usというところか。
最初の2byteだけ連続しているのは、SPIの送受信ともに余裕バッファが1つあるので、そこに貯める間隔が早くなっているだけのようだ。3byte目までの時間が空いているのは、結局そこが空くまで待つからだろう。

そんなわけで、時間的にもそんなに悪くない作りになったんじゃないのかな。
ここまでの成果は、githubにも上げてます。

ZeroPlusでダウンロードする無料の解析プロトコル

ようやく、ZeroPlusで何をダウンロードすればよいかわかった・・・。
ロジアナ本体はわかるとして、無料のプロトコル解析の方だ。
追加でダウンロードするものについては説明があるんだけど、無料の方がわからんかったのだ。

image

これをインストールすればよい。

ロジアナを買いました

ロジアナを買うと、テンションが上がりますな。

http://akizukidenshi.com/catalog/g/gM-04426/

スタンドアローンじゃなくて、PCと接続するタイプ。
サンプリングレートは100Hz~100MHzとあるので、私の扱う範囲では問題なし。
何より、お値段が手頃。
プロトコル解析にも対応していて、無料で25プロトコルまで追加ダウンロードできる。
(この、25個という制限に気付かないところだった・・・。)

で、ここで作業が止まっている。。。
秋月から買ったZeroPlusにはインストールメディアが入っておらず、ダウンロードするようになっている。
んで、サイトからダウンロードするのだけど、Logic AnalyzerとProtocol Analyzerがあり、ロジアナ本体はLogic Analyzerをダウンロードして使えたのだが、プロトコルの解析はProtocol Analyzerをダウンロードするようだ。
ではとダウンロードしたのだが・・・うちのAvastがウイルス検知してしまった。

誤検知かどうかっていうのを素人が判断するのは難しいと思う。
ZeroPlusはけっこうメジャーなので大丈夫な気はするが、私がダウンロードした瞬間はダメなソフトになっていたのかもしれない。
とりあえず、Microsoftのセキュリティソフトに変更して試してみよう。
あー、こんなので私の週末は終わるのかー

2014/07/25

FeliCa Linkがスイッチサイエンスさんから発売

とうとう来ましたねぇ。
個人購入できるFeliCa Linkですよ、奥さん。
やはり、ここはスイッチサイエンスさんだった。
そっけないページとは裏腹に、在庫を多数用意しているところに本気さを感じるのは私だけか。


さて、FeliCa Linkについて購入前の復習をしておきましょう。

まず型番から。
RC-S730はアンテナ付きのモジュール、RC-S967はチップ単体。
私のように使うだけの人は、RC-S730になる。
ちなみに「RC-S370」は、少し前までメインだったPaSoRiの型番なので、注意しよう。

そして、機能についてみていこう・・・・あれ。
あれっれれれれれれれr????

さっき、モジュールとチップのことを書いたが、FeliCa Linkのチップは2つあり、1つはRC-S967/1V、もう1つがRC-S967/2V。
違いは、1Vか2Vかだ。
RC-S730に載っているのは1Vの方らしい。
1Vと2Vの違いは・・・リーダライタ機能の有無

私のね・・・私の思っていたFeliCa Linkというのは、こんなに小さいのにR/Wまで載ってるなんてすごい!!だったのよ。
それがねー、ちょっとテンション下がったわー。
まあ、それは私の理解不足が原因だし、R/Wまでやろうとすると大変なのはなんとなくわかるんだけど。
でも私は夢を描いていたのだよ・・・。

まあ、無い物ねだりは、よそう。
FeliCa LinkのRC-S730とRC-S967/1Vには、リーダライタ機能は無い、と。
でもね・・・。


でもね、NFC-DEPはあるんだよ。
リーダライタができるんだからDEPもできるよなー、と思ってたけど、なくてもできるのだ。
ドキュメントに「イニシエータとしてのNFC-DEP通信はリーダ/ライタモードで行います」とあるから、RC-S730とかではターゲットとしてNFC-DEPになるのだろう。

んー、では、RC-S730同士ではNFC-DEPできないのだろうか?
できないのだろう。
ここ数年、SONYの技術資料を読んでいてわかってきたのだが、「できない」というのは書かないのだ。
こういう使い方はするな、というのはあるし、細かい部分になると ”これはできない”という記載もあったりするが、基本的に「これはできない」ということを書いていないのだ。
そこら辺が、SONYチップが敬遠される理由の一つかもしれん。クロノトリガーの話じゃないけど、あれくらいは書かないとな、といつも思う。

あ、「9.4 リーダ/ ライタモード付FeliCa Link同士の通信」という章があるので、そういう意味では今までのよりは親切かも。
しかし、この章のタイトルから「リーダ/ライタモードがついていないFeliCa Link同士ではNFC-DEPできない」ということを読み取るスキルが必要になるんだけどね。
ちなみに、普通に読み取るなら「両方にリーダ/ライタモードがついていると注意することがあるけど、そうでなければ注意しなくてよいよね」だ。

一応フォローするなら、「1.6.4 NFC-DEPモード」に「FeliCa LinkはNFC-DEP通信のターゲットとして動作します」と書いてある。
ただ、私に言わせれば、それは「NFC-DEPモード」ではなく「NFC-DEPターゲットモード」だ。


と、最後は文句を書いていたような感じになったが、FeliCa Plugと同じくらいのチップの値段でNFC-DEPターゲットになることができるとなると、用途は広がるんじゃなかろうか。
できれば、LLCP、いやSNEPまでサポートしてほしかったのだが、そこまでは難しいということですかね。

2014/07/24

[nrf51]今のFeliCa Plugの動き

現在実装できているところまでのFeliCa Plugがどう動くか、簡単に説明しておこう。
ソースファイルなどは、こちら。
https://github.com/hirokuma/nrf51822_felicaplug/tree/e43719514679f0515670656c582036a15e37e2af

ドキュメントフォルダの、FeliCa Plugの説明をがんばってるつもり。
Excelファイルは、これから作ろうとしているものについてなので、astaファイルを見るのがよいだろう。
だいたい、どういうことをしないといけないかとか、どこでどのくらい待つとかがわかるんじゃなかろうか。

これを実装して、FeliCa Plugを接続し、R/Wで読み込みを行うと、こういうデータになる。

image

注意としては、IDmだろうか。
私はスイッチサイエンスさんから購入したFeliCa Plugを使っているので、FeliCa Plugへの初期パラメータはこうしている。

static const uint8_t k_InitVal[] = {
    /* 各種設定パラメータ */
    0x03,                    /* データ転送設定 : FT転送設定        */
                            /* システムコード : 0x12FC            */
    /* 最大応答時間パラメータ */
    0xff, 0xff,                /* Read w/o Enctyption  : 255        */
                            /* Write w/o Enctyption : 255        */
    /* データフォーマットコード */
    0x00, 0x1c,                /* Switch Science社から購入の場合    */
    /* ユーザー設定パラメータ */
    'k', 'u', 'm', 'a'
};

データフォーマットコードが、スイッチサイエンスさんの場合は上記の値になっている。
そして、ユーザー設定パラメータは、とりあえず「kuma」にしてみた。

だから、IDmが

  • 03 FE : FeliCa Plugの値
  • 00 1C : データフォーマットコード
  • 6B 75 6D 61 : kuma

になっている。
まあ、03 FEで始まるのはFeliCa Plugだけということになってるから、気になる人はユーザー設定パラメータはランダム値にしておいてもいいかも。

Read w/o Encryptionで返す値は、無条件で0x00~0x0Fまでになっている。
これはfelica_plug.cのrecv_rwe()を見てもらえばわかるだろう。
Write w/o Encryptionしても、かならずステータスフラグは正常を返すようにしている。同じくrecv_wwe()。

ここまで動けば、あとはBLEを使うだけだ。
さてさて、どう料理しましょうかね。

2014/07/23

[nrf51]バグにも、よいバグと悪いバグがあってな・・・

FeliCa PlugからのSPI受信ができずに悩み続けた私。
原因を突き止めるべく、ロジアナの購入にまで踏み切った。
しかし、購入までには時間があるため、もちろんデバッグを続けていた。

のろのろ考えていると、隅にいた老人が声をかけてきた。
彼は紐を持った震える指で複雑で美しい結び目を作りながら、静かに話すのだった。

「バグには・・・バグにも、といった方がよいかな。
 バグにも、よいバグと悪いバグがあってな。」

私は彼が何を言い出すのかさっぱりわからなかったが、この薄気味悪い老人と話すのがよいか逃げるのがよいか決めかねていた。
というのも、薄気味悪い見かけとは違い、目はとても知的で澄んでいたためだ。
それがわかっただけに、さらに私は彼を薄気味悪く感じた。

そんな様子に気付いたかどうかわからなかったが、彼は続けた。
「よいバグなんてない、そう思ってるだろう?
 バグはすべて悪だ、と。
 わしも、若い頃にはそう思ったもんじゃ。
 君と違ってわしは血気盛んな方でな。
 まあ、今のこの姿からは想像もつかんと思うが」
そういうと、予想した以上に不気味な笑い声を静かに上げた。
立ち去ろうと思えばその瞬間だったのだろうが、私は彼が何を言い出すのか気になり、足を止めてしまった。

「でも、な。
 『これは悪いバグだ!』というのはあるじゃろう?
 見た瞬間に身の毛が総立つような、腐臭が漂ってくるような、そんなバグじゃ。

 ということは、じゃ。
 相対的に、よいバグというものもある、という証明にならんじゃろうか?」
なんとなく彼の言い分がわかったので、思わず聞いてしまった。
「爺さんが見たことある悪いバグって、どんなのだい?」

その声を聞いた瞬間だった。
老人から漂っていた不気味な雰囲気は消え去り、代わりに別の雰囲気をまとっていた。
こういえばよかろうか、悪魔的な、と。
予想できる以上に悪魔的な笑い声を続けた後、聞こえるか聞こえないかの声で囁いた。
「これじゃよ」

それは、私が見ていたディスプレイを指していた。
そしてその目線は、GPIOの割り込みハンドラ処理に注がれていた。
気になってそこを見ると・・・。

「あああああああああああ!!!!」

私は叫び声かうめき声かわからない音を放ちながら崩れ落ち、血の涙を流し始めた。
画面には、GPIOからの割込が立ったビットを受ける変数をビットマスク値で&&している様子が浮かび上がっていた。
それも、全部の条件式に。

血の涙を流し終わったときには、隅の老人は消えていた。悪魔的な雰囲気だけを残して。


えーっと、『隅の老人』はこんなお話じゃないのでご安心を。
では、バグの説明に入ります。

まずバグのコードを。

static void gpiote_event_handler(uint32_t event_pins_low_to_high, uint32_t event_pins_high_to_low)
{
    //立ち上がり
    if (event_pins_low_to_high && GPIOTE_MASK_IRQ) {
        fp_irq_assert();
    }
    if (event_pins_low_to_high && GPIOTE_MASK_RFDET) {
        LED_OFF(PIN_LED);
        fp_stop();
    }
    //立ち下がり
    if (event_pins_high_to_low && GPIOTE_MASK_RFDET) {
        LED_ON(PIN_LED);
        fp_rfdet_assert();
    }
}

これはGPIOTEの割り込みハンドラ。
GPIO Task Eventという名前なのだが、登録したGPIOピンに変化があったとき、event_pins_low_to_highには立ち上がりのピンが、event_pins_high_to_lowには立ち下がりのピンが、それぞれビットで入ってくる。
0x00000014だったら、bit2とbit4に1が立っているので、GPIO2とGPIO4に変化があった、という見方だ。

FeliCa PlugからのGPIO制御で割込監視するものとしては、/RFDETとIRQがある。
/RFDETはアクティブLOWで、搬送波検知を示す。
IRQはアクティブHIGHで、受信データ要求を示す。

おおよその使い方としては、こうなる。

  1. 搬送波が来るまで、省電力で待つ
  2. nRFDETがアサートしたら、FeliCa Plugの初期設定をして、コマンド待ち受け状態にする
  3. IRQがアサートしたら、FeliCa Plugからコマンド受信する(コマンド受信中にIRQはネゲートする)
  4. コマンドがRead w/o EncryptionかWrite w/o Encryptionか判断し、戻り値を返す
  5. 搬送波が無くなるまで、3~5を繰り返す

そして、上記の実装で動いていたのは、3のアサートしたら、までだった。
というのも、IRQが立ち上がってevent_pins_low_to_highに値が入ると、まず最初のif文に入り、fp_irq_assert()が実行される。
これは(if文の書き方はさておき)期待通りの処理だ。
しかし次のif文、ここにも入ってしまい、fp_stop()が呼ばれ、すべてのFeliCa Plugへの処理を取りやめてしまっていた。
入る理由は簡単で、&&でつなげていて、右も左も値が入っているからだ。
あーー、恥ずかしい・・・。

正解は、こう。

static void gpiote_event_handler(uint32_t event_pins_low_to_high, uint32_t event_pins_high_to_low)
{
    //立ち上がり
    if (event_pins_low_to_high & GPIOTE_MASK_IRQ) {
        fp_irq_assert();
    }
    if (event_pins_low_to_high & GPIOTE_MASK_RFDET) {
        LED_OFF(PIN_LED);
        fp_stop();
    }
    //立ち下がり
    if (event_pins_high_to_low & GPIOTE_MASK_RFDET) {
        LED_ON(PIN_LED);
        fp_rfdet_assert();
    }
}

「||」と「|」は間違えないけど、「&&」と「&」は間違えやすい気がする。
なんでだろう?
「if (abc & MASK == 0)」みたいな優先順位の間違いはしなくなったのにねぇ。

2014/07/22

[nrf51]初期パラメータ送信まではいけるが、受信ができない

FeliCa PlugのIRQは、有線データができたときにもHになるけど、SWをLにしたときもハイインピーダンスになるためかHに見えてしまう。
だから、IRQの立ち上がりだけで処理をするようにしていると、期待していない動作になってしまう。

というメモを見つけたので実装し直したら、搬送波検知をし直すたびにFeliCaランチャーが動作してくれるようになった。
ここまではいいのだが、その後がまだ動かない。

この後は、IRQ割込によってFeliCa Plugが持っているR/Wからの無線コマンドを取得するのだが、IRQ割込は来てるけれども、SPIの受信完了が上がってこない。

うーむ。。。
FeliCa Plugって、SPIっぽい通信ではあるのだけど、独自性が強いのよね。。。
データが送信と受信で同じポートになってるのだ。
クロックマスターはホスト側だから、FeliCa Plugの制御がちゃんとできていようといまいと、好きなだけクロックを出してポートからがんがんデータを吸えば終わりだと思うのだけど、終わった通知が来ない。


ということは、何かわからないけど、nRF51 SDKが期待している「終わり」になっていないということだ。
文章にしてみてようやく整理できたので、明日からはそこを見直そう。

2014/07/21

[nrf51]スケジューラを使ってGPIOハンドラからSPI転送するとHardFaultになった

nRF51822で、ボタンが押されたら、SPI転送をするような処理を書こうとしていた。
が、SPI転送の開始APIを呼ぶと、その中でHardFaultが発生していた。

発生しているのは、SPI転送spi_master.cの仲で割込を禁止しようとしているところのようだったが、原因がわからない。
つらつらとnRF51 SDKのHTMLドキュメントを見ていると「GPIOTEのハンドラは、スケジューラを使っていると直接GPIOTEの割り込みハンドラから呼ばれますよ」と書いてある。

割込禁止にしているところは、SVCALL()を呼び出しているところだった。
つまり、割込コンテキストからさらに割り込みを発生させようとしていたのでHardFaultになったということか?

調べてないけど、ありえそうな気がしてきたので、SPI転送をハンドラからメインループに移動させると動くようになった。
すっきりはしてないが、検索する語彙がわからないので、もういいや。


さて、そうしてようやくFeliCa Plugとお話しする環境ができてきたのだが、うまく動いてくれない。
初期パラメータの転送がうまくいってないのか、どこか待つべきタイミングを待ててないのか・・・。
というのも、デバッガで止めたりしているとFeliCaランチャーが反応することがあるからだ。
反応しないと言うことは、初期パラメータがうまく送信できてないのか・・・。
でも、nRF51822に電源を入れた直後だけは成功しているような気がするので、搬送波がOFFになったときの処理を間違っているだけかもしれない。

悩んでいてもしょうが無いからロジアナで波形を取ろうとしたのだが・・・使っていたカメレオンUSBのロジアナに入っているCypressのチップが最近では対応していなさそうで、ドライバが認識してくれなかった。
いろいろと動かせるようにしている人もいたのだが、すまん、私にはその根性が無かった・・・。
ロジアナの買い換えも検討していたところではあったので、これを機に買うことにした。
http://akizukidenshi.com/catalog/g/gM-04426/

来るまでの間に動いてしまうと残念かもしれないが、まあやれるだけはやってみよう。

[nrf51]待たせる

ちょっと待ちたい、ということがあると思う。
デバイスが安定するまで、とかなので、それほど正確じゃ無くてもよいけど、だいたいの精度を持ってくれてればよい、というくらいの待ち方。
タイマーをわざわざ使うまでも無いけど、じゃあ自分でループを作るかってのも面倒だし・・・。

FeliCa Plugの場合、搬送波検知した後にポートの設定をするのだが、そこから50usec待つことになっている。
その時間をどうやって待たせようか悩んでいた。

nrf_delay.h
static void __INLINE nrf_delay_us(uint32_t volatile number_of_us)

作る前でよかった。

2014/07/19

[ble][nrf51]nRF51822+GDBのやり方は、あまり的外れでも無かった

以前、こんな記事を書いた。
[ble][nrf51]gdbデバッグの設定がよくわからん

自分の中ではもやもやしたままだったのだが、Nordicのサイトにも同じような解決方法が書かれていた。https://devzone.nordicsemi.com/question/1566/uart-application-problem/

間違ってなかったんだ!
とはいうものの、SoftDeviceが変わるたびにアドレスを調べるというのもスマートじゃあ無い。

そこに「こっちはやった?」というリンクが書いてあった。
https://devzone.nordicsemi.com/question/825/strange-behaviour-with-nrf51822-and-s110/

loadしたあとにresetができてないのでうまくいってないっぽい、という見解だそうだ。
よくわからんが、まねをしてみた。

mon speed 10000
mon endian little
mon flash device = NRF51822
file "C:/Nordic Semiconductor/nRF51 SDK_v6.0.0.43681/Nordic/nrf51822/Board/nrf6310/s110/ble_app_beacon/gcc/_build/ble_app_beacon_s110_xxaa.out"
load
mon reset 0

fileとloadをはさんだだけ。あと、loadするチェックを外しておく。
・・・うん、うまくいった。ちゃんとmainでブレークしてくれたのだ。

とはいうものの、ここにフルパスで、しかもWindowsでやってるのにパスのデリミタを書き換えないといかんのもめんどくさい。
うー。

見解が「resetができてない」なら、うまくresetするようにすればよいのではないか?
ということで、SEGGERのドキュメントを眺めた。
UM08001に「Reset strategies」という章があり、Cortex-Mにはタイプが0~10まであることがわかった。

よく・・・わからないが・・・SoftDevice v7.0.0からブートローダーがどうのこうのといっていたと思うので、4, 5, 8くらいがいいんじゃないだろうか・・・。

mon speed 10000
mon endian little
mon flash device=NRF51822
mon reset 8

mainで止まったけど・・・あやしい。
というのも、その前にreset 4で試して止まったからだ。どうも、fileとloadでうまくいっていたときの名残かなんかみたいで、もう一度全部落としてやりなおしたらダメだったのだ。
うん・・・やっぱりダメだった。が、2回やるとmainで止まった。

よくわかりませんが、デバッグなんてしょっちゅうやるから、またいい方法が見つかったらお知らせしますかね。

2014/07/18

[ble][nrf51]eclipseでStandard GDBが出てこない

こんなQAを見つけた。

Problem running/debugging nRF51822 GCC example project

これによると、eclipse keplerでは DSFではなくStandardなGDB Hardware Debugging Lancherを使う、と書かれていた。

おお!
これが、私のところでGDBがうまくできていない理由か!?

そう思って探したのだが・・・

image

DSF以外はLegacyしかない。。。

長々と考えたが、そういえば私の使っているのはkeplerじゃなくてlunaだったことに気付いた。
なら、keplerのCDT + Hardware GDB DebuggingだったらStandardが出てくるのかと思ったが、やっぱりLegacyだった。

んん????

2014/07/17

[ble][nrf51]スケジューラーって、何よ?

まだ電池を使った開発をしているわけじゃないけど、消費電力にはケチな私。
消費電力を抑えるためには、個々の消費が小さいのはもちろんだけど、消費しなくてよいようなシステムにするのが一番なのよね。

それはともかく。
個々の消費電力を抑える一般的な考え方は、こうなるだろう。

  • なるべく長い時間、寝る
  • 用があるときになったら、起きる
  • 起きる時間は極力短くする

nRF51822の場合、動作クロックは16MHzで、低周波クロックとして32.768kHzがある。
感覚的にわかると思うが、32kHzで動く方が16MHzで動くよりも消費電力は少ない。
CPUとしては、動作するクロックの間隔が違うだけなので、同じことをするのに時間がよりかかるようになるだけだ。
まあ、機能によっては周波数が低いと動かせないものなんかもあるだろうが、まあ、そこは置いておこう。

「寝る」ときは、何もしたくないので、動作クロックは低い方にしておいた方が得だ。
でも、そこから「起きる」ことを考えると、簡単にはいかない。
寝てる状態から起きるためには、ハードウェアの力を借りることがほとんどだ。
だいたいが「割込み」を使うことになるだろう。
人間でいえば、たたいて起こすようなものか。

動作クロックを低くした状態で起こされたとき、それは非常に人間っぽい。
「なになに?」みたいな感じで、低い周波数で動くことになるからだ。
そこから、まずは動作クロックを高い方に持っていきたいだろう。
が、クロックは急には立ち上がらない。
それなりに動作が安定するまでに時間がかかるのだ。
安定するまで待って、動作クロックを高い方に切り替える、という感じか。
それに、「たたいて」から「たたかれた」がわかるまでも低い周波数で動くので、眠った状態からハイテンションになるまでには結構な時間がかかるのだ。

16000kHz・・・1クロックが62.5μ秒
00032kHz・・・1クロックが31.25m秒

単位がそもそも違うね。
マイコンとかの説明が、時間じゃ無くてクロックで書いてある理由がわかるであろう。
彼にとっての時間が「100」だったとしても、動かしている側から見ると、16MHzなら「6.25ミリ秒」で、32kHzなら「3.2秒」みたいなことになるからだ。


で、だ。
nRF51822だって、いやSoftDeviceだって、そういうことは十分に考えていると思うのだ。
BLEの「LE」はLow Energyなんだから、制御するSoftDeviceが電力制御をしてくれないと困るのだ。

s110のサンプルを見ていると、ぐるぐると監視するのではなく、スケジューラなるものを使っているっぽい。

static void power_manage(void)
{
    uint32_t err_code = sd_app_evt_wait();
    APP_ERROR_CHECK(err_code);
}
main()
{
    (略)
    for (;;)
    {
        app_sched_execute();
        power_manage();
    }
}

使っているようなんだけど、それが何をどうしてくれるのかわからない。

このまま泣き寝入りするしか無いのか・・・と思ったが、よく考えるとSoftDeviceの部分は非公開だけど、そうじゃない部分はかなりソースがあるんだった。
ただ、ここらへんは契約というか登録をしていないとダウンロードできないものだから、ここら辺に書くことができない。
うーん・・・nRF51822の普及をさせたいけど、SoftDeviceなしで話をするのは難しいから、どうやると深い話ができるんだろうか・・・・。

とりあえず、ここら辺のソースを実行すると、wfeを実行しているようだ、ということは伝えてもよいんじゃ無かろうかね。

2014/07/15

[ble][nrf51]SensorTag Beaconのふりをする

ドキュメントばかり読んできて飽きたので、ちょろっと動かすことにした。

s110のサンプルに、ble_app_beaconというのがあるので、それを動かしてみよう。
それだけだと面白くないので、SensorTagと同じデータを吹いて、iPad miniに入っているSensorTagのiBeaconアプリが反応するか見てみよう。

https://sites.google.com/site/hiro99ma/home/files/other/main_SensorTag.c?attredirects=0&d=1


これが変更したところ。
BVMCN51なので、32kHzは内蔵にした。

image

image

うむ、成功じゃ。

ただ、main()でブレークを張ることができなかったのよねぇ。。。
確認してないけど、release用のmakeをしてしまった、ということにしておこう。

[ble]Attribute Valueのサイズ

nRF51で何かやるんだったら、ServiceとProfileを作ることになりそうだ。
まあ、既存のServiceを使うんだったらProfileだけでいいんだろうけど、それだったら既存のProfileがあることが多そうだし、そうじゃなかったとしても自分で一手間加えたいからデバイスを作りたいんだろうし。

そうなると、Attributeってどういうことができるの?を知らないといかんだろう。
なので、まずはAttributeとして扱えるサイズを調べよう。

Core_v4.1のp.2121。
「3.2.4 Attribute Value」がよかろう。
サイズは固定か可変、となっている。
1回のPDUで転送できないなら、複数のPDUでやる、とも書いてある。LLCPとNFC_DEPみたいな関係か。

じゃあAttributeのサイズに制限が無いのか、というと、そうでもない。
p.2124に、512 octってあった。
これは・・・これは見逃すわ・・・。
まあ、あんまり長いと、途中で途切れてしまったときのリトライとかが複雑になるだろうから、ちゃっとやって、ちゃっと終わるのが理想だろう。

2014/07/14

[ble][nrf51]S110をひもとこう (4) - nAN36 - (6)

前回で、接続のところまでできたことになる。
あとは論理的なところか。



2.2 Generic Attribute profile(GATT)

どうでもいいことだが、これを普通に略すと「GAP」になってしまうのよね・・・。
GATTと同じルールで略すと、Generic Access ProfileはGACCだし。
GATTは「ガット」でよいけど、GACCは「ガック」になって、なんとなくがっくりしそうだからダメなのかな。


GATTはデータ値を実際に転送するレイヤー。

2.2.1 Roles

GATT ServerとGATT Client。
値を持っている方がServerで、アクセスしに行く方がClient。
LED Buttonアプリでは、PeripheralがServerで、CentralがClientになる。

2.2.2 GATT hierarchy

GATT Serverはattributeテーブルと呼ばれるデータ構造を持っている。
データ構造というか、attributeがデータそのものなのかな。

2.2.2.1 Attribute

attributeは、ハンドル、UUID、値で構成されている。
  • ハンドル
    GATTテーブルのインデックスで、デバイス内でユニーク。
  • UUID
    attributeが持つデータのタイプ情報や値を解読するためのキー情報。
    多くのattributeが同じUUIDを使うことになる。

2.2.2.2 Characteristic

characteristicは最低でも2つのattribute(declarationとvalue)を持つことになる。
GATT Serverが転送する値は、必ずcharacteristicに割り当てられる。
Core_v4.1のp.2181あたりに書いてある。
characteristic定義は、以下を含む。
  • characteristic declaration(p.2182)
  • Characteristic Value declaration(p.2184)
  • characteristic descriptor declaration(p.2184)
大文字始まりだったり、そうじゃなかったりしているが、なぜか値だけが大文字で書いてあるのだ。

2.2.2.3 Descriptors

characteristicのattributeに、descriptorというものがある。
Characteristic Valueに関連した情報みたいだ。
ただ、CCCD(Client Characteristic Configuration Descriptor)は別みたい。
S110では、NotifyかIndicateプロパティに自動的に付加されるとのこと。

2.2.2.4 Service

serviceは1つ以上のcharacteristicから構成される。
普通は、特定のセンサーの読み書きや設定のような感じでまとめたserviceにするのだけど、LED Buttonアプリはあまり気にせず、LEDとボタンをまとめたserviceにしておく。

2.2.2.5 Profile

profileは1つ以上のserviceから構成される。
profileはattributeがない。

2.2.3 Standard versus custom services and characteristics

省略

2.2.4 UUIDs

UUIDは128bitの値。

2.2.4.1 Bluetooth SIG UUIDs

Bluetooth Core Specificationでは、base UUIDと16bit UUIDで分けている。
0x0000xxxx-0000-1000-8000-00805F9B34FB
これは、Bluetooth SIGが使っているcommon base UUID(p.1864)。
例えばHeart Rate Measurement Characteristicは0x2A37なので、こうなる。
0x00002A37-0000-1000-8000-00805F9B34FB

2.2.4.2 Vendor specific UUIDs

SoftDeviceも、Bluetooth SIGと同じようなUUIDの決め方にしている。
base UUIDはnRFgo Studioで生成するらしい。
LED Buttonアプリでは「0x0000xxxx-1212-EFDE-1523-785FEABCD123」にしているとのこと。
serviceは0x1523、LED characteristicは0x1524、ボタン状態characteristicは0x1525。

2.2.5 On-air operations and properties

だいたいの操作は、attributeのハンドルとUUIDで行う。
characteristicを扱うのは、propertyに依存する。
  • Write
  • Write without response
  • Read
  • Notify
  • Indicate
これ以外にもあるけど、使うのはだいたいこんなもん。

2.2.5.1 Write and Write without response

GATT ClientがServerに書き込むことができる。
without responseの場合は、アプリレベルの承認や応答が無しになる。

2.2.5.2 Read

GATT ClientがServerの値を読むことができる。

2.2.5.3 Notify and Indicate

GATT Serverが変化をClientに通知することができる。
NotifyとIndicateの違いは、Indicateはアプリレベルの承認が必要で、Notifyにはそれがない。
LED Buttonアプリでは、こうする。
  • LED characteristicは、アプリレベルの承認が不要なので、Write without responseとRead property。
  • ボタン状態characteristicは、アプリレベルの承認は不要なので、Notify propertyのみ。



これで2章は終わりだ。
ようやく、4章の続きに戻ることができる。
もともとは、なんでService構造体にハンドルとかUUIDがいるの?という疑問だったのだけど、attributeの構造がそうなっているからなんですな。

4.4.3 Service Initialization

typedef struct ble_lbs_s {
    uint16_t                    service_handle;
    ble_gatts_char_handles_t    led_char_handles;
    ble_gatts_char_handles_t    button_char_handles;
    uint8_t                     uuid_type;
    uint16_t                    conn_handle;
    ble_lbs_led_write_handler_t led_write_handler;
} ble_lbs_t;
サービスが1つ、characteristicが2つ。
UUIDタイプは、sd_ble_uuid_vs_add()で設定するようだ。管理用かな?
この書き方はスニペットだ、と書いてあるので、従っておけばよいか。
なお、Base UUIDはnRFgo Studioで作るようになってるんだけど、これは単にUUIDの生成のためだけで、別にボードに書き込んだりするものではないようだ。
また、Base UUIDエンディアンはこの段階でリトルにしておくようだ。
でも、16bit UUIDは直値で書いている。これはnRF51822がリトルエンディアンで動いているからそれでよいってことかいな。
#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}



あとは実装の細かいところになるから、もういいかな。
と思ったんだけど、p.24が気になった。

4.4.4 Handling stack events

stackイベントは、なにかしらアプリケーションに通知する必要がある場合に発生する。
このアプリでは、LED characteristicに書き込んだとき(必要とするならば)。

4.4.4.2 Removing handling of CCCD writes

既存のイベントハンドラ(Battery Serviceのね)はCCCDへの書き込み操作をlistenするようにしてあるが、このアプリでは不要。
sd_ble_gatts_hvx()のドキュメントでは「CCCDが有効でないなら通知は許可しない」といっているので、このアプリではチェックしなくてよい。
訳し方が間違ってるような気がする・・・。
「if the CCCD is not enabled」って書いてあるけど、S110は自動でCCCDを付加するんじゃないっけ?
そうじゃなくて、そもそもCCCDへの書き込みを行わないから関係ない?
BASのCharacteristicを見ると、Client Characteristic Configurationへの読み書きが必須になっているな。今回作るサービスではCCCDがないから、書き込みを通知する必要は無いから、ハンドラは削除してよいだろう。
それはわかるのだが、sd_ble_gatts_hvx()がなんでCCCDの有無と関係するのかと、今回のサービスはCCCDが無いけどsd_ble_gatts_hvx()でエラーになるんじゃないのか、というのがわかってない。
NotifyかIndicateをサポートするcharacteristicでは自動的にCCCDを付加する、というのがあった、あれのおかげなのか?
じゃあ、sd_ble_gatts_hvx()がCCCDのチェックをすること自体、意味が無いだろうし。。。
とりあえず、この節で「ハンドラを外しましょう」といってるのは、on_write()に書かれているCCCDへの書き込みかどうかを判定する処理を指している、ということはわかった。

あとは、やっぱり自分で書きながら試した方がよさそうだ。
よさそうなのはいいんだけど、どちらかといえば問題になるのはCentral。
Nordicの評価ボードはUARTがついてるみたいで、それをCOMポートと接続してPCから制御できるようなのだ。
それがMaster Control Panelというアプリだと思う。
じゃあ使えんか、と思うのだが、Android 4.3用にnRF Master Control Panelというアプリがある。
これなら使えそうやん!と思ったのだが・・・Android Lのプレビュー版をインストールしたためか、インストールに失敗するようになったのよね・・・。
iOSにはMaster Control Panelに相当するものが無い。
うーむ。
まあ、LightBlueで十分な気もするんだけどね。
とにかく、Peripheralの開発にはCentralも必要になるので、手軽な使える環境を用意しておかないと。

2014/07/13

[ble]Connection State

GAPのところがどうも理解できなかったので、もうちょっと調べておこう。

Core_v4.1のp.2537あたりに説明がある。
この辺は、Link Layerのことが書いてあるところだ。


4.5 CONNECTION STATE

InitiatorがAdvertiserに対してCONNECT_REQを送信するか、AdvertiserがInitiatorからCONNECT_REQを受信したらConnection Stateになる。
くどい言い回しだが、前者はInitiatorがConnection Stateになるとき、後者はAdvertiserがConnection Stateになるときを指しているのだろう。
並列して書くんじゃなくて、Master目線とSlave目線でそれぞれ分けて書いてあるとよかったのだが。

この段階では、接続は「created」とは認識しているが「established」とは認識していない。
相手から初回のデータチャネルパケットを受信したときのみ、establishedと認識する。
違いがどこにあるかというと、Connection Supervision Timeout値を使うかどうかだ(4.5.2参照)。

masterデバイスは、Connectionイベントのタイミングを制御する。Connectionイベントとはmasterとslaveの同期を取るポイントである。

4.5.1 Connection Events

Connection StateになったLink Layerは、ConnectionイベントとしてData Channel PDUを送信する。
masterとslaveは、Data Channel Indexを4.5.8節のアルゴリズムで決定する。Connectionイベントでは同じData Channel Indexが使われる。最低でも1回はmasterからConnectionイベントが送信される。

(中略)

Connectionイベントのタイミングは、Connectionイベント間隔(connInterval)とSlave Latency(connSlaveLatency)で決定される。

masterはslaveにData Channel PDUを送信し始める(送信しはじめをAnchorポイントと呼ぶ)。
送信間隔は、connInterval。
connIntervalは、7.5msec~4secで、1.25msec刻み。

image

T_IFSはInternal Frame Spaceで、フレーム間は最低こんだけ空けなさいよ、という時間。
クロック精度とか温度とかの関係で、少し余裕を持たせておかないといかんのよね。
BLEでは、かBluetoothでは、かわからないけど、150usec。

Slave Latencyは、slaveがConnectionイベントの数を軽減するのに使う。
slaveが、masterからのConnectionイベントを連続して何回まで確認しに行かなくてもよいか、という値。
connSlaveLatencyは、0~(connSupervisionTimeout / connInterval) - 1で、500以下。
0だったら、slaveは毎回Anchorポイントを確認することになる。

image

もしSlave Latency決定後にmasterからパケットを受信できないことがあったら、masterからパケットを受信するまでSlave Latencyは0で動作する。

masterとslaveは16bitのConnectionイベントカウンタ(connEventCounter)を持っていて、最初のConnectionEventで0にする。
Connectionイベントごとにインクリメントして、0xFFFFの次は0x0000に戻る。
このカウンタは、Link Layerが同期を取るのに使う。

4.5.2 Supervision Timeout

相手がいなくなったと認識するまでの時間、でよいのかな。
TLLconnSupervisionというタイマで、6 * connInterval経過したら、そう認識するとのこと。

これとは別にconnSupervisionTimeoutという値があり、これはData Packet PDU間のタイムアウト。
connSupervisionTimeoutは100msec~32secの間で、10ms刻み。かつ、(1 + connSlaveLatency) * connInterval * 2以上。

 

connIntervalが1秒で、connSlaveLatencyを4にすると、下限はこんな感じか。

image

image

[ble][nrf51]S110をひもとこう (4) - nAN36 - (5)

以前、Excelで作っていた図があったので貼っておこう。
たぶん、BLEの大ざっぱな構成だと思う。
image
3つのブロックのうち、実装がいるのが一番上のブロックなのだろう。
つまり、今回のサンプルであるLED Buttonアプリが、Profileって書いている部分(ちょっとはみ出すんだろうが)辺りなのだろう。
Profileは、私の解釈では、プロトコルを含む機能、ということにしている。
1つのProfileは、1つまたは複数のServiceで構成されている。
なんでか知らないけど、Bluetoothフォーラムの上記リンクでは、ProfileとServiceが同じ表になっている。
でも、普通はProfileの話しかしないよな・・・
例えばANPはこんな構成。
image
ANP_SPEC_V10より
BLPは、こう。
image
BLP_V10r00より
数えると、Profileは10個、Serviceは14個あった。
S110のヘッダを見ると、提供しているのはProfileじゃなくてServiceのようだ。
ではBLEでやるのはこの14サービスから選ばないといけないかというと、そうでもない。
今回のLED Buttonも、Serviceを作るところからやる。
Serviceを作るということは、Profileを作るということにもなるだろう。


4.3 Set up

4.3.3 Setting up the service

Serviceのテンプレートは無いが、Battery Serviceがシンプルな構造なので、それをカスタマイズするのがよいだろう。
(githubの方は修正後の結果だけど、nAN36ではこれを作る過程から書かれている。 )
  • Source/ble/ble_services/ble_bas.c
  • Include/ble/ble_services/ble_bas.h
これを自分のところにコピーして、リネームする。
今回はble_lbs。

4.4 Implementing the service

Serviceは他のアプリで再利用できるように、汎用的な実装にする。
 

4.4.1 Designing the API

以下を書き換える。
  • uint32_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init);
  • void ble_bas_on_ble_evt(ble_bas_t * p_bas, ble_evt_t * p_ble_evt);
  • uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level);
これが、こうなる。
  • uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init);
  • void ble_lbs_on_ble_evt(ble_lbs_t * p_lbs, ble_evt_t * p_ble_evt);
  • uint32_t ble_lbs_on_button_change(ble_lbs_t * p_lbs, uint8_t button_state);
ble_evt_tはS110の構造体だが、それ以外は自由だ。
戻り値を取るタイプは、NRF_SUCCESSなどを返す。s110/nrf_error.hに定義があるので、見ておくとよいだろう。

4.4.2 Implementing data structures

ble_lbs_tやble_lbs_init_tのことについて。
BAS(Battery Service)の初期化構造体は、こう。
typedef struct {
    ble_bas_evt_handler_t         evt_handler;
    bool                          support_notification;
    ble_srv_report_ref_t *        p_report_ref;
    uint8_t                       initial_batt_level;
    ble_srv_cccd_security_mode_t  battery_level_char_attr_md;
    ble_gap_conn_sec_mode_t       battery_level_report_read_perm;
} ble_bas_init_t;
イベントハンドラ、オプションのパラメータ、初期値、セキュリティモードなど。
BASのService構造体は、こう。
typedef struct ble_bas_s {
    ble_bas_evt_handler_t         evt_handler;
    uint16_t                      service_handle;
    ble_gatts_char_handles_t      battery_level_handles;
    uint16_t                      report_ref_handle;
    uint8_t                       battery_level_last;
    uint16_t                      conn_handle;
    bool                          is_notification_supported;
} ble_bas_t;
イベントハンドラ、Serviceの状態、現在のバッテリーレベル通知ができるかどうかなど。
BASはServiceの開始から終了までの間、定期的にバッテリーレベルを通知するServiceだが、LED Button Serviceは期間ではなく単発だ。
LBSの初期化構造体は、こう。
typedef struct {
    ble_lbs_led_write_handler_t led_write_handler;
} ble_lbs_init_t;
LED状態を書き込むイベントハンドラがあればよい。
ハンドラの型というかシグネイチャも、特に規定は無く決められるようだ。
BASは
  typedef void (*ble_bas_evt_handler_t) (ble_bas_t * p_bas, ble_bas_evt_t * p_evt);で、LBSは
  typedef void (*ble_lbs_led_write_handler_t) (ble_lbs_t * p_lbs, uint8_t new_state);だ。
次のパラメータは「keep track of the state」のために必要。
えーっと・・・状態を追跡するため?
  • Serviceのハンドル
  • Characteristicのハンドル
  • Connectionのハンドル
  • UUIDタイプ
  • LED書き込みのハンドラ
これらをService構造体に持つことになる。
typedef struct ble_lbs_s {
    uint16_t                    service_handle;
    ble_gatts_char_handles_t    led_char_handles;
    ble_gatts_char_handles_t    button_char_handles;
    uint8_t                     uuid_type;
    uint16_t                    conn_handle;
    ble_lbs_led_write_handler_t led_write_handler;
} ble_lbs_t;

ここで休憩だ。
というのも、なぜ上記のパラメータを持っていないといけないかがわかっていないからだ。
ようやく私も、ここらへんでBLEってものを学ばないといけないと気付いた次第である。
適当にやっていた2章を見直そう。

2 Introduction to Bluetooth low energy

ここの図を見て、今回の最初に描いていた絵の意味がわかった。
あれは、BLEのプロトコルスタック構造なんだ。
上から順に、Profiles、Host、Controllerというレイヤーみたいだ。

2.1 Generic Access Profile (GAP)

GAPはアプリとのインターフェースになる最下層のBluetoothスタックだ。
パラメータとして、govern advertisingとconnection among other thingsを含んでいる。
うーん、伝わらない・・・。
詳細はBluetooth Core SpecificationのVolume 3 - Part Cに書いてあるらしいから、覗いてみよう。
このProfileは、以下に関する一般的な手順を定義する。
  • Bluetoothデバイスの検索(idle mode procedures)
  • Bluetoothデバイスの接続管理(connectiong mode procedures)
わかるような、わからんような。
とにかく、Generic Access、だから、一般的なアクセス、ってことか。
全部理解しようと思ったら、日が暮れるどころか今年が終わってしまいそうなので、このくらいにとどめておこう。

2.1.1 Roles

BLE接続(BLE link)を行ったり管理したりするのに、roleを決めないといけない。
接続に先だって、CentralかPeripheralかを決定しておく。Centralは接続しに行く側で、Peripheralは接続される側。
これはLink Layerだと、MasterとSlaveという用語になる。
うん、前に調べたことがある
そもそもというか、S110はPeripheral用のSoftDeviceなので、今回はPeripheralということになる。
GAPのRoleとしてはこれ以外に、BroadcasterとObserverというものがある。
BroadcasterはAdvertisingイベントを出すデバイスで、ObserverはAdvertisingイベントを受信するデバイス。
接続は確立させないと書いてあるので、これがBeaconってことかな。
個人まとめ
  • 接続を確立させるなら、Central-Peripheralの関係
  • 接続を確立させないなら、Observer-Broadcasterの関係

2.1.2 Advertising

PeripheralはCentralとの接続のために、20ms~10.24sec間隔でAdvertisingパケットを送信する。
接続前のCentralはAdvertisingパケットを受信するだけだし、接続前のPeripheralはAdvertisingパケット送信後の短時間のみ接続要求の受信確認(listen)を行う。
Advertisingパケットは31バイトまでのデータを含めることができる。
CentralはAdvertisingパケットを受信すると、Scan要求という、「まだAdvertisingデータがあるなら送れ」要求を送信する。
これは「Active Scanner」になっているときだ、と書いてある。
Core_v4.1のp.1930では、ScanningタイプとしてPassiveとActiveが書いてあり、Centralとしては「PassiveをサポートしているならActiveの方はオプショナル、PassiveをサポートしていないならActiveは必須」と書いてある。
p.1255では、LE_Scan_Typeの定義があり、デフォルトは0x00でPassive、0x01がActiveで、SCAN_REQを送信する、と書いてある。
p.2506にはAdvertising PDUの種類が4つある。
  • ADV_IND
  • ADV_DIRECT_IND
  • ADV_NONCONN_IND
  • ADV_SCAN_IND
このADV_SCAN_INDを受けとったときにSCAN_REQする・・・のかと思ったが、p.2527に表があった。
image
ADV_INDかADV_SCAN_INDのときにSCAN_REQできる。ADV_SCAN_INDは接続できないタイプなんだな。

2.1.3 Scanning

Scanningは、CentralがAdvertisingパケットを確認することとScan要求を送信すること。
「Scan Window]と「Scan Interval]という時間のパラメータがある。
Centralの動作だから、今回は気にしなくてよいかな。
Interval間隔でWindow時間だけ確認する、という動作じゃなかろうかね。

2.1.4 Initiating

Centralが接続しに行くのは、Advertisingパケットを確認するためにScanningするのは同じ手順だ。
Centralが、PeripheralからのAdvertisingに対して接続要求を返す。
NFCだと、R/WをInitiatorって呼ぶのと似たような用語だな。
あ、ここら辺のタイトルになっているScanningとかInitiatingとかは、Core_v4.1のp.2499にある図のStateと一致している。
image
Centralは、Standby→Scanning →Standby→Initiating→Connection、という流れ。
Peripheralは、Standby→Advertising→Connection、という流れ。
だから、次の節は・・・

2.1.5 Connection

接続だ。
定義としては、CentralとPeripheralが最初のデータ交換をしてからがConnectionになる。
Connection状態になると、CentralはPeripheralからの要求に対してデータを要求する。要求するのだが、それは「Connection Interval」と呼ばれる間隔で行われる。この間隔はCentralが決めるのだけど、PeripheralはCentralに対してConnection Parameter Update Requestを送信することができる。
接続間隔は、7.5ms~4sec。
Peripheralが「Connection Supervision Timeout」と呼ばれる時間以内に応答しなかったら、リンクは失われる。
「Slave Latency」の説明もあるけど、よくわからん。Core_v4.1のp.1295からすると、0~499の値を取る。
p.2550の図にタイミングが書いてあるんだけど、見てもわからんし、latencyが載ってない。
image
p.2549では、Connectionのパラメータとして
  • connInterval
  • connSlaveLatency
  • connSupervisionTimeout
が上げられている。LL_CONNECTION_UPDATE_REQをCentral→Peripheralに送る(Link Layerの話なので用語としてはMaster→Slaveになる)。その時間では動けない、とPeripheralが判断したら、CentralにConnection Parameter Update Requestを送信する、ということなのかね。
Connection Parameter Update Requestは「新しい接続パラメータを送ってくれ」と要求するもののようだ(Core_v4.1 p.1718、2000)。L2CAPのコマンドみたい。CentralやPeripheralがConnection Parameter Request Link Layer Control procedureをサポートしてないときに送るものらしいが、送るのはPeripheralからみたいだ(BroadcasterやObserverはサポートしない)。
image
シーケンス図がほしい・・・。



長くなったので、ここで2.1章は切ろう。
次はGATTなんだけど、ここも理解できるか心配だ。。。












2014/07/12

[ble][nrf51]S110をひもとこう (4) - nAN36 - (4)

さあ・・・いろいろとある個人事情だが、技術は突き詰めないとすっきりしないので、気にせず行こう。
博多近辺で、NFCとBLE好きな人を募集している方は・・・どうぞ(2014/07/12)!


4.1.2 Code flow

基本的なBLEアプリの流れは、こうだ。

  1. 必要な部品を全部初期化
  2. advertisingの開始(可能なら省電力動作をしてBLEイベント通知を待つ)
  3. イベントを受信したら、全BLEサービスとモジュールを有効にする

4.1.3以降は、かなり環境依存の話が出てくる。
まず、4.1.3はkeil(IARでもeclipseでもないが、メジャーな統合開発環境)だ。
私がIARやkeilを使ってないのは、単にお金だけの話だ。
仕事でやるなら、どちらかを選ぶだろう。ARM社のコンパイル環境が手に入れば別かもしれないが(RealViewとか?)、私がお遊びで作る環境であれば、そんなに大きなサイズのプログラムを書くとは思えない。
SoftDevice S110 v7.0.0でも88KBくらいだったと思うので、私が40KB書くか・・・書かないな。
じゃあkeilでもなんでもいいのだろうけど、じゃあeclipseでもいいよね、というところだ。

仕事でならお金を払ってもよいと思う理由は、お金を払わなかったときに発生するリスクとどちらが高いかを考えたときに、どっちが安いかということだろう。
あと、わからんことは聞けるし。その時間とお金は、かなり釣り合うと思っている。原因がわからずに1日うんうんうなるよりも、数時間1万円で解決できるなら安いもんだ。

家でやってるときだと、悩んでる時間も楽しいときがあるから、そのお金がもったいない。


今日はここまで。

というよりも、後の部分はコードの説明なので、あんまり面白くなさそうな。
それよりは、これをベースにコメント付きのソースファイルを書いた方が、まだ面白そうだ。

何をどうすれば動くか、が最初にあって、何がどうあって動くのか、が次にあるとよいのかな。

2014/07/11

[ble][nrf51]S110をひもとこう (4) - nAN36 - (3)

nRF51822のアプリケーションノートnAN36を読んでいる。
この中では、LED Buttonというアプリを例に説明しようとしている。
lbs、という名前がときどき出てくるのでプロファイルの1つか何かかと思ったら、Led Button Sampleなのかな?
ソースは以下にある。
https://github.com/NordicSemiconductor/nrf51-ble-app-lbs


4 LED Button application example

4.1 Code overview

4.1.1 Code separation

LED Buttonアプリは、他のSDKサンプルと同じ構成になっている。

  • main.c
  • ble_lbs.c, h

main.cはアプリ的なものを実装し、それ以外はservice的なものを実装している。
I/Oの振る舞いはアプリ側。

nRF51822で動くアプリは、次の部品に分かれる。

  •  Hardware registers
    • nrf51.hに定義してあるレジスタにnrf51_bitfields.hで定義してある値を書き込む。
      今回のサンプルには、この部分は無い。
  • SDK modules
    • レジスタ設定をラップしたマクロを使う。nrf_gpio.hなんかがそう。
  • Softdevice functions
    • SoftDeviceの設定をする。SoftDevice関係のAPIはsd_で始まる。

BVMCN5102の外部16MHz起動なんかは、よくわからんのでレジスタを直接設定した。
32kHzの方はSoftDeviceの初期設定マクロ(SDK modulesってやつか)でできたので、16MHzもなんか用意されているような気がしなくも無い。


今日はここまで。
ちなみに、全38ページのうち、今は16ページくらい。
動作確認が6ページくらいあるので、半分くらいだな。

2014/07/10

[ble][nrf51]S110をひもとこう (4) - nAN36 - (2)

誰のためにというわけでもなく、自分のために記録している。
だってねぇ、忘れると思うから。
後から読み返して、これとこれはやらなくてもよかったな、と思うかもしれない。
そういう記録なのだ。

では、SoftDevice S110のためにアプリケーションノートnAN36を読んでいこう。
今日は3章が読み終えたらいいな、というところ。


3 Minimal BLE application overview

最小限なにをしないといかんか、という説明だ。

 

3.1 Overview of initialization

ここには概要の説明が表形式で並んでいる。
「Initialization call」「Ways to achieve this」「In LED Button demo app」の3列になっているのだが・・・どう感じるとよいのか。
「やりたいこと」「有効にする方法」「LED Buttonアプリでの実装箇所」くらいか。

やりたいこと 方法 実装例
BLEを有効

・SOFTDEVICE_HANDLER_INIT()
・sd_softdevice_enable()

ble_stack_init()
イベントハンドラの追加 SOFTDEVICE_HANDLER_INIT() ble_evt_dispatch()

 

やりたいこと 方法 実装例
デバイス名の設定 sd_ble_gap_device_name_set() gap_params_init()
adveertisingデータの設定 ・ble_advdata_set()
・sd_ble_gap_adv_data_set()
advertising_init()
接続パラメータ ・ble_conn_params_init()
・sd_ble_gap_ppcp_set()
conn_params_init()

 

やりたいこと 方法 実装例
serviceの追加 sd_ble_gatts_service_add() ble_lbs_init()
characteristicの追加 sd_ble_gatts_characteristic_add() ble_lbs_init()

 

やりたいこと 方法 実装例
advertising開始 sd_ble_gap_adv_start() advertising_start()

 


すまん、今日は力尽きたのでここまで。

しかし、3章の説明はほぼこのくらいで終わりだ。
最近流行りのBeaconはadvertisingだけで終わるけど、connectしてからが面白そうだと思っているので、BLE自体をもう少し理解しないといかんですな。

2014/07/09

[ble][nrf51]S110をひもとこう (4) - nAN36 - (1)

S110を理解するのに、アプリケーションノートnAN-36がよさそうだと思った。
読むところは30ページくらいなので、ちょろっと眺めてみよう。
今はv1.1だ。

書いていくのは、翻訳ではなく意訳。
それに、興味があるところとか、うまく読めたところしか書かない・・・書けない・・・。


1.4 nRF51822 and the S110 SoftDevice

S110 SoftDeviceはBLE Peripheralプロトコルスタックソリューションである。
プリコンパイルされたHEXファイルで提供され、自作のプログラムを動かす前に焼かれてないといかん。

SoftDeviceのFLASHとRAMは、自作アプリから保護されている。

 

1.5 Application overview

LED Buttonアプリというサンプルを作ることで、どうやってnRF51822のBLEを使うかを学ぼう。
このサンプルは、BLEでそうほうこうの通信を行うアプリだ。アプリはCentralからLEDを制御されるし、nRF51822に接続したボタンを押すと通知を受信することができる(receiveって書いてあるけど、ボタン押下でnotification送信するのでは?)。

アプリは、1サービス、2キャラクタリスティック(LED制御とボタン押下通知)を実装する。

 

2. Introduction to Bluetooth low energy

ここは、BLE自体の説明をしている章。

2.1 Generic Access Profile (GAP)

2.1.1 Roles

今回のサンプル、LED ButtonアプリではPeripheralの役割ですよ、ということ。

2.2 Generic Attribute profile (GATT)

2.2.1 Roles

LED Buttonアプリでは、PeripheralがServerで、CentralがClientですよ、ということ。

2.2.2.2 Characteristic

LED Buttonサービスでは、LEDとボタンには関連がないので、それぞれ好きに変更できる。
なのでキャラクタリスティックは、ボタンの状態とLEDの状態で分離させておく。

2.2.2.4 Service

LED Buttonアプリでは、LEDキャラクタリスティックとボタンキャラクタリスティックの再利用などは考えず、両方とも1つのサービスとしてまとめておく。

2.2.2.5 Profile

LED Buttonアプリでは、profileは正式ではない(not formally described)。

2.2.3 Standard versus custom services and characteristics

標準とカスタマイズのどちらがよい?という話。
Bluetooth SIGはprofile, service, characteristic, attributeなどをたくさん用意しているが、BLEのserviceはスタックじゃなくてアプリに実装していくものだ。
アプリがprofileとserviceをサポートするので、アプリがカスタムserviceを用意した方がよい。
(ここ、非常に不安な訳だ)

LED Buttonアプリでは、Bluetooth SIGのserviceを使っていない。

2.2.4 UUIDs

2.2.4.2 Vendor specific UUIDs

このアプリでは、0x0000xxxx-1212-EFDE-1523-785FEABCD123がベース。

serviceは0x1523、LED characteristicは0x1524、ボタンcharacteristicは0x1525。

2.2.5 On-air operations and properties

2.2.5.3 Notify and Indicate

アプリでは、LED制御とボタン状態のキャラクタリスティックがLED Buttonサービスで使われる。

LED characteristicでは、Centralが「値の設定ができるか」と、「読み出しができるか」を求める。
アプリの了解は必要ないので、Write without responseとReadプロパティが使用できる。

ボタン状態characteristicでは、Clientが「ボタン状態の変化を通知されるか」を求める。アプリの了解は必要ない。
Notify propertyが必要とする。


ここで今日は終わり。

読みながら「ああ、BLEの知識が私にはないんだな」と思った。
まだ、GATTとかCharacteristicなどが体になじんでこない。

いつか・・・いつかBLEが身になじむことを信じて!

2014/07/07

[ble][nrf51]こんな感じでLED点滅

app_buttonを有効にするには、app_button_enable()を呼ぶ必要があった。
タクトボタンでうまくいったので、FeliCa PlugのnRFDETに接続した。
最初は、時間の設定が長かったためかうまくどうさしなかったが、短くするとLEDが点滅するようになった。
 

 

初めて動いたんだから、動画くらい撮っても罰は当たるまい。
と思ったけど、なんか動画が再生できないな。
まあいいや。

動画が見えた人も・・・見ても何だかわからないと思う。
PaSoRiを止めると、ちゃんと点滅も停止するんだけど。。。

2014/07/06

[ble][nrf51]S110をひもとこう (3) - button

では改めて。
SoftDevice v7.0.0 + nRF51 SDK v6.0.0の組み合わせで見ていこう。

といっても、動かしながら調べた方がわかりやすいと思うので、ひもとくというか、実践だな。


まずは、ボタン処理。
以前作った回路では、FeliCa Plugの搬送波検知によってLED点灯させるようになっている。
この「搬送波検知」は、ボタンのON/OFFと同じなのだ。
処理としては、こうやっている。

    while (true) {
        nrf_gpio_pin_write(PIN_LED, nrf_gpio_pin_read(PIN_RFDET));
    }

PIN_RFDET(GPIOのinput)を読んで、PIN_LED(GPIOのouput)に書き込んでいるだけだ。
これをwhileでやっているので、電気を無駄に使っていることだろう。
それに、そのままポート出力させているけど、実際にはチャタリング処理をやってやりたいところだ。

この辺りのことを、「button handling library」がやってくれそうである。
チャタリングって、debouncingっていうんですな。
GPIOTE Handlerを使えば良いらしい。TEは、Task Eventみたい。

 

と、nRF51 SDKのドキュメントには書いてあり、app_gpioteとかAPP_BUTTONとか書いてあるのだが・・・。
SDKのサンプルソースにあるgpiote_exampleでは、nrf_gpioteを使っている。
nrf_gpiote.hは「GPIOTE abstraction」らしい。抽象化したもの、か。
これはnRF51シリーズ内で抽象化している、ということかな。

nRF51を使うということはBLEを使うことになるし、BLEを使うということはSoftDeviceは組み込むことになる。
もうあれこれ考えず、S110限定で見ていこう。
そうやってサンプルを探すと、s110フォルダ内のものはだいたいAPP_BUTTON_INIT()を使っている。
これをまねすれば良いだろう。
まあ、やるならば、ble_app_templeteをコピーして、いるところだけ残していく方が賢いかも。

 

さて、まねをしてはみたものの・・・動かない。
イベントハンドラに飛んでくれない。
エラーになるわけでもないので、どこが悪いかよくわからん。
タイマがうまく動いてないんじゃないか、という気がするのだが、はてさて、どこから見ていくのが良いやら。

[追記:2014/07/07]
app_button_enable()が必要だった。
とりあえずFeliCa Plugではなく、タクトスイッチで試したところ、それでうまくいった。
nRFDETはプルアップだったのでそのまま使っていたのだが、ボタンはアクティブHIGHでつなげたので、それで安定せずに変な動きをしていたのだが、PULLDOWN指定することで意図した動きをするようになった。


そういえばSDK v6.0.0からmakefileが変わって、使うライブラリは自分でソースを追加してやらないといかん、と前に書いたけど、あれは勘違いだったな。
前からmakefileにはアプリ側で追加してやるようになっていた。
すまん、SDK...

[android]Nexus7 2013にAndroid L previewを入れた

特に何をしたというわけでもないが、Android Lっていうのがインストールできるようだったのでやってみた。

バッチを動かすと、system.imgがメモリ不足で焼けないとか出てきたので、個別に焼いた。

fastboot flash boot boot.img
fastboot flash recovery recovery.img
fastboot flash cache cache.img
fastboot flash userdata userdata.img
fastboot flash system system.img

 

4.4のbackupを取っていたので、restoreして戻したところだ。
「ok google」っていうと、検索が出てきた・・・昔からだっけ?
Siriも声をかけると自動起動するようになったけど、ずっとマイク拾ってるのかいな。
電気食いそー。

あと、設定画面の見栄えが変わった。
リストの見栄えが変わったのか?
とにかく、こんな感じ。

image

下側の黒っぽい山みたいなのは、バウンスというのか、あの状態。
指の位置で山が動く。山というか、波っぽい感じだな。

ステータスバーが、4.4だと右と左で降りてくるものが違ったけど、また1つに戻った。
それはいいんだけど、通知を一気にクリアする方法がわからん。

 

全然これとは関係なく、バックアップの仕方を間違っててデータが消えてしまった。。。
Nexus7って外部SDがないからshared指定をしてなかったんだけど、内部SDを含むんだね・・・。

[ble][nrf51]nRF51 SDK変わりすぎ・・・

では、デバッグできるようになったのでFeliCa Plugをつなげてた続きをやろうとしたが・・・makeが通らない。。。

nRF51 SDKがv6.0.0になったのだが、Makefile.commonの書き方が変わったようで、各プロジェクトで必要になるSDKソースファイルを組み込むようになったみたいだ。
うーん、ちょっと変わりすぎだろう・・・。
[追記]これは、以前からそうなっていた! すまん、勘違いだった。。。

お遊びで使ってるからいいけど、仕事でやるんだったら難しいだろうな。
SoftDeviceが新しくなったから差し替え、というわけにはいかんので、それなりに検証し直す必要がありそうだ。

とりあえずビルドできるようになったので、記録としてgithubに置いた。
https://github.com/hirokuma/nrf51822_felicaplug


あと、これは解決できたこと。
デバッグするたびにcleanしてビルドし直されるのでめんどくさいと思っていたのだが、Configurationの設定がallになってたせいだった。

image

[ble][nrf51]gdbデバッグの設定がよくわからん

よくわからんシリーズだ。

nRF51822ドキュメントの中にGDB + CDTでのデバッグ方法が載っているのでそのままやっていたのだが、mainに行く前にHardFaultで死んでしまう。
SoftDevice v6.0.0のときは動いていたので、いろいろさまよっていたのだが、どうもGDBの設定に関係がありそうだ、ということがわかったのが昨日のこと。

よくわからないけど、こういう設定にしたらmainで止まってくれるようになった。

image

変更したのは、Runtime Optionsだ。
前は、Set breakpoint atにmainを設定してたのだけど、それを外してSet program counter atを設定するようにした。

このアドレスは何かというと、SoftDevice v7.0.0のHEXにあった0x0000_0004~7の値だ。
Cortex-M0とかは、起動時に最初の4byteをSP、次の4byteをPCとして設定するので、じゃあPCを設定したらそこに止まってくれるかな?と期待して設定したというわけだ。

実際には止まらず、なぜかmainで止まるようになった。
正直なところ、さっぱりわからない。。。
このチェックを外して、tbreak mainとか直書きしたけど、それもだめだった。
アドレスを0にしたら、それはそれでダメだった。

なので「この設定値以外でも動くかもしれないけど、とりあえずmainで止まった」という状況だ。

2014/07/05

CDTのIndexer

あまりeclipseを使わないから、と前置きしておこう。

S110のサンプルプロジェクトをCDTで展開すると、main.cにいっぱいエラーマークが表示された。
どうやら、Includeパスとかで見つけられなかったAPIやマクロにマークがついているようだ。
Makefileでは解決できているので問題はないのだけど、エラーマークが出ているのは精神的によろしくない。
チェックを外せばいいんだけど、せっかくなのでチェックしたままエラーをなくそうとした。

まず、プロジェクトプロパティでパスを設定。
nRF51822へのパスは、プロジェクト相対でだいたいあってるのだが、GCCのパスが絶対になっていて、私はそこに置いていなかったためエラーになっていた。
それは、設定すればよし。
nRF51822のパスでも、いくつか設定されていないものがあったので、それも追加すれば良い。

それでも、2つほどエラーが残った。
マクロのところだったからincludeが足りないのかと思ったがそうではなく、マクロが参照している関数が見つからないようだった。
その関数のプロトタイプ宣言をマクロの前に追加すれば、エラーは消える。

 

消えるんだけど、これはIndexerの限界なんだろう、と思った。
というのも、関数の定義はマクロの後にちゃんとあるからだ。
ビルド時の処理の流れだと、プリプロセスの展開→ビルド、となるので、マクロも展開されるけど、includeも展開されるので、ヘッダファイル内でマクロの後に関数定義があっても問題がない。
でも、たぶんIndexerはincludeの展開は直接行わないのか、あるいは展開処理の順序があまりうまくいっていないとかじゃないのかね。

そういう意味では、わざわざライブラリのヘッダを変更してまでエラーを取ってやらなくてもいいんじゃないか、と思わなくもない。
たぶん、次にやるときは、もったいないけどエラーチェックを外すだろうな。

[ble][nrf51]なぜか普通に動いた

昨日からデバッグをせずに情報集めをしていた、SoftDevice v7.0.0。

さっき、久々に動かすと・・・SPの値がまとも。
もちろん、mainまで動く。

なんじゃそりゃああああああ!!!!!

環境変数がうまく反映されてなかったとかか?
なんかもう、すごい脱力感。

 

あれ、もう一度やったら、またHardFaultした。
よくわからないが、GDB Hardware Debuggingの設定で、Runtime Optionsの「Set breadpoint at」でmainを指定していたのだが、それをはずして、「Set program counter at」を指定すると、なんか知らんけどmainで止まるようになった。
何が何だか、さっぱりわからない・・・・。

とりあえず、SoftDeviceがどうのこうのというよりも、GDBをうまく動かせていない、ということらしい。
SoftDevice関係の方にはご迷惑をお掛けした m(_ . _)m

が、GDBの疑問は残るので、これでよしとしてよいかがわからん。

2014/07/04

[ble][nrf51]softdevice v7.0.0はどう焼けば良い?

なんか、BLEとかnRF51とかに全然関係なくなってきたが・・・仕方ない。

まず今朝の復習から。
HEXファイルのデータは確認したが、アドレスはツールに任せていた。
INTEL-HEXフォーマットの書式で確認しておこう。

:02 0000 04 0000 FA
:10 0000 00 C0070000D1060000D1000000B1060000 CA

一番先頭の2行。

  • 最初はデータ長(赤文字のバイト長)
  • 次はデータレコードのアドレス
  • 続いてレコードタイプ
  • データ
  • チェックサム

うん、アドレスは0x0000_0000で、最初は0x0000_07C0だ。
でもね、S130のHEXも同じくらいのアドレスなんだよ。
間違っているとは思えない。
それに、もしSPのアドレスが違うのであれば、デバッガを外して起動したとしても動かないはずだ。

じゃあ、SPがどのくらいのアドレスだったらいいんだろう、というところから考えてみようか。
とりあえずRAMは、0x2000_0000から16kB分しかない。
だから、0x2000_0000~0x2000_3FFF、でいいのかな(計算苦手)。
逆立ちしても、0x07C0なんてアドレスにRAMはいない。

 

うーーーーーん、まだわからん!
SPに実はオフセットレジスタがあって、その値を加算したアドレスにアクセスする、とかいうシナリオも考えたけど、そういう記述は見つけられていない。
あるのはせいぜい、アプリ用とシステム用で2セット持てる、というくらいだ。

VectorTableの先頭値を、あんなRAMでもない値にしておく理由が思い当たらないのだ。
なんか、気付いてしまえば大したことがないことだった、みたいなところにいるんじゃないかという気もする。

2014/07/03

[ble][nrf51]S110 v7.0.0のリリースノート

S110 v7.0.0のリリースノートを読んでいる。
昨日、nRFgo Studioで焼くときに「Enable protectionってなんだろう?」と思っていたことと関係があることが書かれていた。

まず、Enable protectionについては、nRFgo Studioのヘルプファイルに書かれていた。

  • もしsoftdeviceのCLENR0(code-length value)が未定義なら、サイズを指定する。
    • HEXファイルにCLENR0がないので、ここではサイズしか設定できない
  • もしsoftdeviceがUICRのかわりにCLENR0を持っているなら、”Enable SoftDevice protection”チェックボックスを使って、CLENR0をUICRにコピーするかどうか選択できる。
    • DFUを使うなら、チェックを外す

うーん、いちいちわからん。
わからんが、リリースノートも見ておこう。

  • SoftDeviceのサイズは88kBと大きくなった
  • FWIDはもうUICRに書き込まれない。この変更に互換性を持つアップデートされたnRFgo StudioやnrfjprogはNordicのサイトからダウンロードできる。
  • SoftDeviceのHEXは、UICR.CLENR0レジスタを含まない。つまり、SoftDeviceはデフォルトでprotectedではない。アップデートされたnRFgo StudioやnrfjprogはデフォルトでUICR.CLENR0レジスタにSoftDeviceのサイズを書き込む。それによって、デフォルトのprotectionを実現している。protectionを有効にするとオリジナルサイズよりも大きいサイズのSoftDeviceをDFUで書き込むことができなくなる。よって、ツールがUICR.CLENR0レジスタへ書き込む動作はオプションとした。
  • sd_softdevice_forward_to_application()はsd_softdevice_vector_table_base_set()に置き換えられた。

うーーーん。。。

製品とかで書き換えをあんまりやりたくないなら、UICR.CLENR0レジスタには書き込まない方がよい、つまりEnable protectionにはチェックしない方がよい、ってことかしら。「DFUでは」って限定なのかな。

DFUもよくわかってないが、汎用のFLASH書き込みのしくみ、みたいなイメージでいるんだけど、ちゃんと調べておかないと失敗しそうだ。

UICR : User Information Configuration Register。アドレスは0x1000_1000。
CLENR0 : Length of code region 0 in bytes。FICR.CODEPAGESIZEの整数倍。

この「region」ってのが、0と1とあって、それぞれのregionで動いているコードからは他のregionへの書き込みができないようだ。
それが「Enable protection」ってことかね。
なら、JTAGとかなら関係はないから、どっちでもいいってことか。


では、今朝は終わりにするが、最後にS110 v7.0.0のHEXをバイナリ変換して、ベクタテーブルを見ておこう。

image

やっぱり、0x0000_07c0やん。
これだと、SPにこの値が入っているのは当たり前だ。

ちなみに、S110 v6.0.0は、こう。

image

そうそう!
そういうのを求めているんだよ!!

 

じゃあ、どうするのが正しいんだろう。。。。
なんか、新しいものがさらにリリースされるとか、何か見忘れてるとか、そんな感じがする。
少なくとも、S110 v7.0.0のHEXをRegion 0に書き込んでもだめだということはわかった。
アプリをRegion 0に、SoftDeviceをRegion 1に、とかか??

2014/07/02

[ble][nrf51]開発環境アップデート(そして失敗)

環境を作ったばかりだったが、nRF51の新しい環境が出てきたので、今のうちにアップデートしておこう。
アップデートのペースを確認してないんだけど、頻繁じゃなかったら良いなあ。


まず、nRF51 SDKがv6.0.0になった。
これは、S110 v7.0.0になってるとのこと。
うん、確かにincludeフォルダが一致していた。
しかし、includeフォルダ(SDK展開後だとinclude/s110)だけ見ても、S110のどのバージョンかわからないのよねぇ。
どこ見たらいいんだろう?

細かいけど、SVDフォルダに入っているxmlファイルも微妙に変わっていた。


次は、うちの環境に合わせる。

まず、ARM-gccのパス設定。

C:\Nordic Semiconductor\nRF51 SDK_v5.2.0.39364_Backup\Nordic\nrf51822\Source\templates\gcc
Makefile.windows

サンプルの、nrf51822/Board/nrf6310/s110/ble_app_hrs/main.cを書き換えて、内部32Kクロックに変更。

image

今回からMakefileにいくつか種類があるようなので、どれかをコピー&リネームしてMakefileにする。
C:\Nordic Semiconductor\nRF51 SDK_v6.0.0.43681\Nordic\nrf51822\Board\nrf6310\s110\ble_app_hrs\gcc

そして、ビルド。
デバッグ設定はoutファイルのパスが変わっているので(以前のhrsデバッグ設定が残っていれば)、変更しておこう。


nRFgo StudioでS110 v7.0.0を焼く。
こうなった。
Enable SoftDevice protectionって、チェック外したけどよいのかな?

image

あれ、Unknownって出てるぞ??

Enableうんぬんをチェックしてなかったせいか?

image

Regionが0になったけど、それだけ。
Verifyしたけど成功するし。
うーん・・・。

こう思うことにした。
私がインストールしているnRFgo Studioは、まだファームウェアIDが0x004Dまでしか対応してないんだ。
v6.0.0は0x004Dだったからファームウェア名も表示できたんだけど、v7.0.0は0x004Fになってて、対応する文字列がないからUnknownになってるんだ。


S110 v7.0.0になってからSoftDeviceのサイズが大きくなり、それによりリンクするアドレスも変わってくる。
これは、gccのtemplateを使っている場合は、v7.0.0用に差し替わっているようだ。

だから、このままビルドしてデバッグ実行すれば動く!・・・
動かない。

image

main関数にすら止まってくれない!
何か失敗した??

でも・・・デバッガをはずして、BVMCN5102にだけ電源を供給すると、無線が出てる。
焼けてはいるってことかい?

 

1つ気になっているのは、Makefile.commonが変更になっていて、allの動作が「clean debug」から「clean release」になっていること。
でも、eclipseのデバッグ設定で、ConfigurationはDebugにしてるんだけどな・・・。
あ、かといって、それが聞いているとも限らないか。

しかし・・・debugに変更してもダメだった。
これだと思ったんだけどなぁ・・・。

休憩。


よくわからんが、gcc_startup_nrf51のスタートアップからSystemInit()に飛んだ後、

push {r7, lr}

とやってるんだが、これがだめみたい。
pushの引数はreglistで、pushしたいレジスタを並べるだけみたい。
push先は、SP(r13)。
今のSP=0x7c0。
nRF51822のメモリマップを見ると、RAMは0x2000_0000から始まっている。
でも、gcc_nrf51_s110_xxaa.ldでは、RAMは前と同じく0x2000_2000からになっている。

いやいや、もしSPの設定が間違ってるんだったら、デバッグ起動しようと通常起動しようと、動くはずがないじゃないか。
くー、悔しいけどわからない・・・。


まず、SPを疑ってみよう。

Cortex-M0の場合、SPのデフォルト値はベクタテーブルの先頭にある32bit値らしい。
スタートアップルーチンを見ても、SystemInit()を呼ぶまでの間にSPを設定している様子がないので、デフォルト値そのままなのだろう。

    .globl __Vectors
__Vectors:
    .long    __StackTop            /* Top of Stack */
    .long   Reset_Handler               /* Reset Handler */
    .long   NMI_Handler                 /* NMI Handler */
    .long   HardFault_Handler           /* Hard Fault Handler */

ベクタテーブルは、こんな感じ。
ふむ、悪くない。
では、値となる__StackTopはどうなっているか。
mapファイルで見よう。

.stack_dummy    0x20002de8      0x800
*(.stack*)
.stack         0x20002de8      0x800 _build/gcc_startup_nrf51.o
                0x20004000                __StackTop = (ORIGIN (RAM) + 0x2000)
                0x20003800                __StackLimit = (__StackTop - SIZEOF (.stack_dummy))

うーん、メモリマップから見てもまともだ。
でも、Vectorsのアドレスはgcc_nrf51_s110_xxaa.ldのFLASHなので、0x0001_6000なのだ(v7.0.0)。

じゃあ、起動時のベクタテーブルはどうなってるかというと、たぶん0x0000_0000。
そこは、SoftDeviceを書き込んでいるところなのか?

image

image

だめだ、今日はここまでだ。

[ble][nrf51]S110をひもとこうとしているのに・・・

nRF51822のS110のことを調べようと思った途端、SDKがv5.2.0からv6.0.0にアップされた。
以前はS110 v6.0.0ベースだったが、今回はv7.0.0ベースになっている。

うーん、v7.0.0で調査をしていくのが良いのか・・・。
ヘッダファイルの差分を取ったが、doxygenタグを追加しただけとか、マクロ定義を括弧でくるんだだけ、というほほえましいものもあるのだが、enumが追加されていたり、その追加位置が途中だったりするものもある。

enumの追加は仕方ないとしても、途中に入れ込むと値が変わるからダメだと思うんだがなぁ。
値が変わると、ビルドし直さないといけない。
SoftDeviceの良いところは、静的にリンクしないってところにもあると思ってたんだけど、英語の読み違いかしら。。。

そしてさっき、SoftDevice S110ドキュメントの変更履歴を見て、1.3よりも1.3Aの方が古いことに気付いた。
なんだよー、AとかBとかは原本の改版バージョンじゃないのかよー!
会社によってドキュメントがいろいろ違うから、気をつけないとな。

2014/07/01

[ble][nrf51]S110をひもとこう (2)

S110 v6.0.0を見ていこうと思ってたんだけど、今日Nordicからメールが出ていた。
S130がalphaながらも出たってことと、S110 v7がアップデートされたということ(ドキュメントも)。

S130はいいとして、S110 v7はどれが最新なんだ?
先週見たものとバージョンが同じっぽいのだが、ユーザ登録したからメールが来たというだけなのかな?
v7はなんでも、OTAによるアップデートができるらしい。FOTAか。
FLASHが256KB、RAMが16KBなんだけど、どうやるんだろうね。