3M バーチュア V4 保護めがね 11672 -

5.0 / 5.0

今まで100均の保護メガネを使ってたけど、ものすごく曇るので、本当に必要そうなときしかつけてないことが多かった。結構つけたりはずしたりするのが面倒。

上記のやつを買ってみたけど、ほんと全然曇らなくてびっくりする。しかし夏は暑いので、やっぱつけはずしは多少しないとダメだなって感じ。

100均のは捨てた。

  1. トップ
  2. tech
  3. 保護メガネを新調した

余談だけど、既存キーボードと併用して Karabiner を使えば実際に左右分割で使えるはず、と思ったが、どうもそれができなかった。修飾キーの共有が BLE キーボードだとうまくいかないみたいだった。Karabiner からもキーボードデバイスとして認識されず謎。これは未だ謎。入力はできてるけどキーボードデバイスとして認識されてない。

https://lowreal.net/2016/09/01/2

と書いたんですが、いろいろやってるうちにできるようになったので記録しておきます。

OS では認識されているにも関わらず EventViewer の Devices にも出なくて???と思っていましたが、どうやら PnP ID (Vendor ID / Product ID) がないと Karabiner に認識されないみたいでした。

といっても VendorID をとるのは難しいので、おそらく一生割り当てられないであろうIDで適当に設定しました (不正ですが)

PnP ID も UUID ベースにすればいいのに、完全登録制なのは不自由な感じがしますね。

  1. トップ
  2. tech
  3. Karabiner で自作キーボードが認識しなかった件

ペアリングして、waitForEvents でスリープしている時間の電流値、つまりアプリケーション的にはアイドル時の各OSごとの消費電流を測った。

というのも基本的に OSX でデバッグしていて殆ど他のOSで検証してなかったからです。

  • OSX: 0.0054mA
  • Windows 10: 0.8mA
  • Android 5系: 0.185mA

なんでこんなに違うんだろうという結果でした。Windows で消費電流が多いのはうすうす気付いてたんですが、あまりにも多過ぎる。

OSドライバが Input Report を READ しまくってる? Notification による実装になっていないとか? よくわからない。slave latency を鬼のように増やしても消費に影響がほとんどないので、強制的に起こすようなパケットがめっちゃ送られていそう。さっぱりわからない。

コネクションまわりのパラメータは実装上、

  • Max Connection Interval
  • Min Connection Interval
  • Slave Latency
  • Connection Supervision Timeout

ぐらいしかなく、どれを変えても変化がない。PnP ID によって専用ドライバが呼ばれるとかがあるのだろうか? と思ったけど、よくわからない。

USB ベースのHIDで実装するとそういうことになってる可能性もないことはない気がする。しかし Microsoft自身も BLE キーボードは発売しているし、こんなことになるはずはないと思う。

BLE のパケットスニファができればもうすこし原因に近付けるかもしれないけど、流れてるパケットがわかっても対処方法が思いつくとは限らないのでやる気があまり沸いてない。というか既に割と飽きてるので OSX で問題ない挙動のために頑張るモチベーションがない……

BLE + HOGP でまともに動いているデバイスの service / characteristics / descriptor のダンプなどをお持ちのかたはお知らせください……

現状の BLE 接続の市販キーボード

市販のBluetoothキーボードの大半は 3.0 です。BLE にしてもそんな意味ないですしね。

Designer Bluetooth® Desktop (デザイナー Bluetooth® デスクトップ)

マイクロソフト キーボード マウスセット Bluetooth対応/ワイヤレス Designer Bluetooth Desktop 7N9-00023 -

3.0 / 5.0

高いうえに日本語配列なので買う気はしないんだけど、評判が良い。そして、スペックシートがすごいしっかりしてて

  • Nordic nRF51822 (Bluetooth Low Energy)
  • Bluetooth Profile Support HID Over Gatt Profile (HOGP)
  • Keyboard: Up to 12 months typical ( 2 AAA alkaline batteries)

と書いてある。使用条件が書いてないのでなんともいえないけど、ディープスリープも実装されてそう。

Universal Foldable Keyboard (ユニバーサル フォルダブル キーボード)

マイクロソフト 薄型キーボード Bluetooth対応/ワイヤレス/折りたたみ Windows/Androidタブレット/iPad, iPhone対応 Universal Foldable Keyboard GU5-00014 -

3.0 / 5.0

これも高い…… Bluetooth 4.0 の HID 接続って書いてあるので、おそらく HOGP だけど、スペックシートには詳しく書いてない。

  • Rechargeable 3.7V 165mAh (min.) Lithium battery
  • 3 months typical

OS X でもペアリング可能っぽい。

英語配列なら買ってみてもいいかと思ったけど、国内だと英語版は売ってない。まじひどい。「製品のイメージは英語版です。実際の製品は日本語のキー配列となります」とか書いてあるので写真に騙されないように。

ただ、技適は国際モデルで共通のようで、国内でも相互承認(MRA)による工事設計認証で認証が通っており、製品にも技適マークがある模様。なので輸入さえすれば法的にも問題なく使えるっぽい。

マイクロソフトの製品の技適検索は数字しかないからわかりにくい。技術データシートに Model
number: 1695, Universal Foldable Keyboard. FCC ID: C3K1695 とか書いてあって、モデル番号がわかる。

Amazon.com だと現時点で$53だった。どうせ日本に発送しないんだろ、、と思ったらちゃんと発送してくれる。送料は最低で$6。結構いいんじゃないか?

Apple Magic Keyboard 2

Apple Magic Keyboard (US配列) MLA22LL/A -

2.0 / 5.0

まじで高い…… BLE らしいけど、詳細は書いてない。

  1. トップ
  2. tech
  3. BLE Nano (nRF51) HOGP で接続中のアイドル電流

必要なもの

arm-none-eabi-* とsrecord が必要。platformio を使ってるなら arm-none-eabi は ~/.platformio/packages/toolchain-gccarmnoneeabi/bin/ に入ってるので、パスを通すか Makefile を修正すればいい。

srecord は brew からインストールできる。

brew install srecord

エクスポートと make

"GCC (ARM Embedded)" でエクスポートする。

とりあえず make してみると、リンク以外はうまくいった。

vfprintf.c:(.text.__ssputs_r+0x46): undefined reference to `__wrap__malloc_r'
vfprintf.c:(.text.__ssputs_r+0x66): undefined reference to `__wrap__realloc_r'
vfprintf.c:(.text.__ssputs_r+0x72): undefined reference to `__wrap__free_r'

と言われてリンクできなかった。

Makefile のうち -Wl,--wrap,_malloc_r -Wl,--wrap,_free_r -Wl,--wrap,_realloc_r を消せばうまくいった。

Makefile は標準的な mbed とリンクしていることを想定していて、うまくいかないところがある。

mbed の代わりに mbed-dev をインポートしている場合以下の書きかえが必要

# SOFTDEVICE = mbed/TARGET_RBLAB_BLENANO/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib/s130_nrf51822_1_0_0/s130_nrf51_1.0.0_softdevice.hex
SOFTDEVICE = ../mbed-dev/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib/s130_nrf51822_1_0_0/s130_nrf51_1.0.0_softdevice.hex

これで、make merge すると .build/combined.hex ができる。これを書きこめば使える。

メモリを32kb使えるようにする

mbed のオンラインコンパイラは BLE Nano v1.5 に対応しておらず、常に RAM を 16kb でしか使えない。実際にアプリケーションで使えるのは6kb程度となっていて、おそろしくキツい。

エクスポートしたらやりたいほうだいなので、リンカスクリプトを以下にように書きかえる。

--- mbed-dev/targets/cmsis/TARGET_NORDIC/TARGET_MCU_NRF51822/TOOLCHAIN_GCC_ARM/TARGET_MCU_NRF51_16K_S130/NRF51822.ld	2016-09-01 13:30:12.000000000 +0900
+++ NRF51822.ld	2016-09-01 22:39:00.000000000 +0900
@@ -3,7 +3,7 @@
 MEMORY
 {
   FLASH (rx) : ORIGIN = 0x0001C000, LENGTH = 0x24000
-  RAM (rwx) :  ORIGIN = 0x20002800, LENGTH = 0x1800
+  RAM (rwx) :  ORIGIN = 0x20002800, LENGTH = 0x5800
 }
 
 OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")

メモリ量チェック用に main の最初にこんなのを書いている。

	{
		const uint32_t reason = NRF_POWER->RESETREAS;
		NRF_POWER->RESETREAS = 0xffffffff; // clear reason
		// reset cause should be shown everytime
		serial.printf("init [%x] sp:%x\r\n", reason, GET_SP());
	}

以下にようになった

# LD スクリプト変更前
init [4] sp:20003fd0
# LD スクリプト変更後
init [4] sp:20007fd0

16kb のときメモリの最後は 0x20004000、32kb のときメモリの最後は 0x20008000 になるはずなので、main の最初の sp がこの値なら問題なく 32kb 使えているはず。

オンラインコンパイラでなんとかできないか

試行錯誤したけどダメだった。ARM は 0x00000000 から読んで MSP として初期化されるので、ここを書きかえれば初期スタックポインタの位置を移動できるはずだけど、生成された hex ファイルから該当部分だけを書きかえてもダメだった。

書きかえてブートさせてみると main までこないので、何か完全にハズれているらしい。リンカの段階でほかにも値を計算して書いてるのかもしれない。

  1. トップ
  2. tech
  3. BLE Nano のオンラインプロジェクトをエクスポートして GCC でコンパイルして RAM 32kB 使えるようにする

ぐっすり寝てると犬に噛まれて殺される。

BLE で接続を維持しつつ、waitForEvent ( sd_app_evt_wait() ) でイベントが起きるまで寝ているケースで、予期せず Watch Dog Timer が発動するという罠にひっかかったので共有いたします。

前提

  • SoftDevice を使って BLE 接続を確立している
  • sd_app_evt_wait() してアプリケーションイベントをずっと待っている
  • WDT を SLEEP 時には PAUSE になるように設定している
  • 途中でアプリケーションの割り込みが入らない (タイマーとかを使っていない)

Pause する設定というのは以下のようなことです。

NRF_WDT->CONFIG = WDT_CONFIG_SLEEP_Pause << WDT_CONFIG_SLEEP_Pos;

予期しないWDTのタイムアウト

SLEEP 時には WDT を止まるようにしていて、アプリケーションは sd_app_evt_wait() で寝ています。よってWDTは働かないことを期待しましたが、本来の WDT の設定時間よりも遥かに長い時間を経過したあと、WDT によりアプリケーションがリセットされました。

原因

結論からいうと sd_app_evt_wait() で寝ていても、SoftDevice は無線アクティビティのために極めて短時間ですが CPU を起こして活動しているため、WDT の設定の「SLEEP 中は PAUSE」の状況にあてはまらない時間が発生します。おかげで、長い時間をかけて本来のタイムアウトに近付き、WDT がタイムアウトします。

対策

アプリケーションレベルでも、十分に短い間隔で割り込みを発生させて、明示的に WDT をリセットする。

普通はメインループで WDT のリセットを書いてますから、単に sd_app_evt_wait() の直前にワンショットなタイマーをかけて一定時間後に割り込みをかければ、割り込み関数で何もしなくても目的を達成できます。


今回3秒のタイムアウトを設定していましたが、このケースで実際に WDT が発生するまでには10分〜30分以上の時間 (無線アクティビティの頻度による) かかりました。なのでかなり安全目にふって1分ごとに起きてWDTをリセットするようなコードにしたところ、問題が発生することはなくなりました。

ケースが限定されていますが非常に見つけにくいバグだと思いました。悩みすぎて死ぬかと思った。

備考:WDT は一度動くと止められない

一度 TASKS_START = 1 すると止められません。STOP するタスクはありません。

RREN を一時的に 0 にすれば止まるかと思いましたが無理です。

The watchdog must be configured before it is started. After it is started, the watchdog’s configuration registers, which comprises registers CRV, RREN, and CONFIG, will be blocked for further configuration.

備考:WDT のタイムアウトのカウンタはとれない

WDT のカウンタがどれぐらいすすんだか? を調べたかったのですが、取得する方法がないようです。

  1. トップ
  2. tech
  3. BLE Nano (nRF51822)、waitForEvent ( sd_app_evt_wait() ) 中に予期せず WDT が発動する場合