2015/10/13

[nrf51]Notifyを出すタイミングはどこだ?

未だに正式名称がNotifyなのかNotificationなのかわかっていないけど、とにかくそれを出したい。

いま、つくっているのはServer側なので、通常はClient側が取りに来る。
でも、Server側から通知することもできる。
それがNotifyだったりIndicateだったりする。

定期的に、AD変換する。
その開始トリガは、タイマだ。app_timerだ。
タイマが満了すると、ADCを開始する。
変換が終わると割込が来る。
そのタイミングでNotifyを送信したいのだ。

が、やってみると、sd_ble_gatts_hvx()で止まってしまった。
感覚的なものだけど、ハードウェア割り込みの中でソフトウェア割り込みをやろうとしてもうまくいかないだろうなぁ。


「ばかたれ! 曖昧なところを残して作業するな!!」というおしかりが聞こえてきたので、もう少し調べよう。

まずADCの割り込み優先度だが、NVIC_SetPriority()でNRF_APP_PRIORITY_HIGHになっている。
この値は、1だ。
もう1つの定義値NRF_APP_PRIORITY_LOWは、3だ。

これが何の値かというと、リファレンスマニュアルのこれに当たる(見たのはv2.1)。

image

青いのがアプリで、ピンクがSoftDeviceだろう。
Notifyの要求はSVCなので、ADCのNRF_APP_PRIORITY_HIGHよりも低くなっている。
これがダメだった原因だろうか?
もしそうなら、ADCの優先度をLOWにすればよいはずだ。

試してみると、今度は固まらずにエラーが返ってくるようになった。
0x3401。
えーっと・・・

#define NRF_ERROR_STK_BASE_NUM   (0x3000)
#define NRF_GATTS_ERR_BASE   (NRF_ERROR_STK_BASE_NUM+0x400)
#define BLE_ERROR_GATTS_SYS_ATTR_MISSING   (NRF_GATTS_ERR_BASE + 0x001)

ということで、System Attribute Missingか。
またか

いや、それよりも、割り込みハンドラからSVCしても大丈夫なんだ、という方が衝撃だった。
本を読んでいるが、SVCは同じ優先度内で使うと(つまりSVCハンドラ内)、用法フォールトということで固まるらしい。
用法フォールトハンドラが未定義なら、ハードフォールトハンドラが呼ばれるとのこと。
今の作りはまさにそうなので、ハードフォールトが呼ばれたのだろう。

ただ、優先度の違いがあるだけでハードフォールトになるのは納得いかない。
優先度が違うだけなら、優先度が変わるまで保留されるべきではないのか?

そう思って説明を読むと、より優先度が高い例外が発生すると用法フォールトは保留される、とある。
この動作によりハードフォールトになったというのであれば、納得だ。

 

まだ、いろいろ把握できていないところがあるねぇ。


[2015/10/14]
いや、ちょっと待ちたまえ。
ちゃんと文章を読むと「用法フォールトは保留される」というだけだ。
用法フォールトより高い優先順位は、全部フォールト系だ。
優先度が変わるまで保留されるのが普通なのだ。

というわけで、nRF51のリファレンスマニュアルをちゃんと読もう。

Exception (interrupt) management with a SoftDevice

SVC APIの実装とアプリ依存のリアルタイム性を満たすために、SoftDeviceは図76の例外モデルを実装している(上の図ね)。
次のガイダンスに従ってアプリが使う割り込み優先度を決定するようにすべし。
SoCライブラリが持つNVIC APIはその辺を安全にやってくれる。

Cortex-M0は0~3の4段階の割り込み優先度をつけられる(0が一番高い)。
リセット時はすべて0になっている。

  1. LowerStack
  2. Application High - App(H)
  3. UpperStack(SVC)
  4. Application Low - App(L)
  5. MAIN

一番高いLowerStackは、リアルタイムプロトコルタイミングのためにSoftDeviceが確保している。
なので、アプリが使えないようになっている。

SoftDeviceはUpperStackも確保している。
この優先度は、より高いレベルで、遅延可能なSoftDeviceタスクやSVC割込で実行されるAPI関数などで使われる。

アプリ向けには、App(H)とApp(L)、あとはバックグラウンドレベルのMAINがある。

App(H)はSoftDevice用の割込の間にある。
これはアプリの割込で遅延を短くしたい場合に使用できる。
App(H)はLowerStackの割込があったときだけ遅延するし、App(L)はLowerStack、App(H)、UpperStackの割込があったときに遅延する。

訳は適当だが、画像の内容をそのまま表現したようなものだな。

これよりも少し前にApplication Program Interface(API)の章があり、そこでは

SoftDevice API functions can only by called from lower interrupt priority

とある。
うーん、やはりそういうものなのか?
手元にあるのがCortex-M3の本なので、そこらへんがCortex-M0は違うということか??

 

こちらが、Cortex-M0の例外一覧(DDI0419Cより)。
image

うん、用法フォールトとかそういうのは無いのですな。。

"Priority escalation"の章に、

もしSVCallの優先度グループが現在の優先度グループ以下だったばあい、HardFault例外が発生する

とある。
そうか、そういうCortex-M0の仕様なのですな。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。