2014年11月29日

[nrf51]ADCにチップバージョンでの差違あり

Blogs - Nordic Developer Zone - Using the ADC with the S110 SoftDevice

今のところ予定はないが、センサーを扱いたいとなるとAD変換を使うこともあろう。

制約としては、まず以下があるとのこと。

  • ADCの割り込み優先度をLOWにする
  • PPIチャネルで0~7を使う(8~15はSoftDeviceが使っている)
    SoftDeviceの初期化前に自分で直接設定するか、nRF51 SDKのsdppiラッパAPIを使う

 

これだけでなく、nRF51の第2世代と第3世代のハードウェアには制限があるとのこと。
世代は、ドキュメントのPANを見ると、チップの表面に書いてあるとのこと。
しかし、私が持っているのはモジュール製品で、nRF51822はカバーに覆われて見ることができない・・・。

どうも、ドキュメントのPSのバージョンとハードウェアのバージョンが一致しているように見える。
今はnRF51822_PS v3.1が最新なのだけど、それはrevision 3、つまり第3世代のドキュメントのようだ。
最新版が出たからって、前のドキュメントは捨てたらいかんな。

たぶん、時期的に、うちのはrevision 2だろう。
BLEの1パケットでだいたい1msecブロックするらしい。なので、例えば6パケット送信するのであれば6msecブロックするので、

1 / 6msec = 0.1667kHz = 167Hz

ということか(ブログでは、だいたい150Hzって書いてる)。

ここでの表現が「sampling frequency」なんだけど、アプリがADCできる間隔じゃなくて、本当にサンプリング周波数がこうなるってことだろうか?
Nordicのサンプルプロジェクトを見たが、時間に関する設定はなさそうで、100msec間隔でADCする、くらいのことしかないみたいなので、あまり周波数が高くないものだけにするか、速くしたいんだったら外部に任せるかになりそうだ。

[keil]32KBの壁はどこにある?

「keilのフリー版は32KB制限がありますよね」という記事を書いていたのだが、読んでくださった方々から情報をいただいた。
ありがたやありがたや。
私があんまり社交的じゃないためか、このブログはマイナーなんですよ。
ときどき、閉鎖して本業に集中しようかとも思うけど、見てくださる方がいるのであれば、もうちょっと続けようかという感じでやっとります。


さて、本題。

hiro99ma blog: [ble]BLEモジュールを使った場合のがんばりどころは?

コメントをいただいた中で、誰もが「32KBを超えても大丈夫だった」ということだった(2人しかコメントがないが、これを「誰もが」と書くことで、すごく多くの人がコメントをくれたようなイメージを与えるテクニックだ)。

では、試してみなくてはならぬ。

まず、32KB、がどこを指しているのか。
ARM KEIL組み込み開発システム 統合開発環境 <MDK-ARM 正規代理店>|横河ディジタルコンピュータ株式会社
こちらの表を見ると、デバッガ、シミュレータ、そしてコンパイラが32KBとのこと。
しかし、コンパイルのどこら辺が32KBかは、見てもわからない。

セカンド・オピニオン (412) MCUで遊ぼう Part2 (3) | マイナビニュース
これを読むと、コード/データが32KBとある。
プログラムは基本的にROMとRAMの2つに分かれるが、ROMもデータとプログラムに分かれる。
RAMも、初期値があるものと、ないものに分かれる。
初期値があるものは、その初期値自体はROMに置かれることになる。じゃないと、初期値を保持しておくところがないからね。
C言語では、初期値を持つ変数というのは、staticなものしかない。
そのstaticな変数の中でも、初期値を代入しているものは「初期値あり」だが、代入していないものは「ゼロ」になる。
だから、staticな変数であっても、初期値の有無でROMのサイズが変わってくる。

なんでこんなことをごにゃごにゃ書いたかというと、32KBのROMをどうやったら作り出せるか、ということを考えていたからだ。
プログラムを書いて32KB作るのは、けっこう難しい。
できれば、var[32768]みたいな感じで、楽に32KBを作りたい。
でも、staticとかvolatileとかつけても、単に宣言しただけだとRAM領域の話になるので、コードサイズにならない。
初期値がないから、ゼロになるだけだ。
私が見たことのあるコンパイラだと、main()が呼ばれる前にmemset()とか、あるいはアセンブラなどでゼロ埋めするものがほとんどだったが、オプションによってゼロ埋めする処理すら省略するものもあった。

我々が求めているのは、ゼロ以外の初期値を持つ変数だ。
そうなると、初期値の部分がROMに配置されるので、今回のコードサイズ制限を調べるのに役立つ。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[256 * 1024 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

16byteのFILL16を、16個並べたFILL256を、4つ配置。これでFILL1K。
とりあえずエラーを見てみたいので、これを16個並べたら、16KBだからよさそうだけど、エラーになった。

Build target 'Target 1'
compiling main_32k.c...
main_32k.c(15): warning:  #177-D: variable "jan" was declared but never referenced
        uint8_t jan = mem[256];
main_32k.c: 1 warning, 0 errors
linking...
.\Objects\test.axf: error: L6047U: The size of this image (268436284 bytes) exceeds the maximum allowed for this version of the linker
Finished: 0 information, 0 warning, 0 error and 1 fatal error messages.
".\Objects\test.axf" - 1 Error(s), 1 Warning(s).
Target not created.

でたー。
これが、maximumなエラーメッセージらしい。
少し満足。

まあ、256 * 1024 * 1024だと、どの環境でもエラーになりそうよねぇ、ということで、32KB制限近くでやってみた。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[31 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

これのビルド結果は、こう。

Rebuild target 'Target 1'
compiling main_32k.c...
main_32k.c(15): warning:  #177-D: variable "jan" was declared but never referenced
        uint8_t jan = mem[256];
main_32k.c: 1 warning, 0 errors
assembling arm_startup_nrf51.s...
compiling system_nrf51.c...
linking...
Program Size: Code=598 RO-data=31970 RW-data=4 ZI-data=4196  
FromELF: creating hex file...
".\Objects\test.axf" - 0 Error(s), 1 Warning(s).

この、memの31を32にすると、リンクエラーになった。

Rebuild target 'Target 1'
compiling main_32k.c...
main_32k.c(15): warning:  #177-D: variable "jan" was declared but never referenced
        uint8_t jan = mem[256];
main_32k.c: 1 warning, 0 errors
assembling arm_startup_nrf51.s...
compiling system_nrf51.c...
linking...
.\Objects\test.axf: error: L6047U: The size of this image (33596 bytes) exceeds the maximum allowed for this version of the linker
Finished: 0 information, 0 warning, 0 error and 1 fatal error messages.
".\Objects\test.axf" - 1 Error(s), 1 Warning(s).
Target not created.

こっちが、warningだけだったコード。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[31 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

こっちが、エラーになったコード。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[32 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

違いは、memの添字になっている値が、31か32か、だ。

こうやって見る分には、ちゃんと32KBで制限がかかっていると感じます。


翌日。
飲みながら調べると、なんかいろいろ馬鹿なことやってるなー、と反省(したふり)。

リンクができる境界を調べて、以下のソースになった。
配列の202を203にすると、リンクエラーになる。

static const unsigned char mem[31 * 1024 + 202] = {0};
int main(void)
{
    return mem[0];
}

image

mapファイルのお尻だけ拾うと、こんな感じ。

      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   
       594         88      32170          4       4196       7352   Grand Totals
       594         88      32170          4       4196       7352   ELF Image Totals
       594         88      32170          4          0          0   ROM Totals
==============================================================================
    Total RO  Size (Code + RO Data)                32764 (  32.00kB)
    Total RW  Size (RW Data + ZI Data)              4200 (   4.10kB)
    Total ROM Size (Code + RO Data + RW Data)      32768 (  32.00kB)

配列の要素数は、1024 * 31 + 202だから、31946。
mapでは32170になってるから、あと224バイトはコード以外のROMデータがあるらしい。

      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Object Name
        84         36        192          0       4096        648   arm_startup_nrf51.o
        12          6      31946          0          0       2055   main_32k.o
       232         30          0          4          0       4241   system_nrf51.o
    ----------------------------------------------------------------------
       328         72      32170          4       4096       6944   Object Totals
         0          0         32          0          0          0   (incl. Generated)
         0          0          0          0          0          0   (incl. Padding)

incl. Generated、というのが32バイトあるらしい。
ARMのヘルプを見ると、これはリンカが生成したオブジェクトらしい。

ともかく、うちで試した限りでは32KB制限というのは発生していることが確認できた。

 

{0}なのに初期値ありとみなされるんだ、というのが多少ショックだった。
前見たコンパイラは、{n}のような感じでnに数値を入れるとmemset(0)で勝手に0初期化してたのだ。
組込用のコンパイラだったから、それを正とみなしてたらいかん、という教訓を得た。

2014年11月28日

[android]AndroidStudio 1.0 RC2が出ていた

Windowsにも、Android Studio 1.0 RC 2が出ていた。

image

前がどんなのか忘れたけど、あか抜けた感じがしますな。
あか抜けてない私が言っても説得力ないですが。

image

 

既存のプロジェクトを開くと、エラーが出た。
こちらを参考に修正すると、よさそうだった。
Android Studioでmethod not found: 'runProguard()'発生 電脳羊(Android Dream)/ウェブリブログ

ファイルを開いて、runProguard を minifyEnabledに変更し、設定をrecommendのものにしただけで、ビルドは通った。
動かしてはいないけど、まあいいや。

2014年11月26日

[c/c++]enumはプリプロセスでは評価できません

「何を当たり前のことを」と言われそうだが、まあ聞いておくれ。

今、BLEの再履修をしているところだ。
一通り小さなサービスを動かしてきたことになるので、始めた当時にはよくわからなかったものが、今では理解できるようになったかもしれない。
私の場合、学習→試作→学習→試作、を繰り返すような感じで物事を把握することが多い。
なんというか、覚えるときは紙に目一杯書き込まないと覚えられないような、体で感じるタイプらしい。

 

まあそんなわけで、BLEのことを調べ直しているのだが、設定できる値の範囲が気になってきた。
例えば、connIntervalは7.5msec~4secの間だ。
これをS110とかでは、こんな表し方になる。

#define CONN_MAX_INTERVAL               MSEC_TO_UNITS(1000, MY_UNIT_1_25_MS)

MSEC_TO_UNITS()はapp_util.hにあるマクロで、こんな定義だ。

#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION))

なんでこんな式かというと、connIntervalは7.5 + 1.25n、というBluetoothの仕様になっているからだ。
TIMEはmsec単位なので、それを1000倍して割る。
ということは、全体としてはμsecになってしまうので、そうならないようにRESOLUTIONも1000倍された値を使う。
「どうせconnIntervalなんて固定値でしか持たないだろうから、そこまでやらなくていいんじゃないの」と思ったが、実装にも仕様にも固定じゃないといかんというわけではなく、もしかしたら普通は曜日や時間帯に合わせて可変にするものだけど、サンプルだから固定にしているだけなのかもしれん。

 

前置きが長くなって済まん。
nRF51で使うconnInterval値の範囲は6~3200になるのだが、そういうマクロ値が既に定義されていることを知った。
BLE_GAP_CP_MAX_CONN_INTVL_MINが6で、BLE_GAP_CP_MAX_CONN_INTVL_MAXが3200とか。
ならば、コンパイル前に定義値の範囲チェックをしておけば、変なバグで悩むことが減るんじゃなかろうか、と思ったのだ。

それで、こんなチェックマクロを埋め込んだ。

#if (CONN_MAX_INTERVAL < BLE_GAP_CP_MAX_CONN_INTVL_MIN)
#error connInterval_Max(Connection) too small.
#elif (BLE_GAP_CP_MAX_CONN_INTVL_MAX < CONN_MAX_INTERVAL)
#error connInterval_Max(Connection) too large.
#endif  //CONN_MAX_INTERVAL

 

メモリを消費するでもなく、ビルド段階で範囲チェックができてよかろう、と満足したのだが、これがgccでエラーになるのだ(他のは知らん)。
さんざん悩んだが、結果としてはこのせいだった。

enum {
    UNIT_0_625_MS = 625,
    UNIT_1_25_MS  = 1250,
    UNIT_10_MS    = 10000
};

えっ、ここにenum使ってたの??
なんでまた・・・。

#defineはプリプロセス段階で展開されるけど、enumはコンパイル時に展開される。
だからプリプロセスとしては、MSEC_TO_UNITS(1000, MY_UNIT_1_25_MS)みたいなenumを含む式を見つけると、展開できないという扱いにしてしまい、ここではゼロとみなして「ゼロで割ってます」というエラーになっていたのだ。

まあ、enumにするとデバッガなどで値が見やすくなるのはあるけど、ここでは使ってほしくなかったなぁ。
せっかくdefineがあるけど、ここは自分で7.5msecとか4secとかの定義値を作って、値でチェックする方式に置き換える方がよさそうだ。
時間かかったわー。

2014年11月24日

Excel2013のコンテキストメニューが薄い

何も解決しない話になるが、Excel2013のコンテキストメニューの文字色が薄い。

image

使えるのは濃いグレーで、使えないのは薄いグレー。
どうにもコントラストが低く、最初見たときは全部ディセーブルなのかと思ったくらいだ。

テーマを変えても色が変わらないので、どうしようもなさそうだ。
Window自体も、アクティブと非アクティブでタイトル文字色しか変わらないので見分けづらい。
Excelの機能に不満はないけど、ちょっとこれはねぇ・・・。

2014年11月23日

[nrf51]iBeaconとNordic

別にNordicに限定したことじゃないが、iOS8からiBeaconの仕様が変わったらしく、今のところNordicのVendor IDはCore Location Frameworkではじかれているらしい。

Nordic beacons and iOS

 

iBeaconのパケット仕様は、もともとAppleからは出てなくて、どちらかというと「こういうAdvertisingデータを流すと反応してくれた」みたいな感じだったのではなかっただろうか。
少なくとも私は、Appleの技術ドキュメントからは見つけられていない。

んで、いつしかMFi対象になってた。
あんまりわかってないけど、Advertisingのデータに書いてあるだけで、それが平文だったら、普通にスキャンしてまねすればだませてしまいますわな。
なので、自由度はなくなってしまうけど、まあAppleなら仕方ないかな、というところか。

2014年11月22日

[android]LollipopのFOTAがNexus5に来たが、TeamWinだったので失敗した

白いNexus5を使っているのだが、昨日の朝、出勤前にLollipopのアップデートが来ていることに気付いた。
ヨドバシの480円SIMを使っているので、外に出てしまえば200kbpsになるため、家の中でダウンロードだけしておきたい。

そう思ってダウンロードは成功して再起動させたのだが、アップデートは始まらずにteamwinって出てきた。
よくよく思い出すと、SMS無しの契約のためセルスタンバイが気になり、root化して押さえ込んでいたのだった。
こういうときは、どうしたらいいんだろう?

 

調べると、recovery領域をオリジナルに戻せばよいようだった。
では、と、Lollipopのイメージを持ってきて解凍し、recovery.imgを焼いて再起動!
そしてリカバリモードにしたのだが・・・ドロイド君が横たわって赤い三角が出てる。
ネットだと、ここにメニューが出てくるような感じで書かれているのに。。。

やっぱり今インストールされてるのと同じじゃないとだめなのか、とKitkatのイメージからrecovery.imgを持ってきて、焼いて再起動してリカバリモード!
・・・同じだ。

もうあきらめて全部焼き直そうかと思ったが、よくネットに書いてあることを読むと、ボタンの操作をしないとメニューが出てこないとか。
昨日なのでうろ覚えだが、確か電源+音量上ボタンの同時押しだったと思う。
そうすると、出てきた。
まあ、私がリカバリモードで何かしたいわけでもないので、焼くものが間違っていなければよいだけだ。

普通にAndroidを起動させ、システムアップデートを促す画面に行くと再起動ボタンがあったので、タップ。
そしたら、自動的に再起動して、今度はごにょごにょとアップデート作業が始まった。

初めてだから、仕方ないよね。


Lollipopだが、あのイースターエッグ画面というか、あそこに入っているLollipopゲーム。
あれは、Nexus5の方がNexus7よりもやりやすかった。
私でもN5なら3点取れた! (レベル低い。。。)

2014年11月18日

[nrf51]UARTログを使い、bonding時のイベントが見えたような気がした

BLEイベントハンドラの各caseにログを埋め込んだところ、bondingしたときに通知されるイベントの順番がわかった。
こんなに簡単に使えるなら、最初からやっときゃよかった。

advertising start
BLE_GAP_EVT_CONNECTED
BLE_GAP_EVT_SEC_PARAMS_REQUEST
BLE_GAP_EVT_AUTH_STATUS

ただ、すぐにDISCONNECTが通知されてしまった。
私の予想では、続けてSEC_INFO_REQUESTが来るはずだったんだが・・・。

そして、その次のCONNECTでは、すぐにSEC_INFO_REQUESTが通知された。
んんん?

advertising start
BLE_GAP_EVT_CONNECTED
BLE_GAP_EVT_SEC_INFO_REQUEST

何度か試したが、これはnRF Master Control Panelアプリを使ったときの動作のようだ。
CONNECTする画面があるのだが、そこで「bond」を選択すると、bondingだけ行うようなのだ。
だから、すぐに切断しているのだろう。

その状態で接続しに行くと、SEC_INFO_REQUESTが来ているような気がするのだけど、そうじゃなくても元々CONNECTできるということもあり、なんだか訳がわからなくなってきた。
ここら辺は、資料からお勉強することになりそうだ。

2014年11月17日

[nrf51]何故simple_uartは38400bps固定なんだろうか

nRF51822の動作をデバッガでブレークポイント使って止めながら見ていたのだが、そろそろ限界になってきた。
SDKがassertionを起こすのだ。
src/rem.cなるファイルだと言ってくるのだが、SDKの中にはなさそうなので、よくわからん。

それに、通信系のデバッグで片方が止まってしまうと、相手側も無応答とみなしてエラー扱いにするだろうから、ログを出しながら確認するのがよいだろう。
そういうわけで、デバッグ用にUARTを組み込むことにした。


ざっとSDKを見ると、simple_uart.hというものがあり、実装例もあったので、それを使うことにした。
configのパラメータでピン設定すると、あとはput/getすれば使えるというシンプルさ。

しかし・・・なぜか通信速度の設定などがない。
ソースを見ると、38400bpsで動くように実装されていた。
いくらシンプルとはいえ・・・。

動作クロックのつごうかとも思ったが、リファレンスマニュアルを見てもあまりそんな感じがしない。
嫌だったら自分で組めばいいやん、ということにはなるけど、でもこの実装になっているのは何か意図があるのか・・・。

気になるが、寝よう。

2014年11月16日

[nrf51]bondingされないけどconnectできる

BLEイベントとしてBLE_GAP_EVT_SEC_PARAMS_REQUESTが来たとき、sd_ble_gap_sec_params_reply()でbondingありを返しているのだが、どうもbondingなしでconnectできているようだ。

デバッガで試したが、そもそもBLE_GAP_EVT_SEC_PARAMS_REQUESTが来ていない。
このイベントはconnect後に必ず来るものと思っていたが、別にそういうものでも無いようだ。

つまり、bondingしてないとアクセスできない、という処理をするのはアプリ側の仕事ということか。
相手がセキュリティとか何も気にせず、こちらも何も気にしなかったら、connectするだけで使えるから注意がいるな。