余談だけど、既存キーボードと併用して 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 が発動する場合

ErgoDox ではないナニか。オープンソースかつ Bluetooth 接続のキーボード | tech - 氾濫原

まず思いつく現状の不満とかを考えて、それを盛りこんで作ろう、という方針を決めた。つまり

  • 左右分割にしたいなあ
  • UNIX 配列準拠がいいなあ
  • Bluetooth がいいなあ

あたりが最初の方針になる。


できるだけ MacBook 標準のキーボードでも十分開発できるぐらいの状態を保ちたいので、奇抜なキー配置のものは例え身体に良くても精神に悪いので使いたくない。

市販品で近いものを探すと、Kinesis freestyle2 あたりがイメージに近い。これをキーリマッパでカスタマイズすれば実用的にはいいかもなとは思った。

Kinesis Freestyle2 Keyboard [KB820PB-us]【キネシス フリースタイル2(9インチ)+VIP3セット Win版】 -

3.0 / 5.0

あと、普通の(普通ってなんだ?)左右分割キーボードの内側のキーにも不満がある。左右分離の場合、タッチタイピングで左手に所属するキーを右手では決して打てなくなる。

しかしゆるふわタッチタイパー的には、中央付近のキーは右手でも左手でも打ちたい。つまりキーをオーバーラップさせたいが、そんなキーボードはこの世に存在していない。僕は「タッチタイピングの矯正」とか別にしたくなくて、ゆるふわでいきたい。

ErgoDox の設計の分析

まずErgoDox はキー数が少なくて UNIX 準拠にはできない。キー配列の画像を見ればわかると思うが、右側にキーが足りない。例えば HHKB なら P の右には [ と ] と DELETE があり3つのキーが続くが、ErgoDox だと1つしかキーがないので無理。ソフトウェア的になんとかするしかない。

なお ErgoDox は設計段階で左右の基板が共通となっている。両面基板をリバーシブルに使うことで両手に対応させている。これにより基板の製造コストはかなり減る (特に小ロットで外注する場合は半額にできる)。ただし、設計には左右対象であるという制約がつく。

一般的なキーボードは右手担当のキーが多く、左右非対称になっている。左右対象という制約をつけると、一般的なキーボードからかなり離れることになる。これはエルゴノミクス的には正しい気はするがよくわからない。ただ、キーが少ないのは現実的に不便だと思う。

余談だけど、右側のキーが多いことも考えると世の中のキーボードは右利き用ではないかと思った。左利きはキーボードにおいても不利を強いられていないだろうか? (僕は右利きなのでそんなこと思いもよらなかったんだけど)

仕様

そういったことを踏まえて自作するキーボードの以下のように仕様とした。

キー配列の仕様

  • UNIX キーボードを2分割した形を基本にする。つまり HHKB とほぼ同じで、Ctrl キーはAの左、ESC は 1 の左など。
  • 矢印キーはどうしても欲しい (HHKB への大きな不満のひとつ)
  • F1〜F12キーもできれば欲しい (HHKBへの小さな不満のひとつ)
  • 中央のキーを1列分オーバーラップさせる
レイアウトの詳細


HHKB からの変更点

  • スペースキーが2分割に
  • F1〜F6, F7〜F12 キーの新設
  • 矢印キーの新設

まず「ぼくのかんがえたさいきょうのキーボードはいれつ」を Inkscape で書いてレイアウトを検証した。軽く書くというよりは CAD 的にちゃんと書いた。のちのち Inkscape からエクスポートして KiCAD で読みたかったため。

備考

  • 僕は右手のスペースキーをほぼ全く使わないので、実質飾りである。
  • Caps Lock キー? そんなものはない。写真にある Caps Lock は Shift キー(キーが足りなかったので)
  • 矢印キーを置くところがなくて右手親指付近に置いている (が、これはちょっと邪魔だった。あと1キー分左にずれていたほうがいい…)

技術仕様

同時に、いくつかこうしたいという仕様も決めた

  • NiMH 単3バッテリー2本で半年ぐらい持つ (普通の製品ぐらい持つこと)
  • 左右ボード間の接続は有線
  • USB に逃げたくなったとき逃げられるようにしておく
    • 制御用のボードは分離して設計すること

一方、躯体については殆ど考えてなくて、いきあたりばったりで基板を作ってから3層構造にした。製作編で詳しく書く。

なお省電力であればあるほどいいけど、そこそこ電波が出るデバイスなので、BLE が生きるぐらいの省電力にはならないだろうという気はしてた。

左右のキーボード間も無線にしたかったが、セキュアにしようと思うと BLE Nano 2台でそれぞれHIDキーボードにしてしまうのが楽ということになってしまう。今回はそういうことはしたくなかったので、ここは有線で妥協した。

ただ、左右どちらも回路構成が完全に一緒なので、単に制御用の基板を2つ用意して取り付ければそれぞれHIDキーボードとして使うことができるようにはした。

つづく → 自作キーボードの製作 — 回路設計とアートワーク・ハードの製作編 | tech - 氾濫原

  1. トップ
  2. tech
  3. 自作キーボードの製作 — コンセンプトとキーレイアウトおよび技術仕様編

ErgoDox ではないナニか。オープンソースかつ Bluetooth 接続のキーボード | tech - 氾濫原

回路設計

仕様とともに回路の設計もしはじめた。単にスイッチがいっぱいついてるだけなので、回路的には難しいところは一切ないといってもよい。問題はPCとのインターフェイス部分になる。

キースイッチ

キースイッチは Cherry MX 系がいいなと思った結果 Gateron (Cherry MX 互換) にした。

  • 安い
  • 品質もそれほど悪くはない (というか ErgoDox Lite に採用されてる)
  • 入手性が良い (いろんな色が ebay 経由で買える状態だった)

あたりで決定した。

BLE Nano

Bluetooth 接続したいので、技適を通っている Bluetooth モジュールを考える。ちょうど BLE Nano という製品が技適を通っていて mbed 対応だったため、これをメインMCUとして使用することとした。 mbed で公式にサポートされているUSBボードと比べて圧倒的に小さく、ライターとともに購入してもなお安いというのもあった。ただし BLE Nano は名前の通り Blueooth LE (4.0) のモジュールなので、多少の不安はあった。

I2C GPIO MCP23017

キーマトリクスのために I2C GPIO IC を使うことにした。これはMCP23017という Microchip 社のものとした。BLE Nano の GPIO は少ないので、左右で1つずつの MCP23017 を使い、この2つを同一の I2C バスに接続する。MCP23017は3bit分スレーブアドレスを変えられるようになっているので、2つのアドレスをわける。ちなみに ErgoDox にも MCP23018 というほぼ同じものが使われている。MCP23017 は秋月で取り扱いがある。

消費電力削減のためハード設計の段階で MCP23017 の割込み生成を使うこととした。MCP23017 側でピン変更を検知した場合 INT ピンを通じて BLE Nano 側に割込みを発生させる。MCP23017 は2つ使うが、割込み生成は1つで良いので、割込みピンを BLE Nano 側でプルアップし、2つのMCP23017はオープンドレインで割込みを生成するように設定する。

割り込みを使わない場合、常時I2Cで通信してキーの状態を調べなければならないが、割り込みを使えば何も変化がないときにはデバイス全体をほぼ完全にスリープさせることができる。BLEによる無線接続は必然的にバッテリ駆動となるので、これは必要だと思った。

左右キーボード間の接続コネクタ

左右分割キーボード間の接続は

  • SCL
  • SCK
  • VDD
  • GND
  • INT

と5ピン必要になった。しかし

  • 5ピン以上
  • 小型・
  • 対称・
  • ケーブルの入手性が良い

あたりを満たすコネクタというのが壊滅的に存在しない。4ピンであれば ErgoDox と同様にTRRSコネクタ(4端子ミニプラグ)が使えるが、INT ピンを入れて5ピンにするのは譲れない仕様なため困難が生じた。VDD を INT と併用するという考えも浮かんだが、キー割込みはI2C経由で読むまで解除されないので厳しいと思った。

結局のところはLANコネクタ(8P8C・RJ45)とした。USB Type-C コネクタがナウいので、可能なら使いたいと思ったが、現状では入手性が悪く、ケーブルも高価なのでやめた。LANコネクタは比較的大きいということ以外は要件を満たしている。ケーブルも安いので優秀なコネクタだと思う。

回路図やボードレイアウトの作成

Eagle だとフリー版にはボードサイズに制限があってキーボードぐらいの大きさのものは作れないので、いよいよ KiCAD に移行することとした。なので KiCAD の使いかたレベルから学習する必要があった。これについては別途エントリを書いてきた。

最初とても辛かったが、なんとか慣れてきた。いままで Eagle でやっていたことをすべて KiCAD で可能にするためにかなりヤックシェイビング的なことをした。特にPCB Millingまわりの環境再構築が大変だった。

最終的には pcb2gcode にパッチ送ったりしてなんとかなる環境をつくった。

回路図



Root.sch / Main.sch / KeyModule-L.sch / KeyModule-R.sch となっている。これはKiCAD で複数ボードプロジェクトを運用する
に詳細を書いた。

左・右のそれぞれのキーマトリクスは BLE によるファームウェアの部分と独立させたかった (つまりBLEではなくUSB接続とした場合でも基板自体の変更がいらないようにしたかった) のでメインの制御基板を別にしてある。

ボードレイアウト



Inkscape から左と右にわけてレイアウトを DXF ファイルを出力し、pcbnew にインポートした。キーの配置はこの状態から DXF のガイドにあわせて手動で移動させて行なった。

レイアウトの仕様は以下のようにした

  • PCB Milling 前提
    • 少しでも作りやすくするため、デザインルールで最小幅を0.3mmに
  • 基本1層基板 (裏面配線のみ)
  • ジャンパ部分は極力わかりやすくする

結構大きな基板になるので格安PCBサービスでも結構高額になってしまう。なので手元でできる PCB Milling (CNCフライスによる基板切削)でやることにした。

しかしこの制約はかなり厳しくて、なかなかレイアウトが決まらなかった。両面にすればよかったが、基板作成の手順が倍以上になるのでそうしなかった。

試行錯誤してオートルートさせてなんとかした。ジャンパなしはできなかったので、ある程度ジャンパを許容してオートルートさせてから、自力でジャンパしやすいように、直線にしたり100mil単位になるようにとかと修正を加えた。

基板の製作



左側

まず先に左だけ作って様子を見ることにした。左側だけでもブレッドボードに組んだ制御基板と配線すれば使うことができるため、出来を確かめることができる。

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


それはともかく、使ってみると結構基板がたわんでしまうことがわかったので、下側のプレートにナットだけを増やして力を受けるようにした。キースイッチの実装面には隙間がほとんどないので、裏側から短いビスでナットを止めて隙間を埋めて力をうける構造になっている。


最終的な構造をいまいち考えれてなかったが、結局3層を単純に重ねる形とした。つまり、化粧板・基板・裏板を15mmのビスで共締めしている。

化粧板は特に強度が必要ないので1mm、裏板には多少強度がいるので2mmとした。結果として以下のような層になった。

  • 化粧板 1mm
  • ナット 5mm
  • 基板 1.6mm
  • ナット 3mm
  • 裏板 2mm
  • ナット3mm

できるだけ薄くて机にキーが近いほうがいいけど、このぐらいが限界だった。

化粧板と裏板の切り出し

いずれも外形カットと穴開けが必要だったため、基板と同様にCNCフライスで切り出している。

この際、CAD は KiCAD の pcbnew をそのまま流用した。KiCAD のユーザー定義レイヤーが2層あるので、ここに切削ラインを書いて、ガーバーに書き出し、外形レイヤー扱いで pcb2gcode で gcode 化した。

ただし、pcb2gcode は現時点では「外形カット」しかできないので、内側に書いたラインも外側を削る挙動になってしまう。pcb2gcode 側に対応をいれたかったが面倒なので、図面の段階でエンドミル径分を考慮して線をひいた。

右側

左側を作った結果をうけていろいろ改良を加えて右側を作った。

以下らへんを改良

  • 角丸に
  • 固定用のビス穴を大幅に増やした

やっぱ角丸にしないとこういうのはきついよなと思った。左側はあとからリューターで削って角丸にしたけど、右側は切削時点で角丸になるように外形を描きなおした。

固定用の穴は多めにあったほうが圧倒的にしっかりするのでケチらないで開けたほうが良い。実際、右側は左側と比べてかなりしっかりした構造にできた。

なお右側は左側に比べてキーの数がかなり多く、基板のサイズもぎりぎりになっている。配線もこちらのほうが大変。基板の原点をちょっと適当に設定しまって、基板は上側が実は足りてない(配線的には問題なし)

作ってみて

これで左右が揃ったので、ファームウェアのクオリティはともかく、ちゃんと打てるようになった。

基本的に HHKB と完全に一緒のキー配置なので、ほとんど違和感なく使える。ただ、物理カールキーをつけたのに関わらず、HHKB のカーソルキー移動に思ったよりも慣れていることが発覚した。Fn キー相当の位置に未割当キーはあるので、ファームウェアで対応した。

カーソルキーを制限のあるなか、なんとか配置したのはよかったが、思ったよりも右手の親指と干渉してしまった。あと1キー分左にあったほうが良いかもしれないけど、ぎりぎりすぎる。右のスペースキーは僕は使うことが全くなくて飾りなので、そこに別のキーを配置してもいいかもしれない。

なお自作する場合、CNCフライスの加工限界によって基板のサイズに制限があり、左右分割でないとそもそも作るのが難しいというのを感じた。

あと細く���短いLANケーブルがなかなかなくて難儀する。多少長くても細いほうが取り回しはよさそう。あんまり長いケーブルだとI2Cのドライブ範囲を超えるのでバグりやすくなる。

つづく → 自作キーボードの製作 — ファームウェアの実装編 | tech - 氾濫原

  1. トップ
  2. tech
  3. 自作キーボードの製作 — 回路設計とアートワーク・ハードの製作編

ErgoDox ではないナニか。オープンソースかつ Bluetooth 接続のキーボード | tech - 氾濫原

とにかくこれが一番大変だった。BLE + mbed + HID キーボードでちゃんと動くもののサンプルっていうのが見つからないので、そこそこ動くサンプルから頑張らないといけない。

ほとんど作り終わってから気付いたけど先に言っておくと、mbed のオンラインコンパイラ環境で BLE Nano の開発をするのは筋が悪い。RedBear も Keil 使って Nordic SDK 直接使って開発しろみたいなことを言ってる。ただ、今回はどうしても、キーカスタマイズとかのために開発環境をゴリゴリ用意するというのが嫌だったので、オンラインコンパイラに拘った。

依存と罠

まず、現状の mbed ライブラリと nRF のSDK のどちらにもあるヘッダファイルが競合していて、まともにコンパイルできなかった。mbed を依存からはずして、mbed-dev をインポートして、該当するヘッダファイルをリネームして対応した。しょっぱなからひどい目にあった。

BLE_HID というライブラリもあって「お、これいいじゃん」という感じだけど、OSX + BLE で HID over GATT でペアリング(bonding)ができなくてハマった | tech - 氾濫原 にある通り、さっぱりペアリングできなくてハマった。

BLE_HID は結局中の構造をいじることが多かったので、プロジェクト内にファイルをコピーして依存から消している (競合するので)。

セキュリティまわり

これまたハマりまくるポイントで困る。上記のようにそもそもペアリングできないというのもあったし、普通に使えるレベルとするにはペアリング情報を覚えてて自動再接続してほしいところだけど、どうやるかさっぱりわからなかった。

結論からいうとセキュリティまわりの処理が終わったら該当デバイスをホワイトリストに入れれば良い。しかし BLE_API のホワイトリストまわり、experimental 扱いになっていて不穏な空気を感じる。

BLE と OS X

まず、よくわからないけど OS X が BLE キーボードをキーボードとしてちゃんと認識しない (具体的にはアイコンが汎用デバイス扱いになるし、バッテリーステータスもちゃんと表示されない。ちゃんと GATT で提供してるのに……)

ただ、ペアリングするとちゃんと入力できるので対応されてないわけではない。

あと、Bluetooth の環境設定が頻繁に固まる。ジョブズが生きていればこんなことには……

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

2.0 / 5.0

Apple Magic Keyboard (Wireless Keyboard ではなく) は BLE 接続らしいけど、どうなってるのかよくわからない。DeviceInformationService で PnP ID を偽称してみたりしてみたけど、うまく認識しなかった。このキーボード、思いのほか高価なので試しに買ってみて調べるみたいなこともできずモヤモヤした。

BLE と Windows

Windows とのペアリングは非常にスムーズで問題がなかった。ちゃんとキーボードとして認識されるし、OS X よりマトモ。ただ Windows でもバッテリーステータスを確認する方法がわからなかった。

BLE と Android

さすがにスマフォは BLE の対応がしっかりしていて、まともにペアリングできるし、ちゃんと使える。

nRF Connect で GATT 情報を見ると OS X 上で LightBlue を使って見るよりも多くの情報を得られる。BLE に関してはスマフォも活用してデバッグしたほうが捗る。

特にハマったところ

別途エントリに起こしたけど、ここらへんでそれぞれハマってる。

あとエントリに起こしていないけど、とにかくメモリが足りなくて苦労する。現状の BLE Nano (v1.5) は 32kb RAM があるのだけど、mbed がサポートしておらず、16kb しか使えない。そして SoftDevice とかの使用を除いて 6kb ぐらいしかアプリケーションが使えるメモリ量がない。この中で抽象化された mbed の BLE_API を使うと本当にすぐにメモリが枯渇する。

メモリが枯渇してもハードフォルトでランダムに stuck したりする感じなので、おそろしく原因究明が難しい。ヒープが上書きされても致命的でなければ動き続けるわけだし、ヒープの正確な使用容量を知るよしはないし、SoftDevice の割込みのために一定量のスタックメモリも残しておかなければならないしで、とにかくつらい。32kb になれば余裕になるので、さっさと 32kb 対応してほしい。

現状のメモリ量だと、たとえばマウスをサービスしたいと思っても不可能だと思う。

消費電力の削減


最初にやったのはこれだった。製品に近いぐらいにはしたいという気持ちがあったのと、消費電力削減はテスターで見てすぐ効果が数値でわかるので好きというのもある。

別途エントリにした 16MHz HFCLK をオフにするというのが一番支配的だったけど、他にも細かいところに気をつかったつもりではある。

必要ないペリフェラルはできるだけ止めているつもり。UART だけデバッグの都合でスリープに入る前後のタイミングで止めてからスリープに入って起きたら再開するというコードになっている。ただし、UART も RX は一切行わないので止めている。

また、無接続ピンもプルアップして中途半端な状態にならないようにしている。中途半端な電位になると、他のところとの電位差で無駄に電流が流れたりするので気をつける必要がある。これは直接レジスタをいじっていて、mbed の DigitalIn とかは使ってない。メモリ節約のため。

キー入力間でチャタリング防止のつもりで5msのインターバルをいれているけど、これも安易に wait_us(5000) とかにせず、Timeout による割込みをしかけて waitForEvent して寝るという実装にしてある。CPU をスリープさせない限り消費電力は減らないので、起きている時間をとにかく短くしたい。

起きている時間をとにかく短く、という視点で、I2C の速度を 250khz に上げてある。100khz よりも2.5倍早いので、I2Cで消費する電力は半減ぐらいになる。ただ、電源電圧が低いので速度をあげると安定性が失われる。オシロで波形を見ると結構なまっている。

BLE のコネクションパラメータで一番効果が高いのは slave latency だった。このパラメータは、ホストからのリクエストを一定個数無視するというもので、スリープ中の消費電力を結構減らせる。

一方、空中線電力は下げてもそれほど効果がなかった。コンスタントに消費はあるが、極めて短時間なので平均的には支配率が低いように感じた。

安定性改善

前述したが特定の変数を宣言するだけで stuck するみたいな挙動で原因がわからずとても苦労した。結局メモリ不足でヒープが上書きくらってたみたいだけど、そんなに使ってるつもりないのに死ぬのでなかなかメモリ量が問題と思いあたらなかった。

また MIC エラーもとにかくハマっていた。メモリ使いすぎの件があったので、これもそういう系なのだと思って原因をさがしていたが、そうではなかった。BLE Nano (nRF51) + mbed でセキュリティ付きペアリングをして 0x3d エラーがでる | tech - 氾濫原

レイヤー

めんどくさくて最初は実装してなかったけど、思いのほかHHKB式のカーソルキーにも慣れていることがわかって、仕方なしに実装した。

レイヤーの部分はいちいち実機デバッグするのが面倒だったので、ユニットテストを雑に書いてある。

バッテリーレベルを mV で見れるようにする

カスタムUUIDを定義して、mV 単位のバッテリーレベルもとれるようにした。カスタムUUIDやってみたかったのと、やっぱ % 単位で見れても実際どうなのか不安なので……

まとめ

まだちょろちょろいじってはいるけど、ほぼ安定した。「もうこれ安定しないんじゃないか」「USB接続に方針を変えたほうがいいんじゃないか」と思うこともあったが、なんとかなったと思う。

  1. トップ
  2. tech
  3. 自作キーボードの製作 — ファームウェアの実装編

ポリスチレンはカッターで切れるのと、プラモデル用の接着剤が使えるのが良い点だなあ。

ASUS ZenFone 2 の Android M (6.0) アップグレードは遅延 | tech - 氾濫原

遅延していた OS アップデートですがようやくきました。8月31日付けで配信開始したようです。リリースノート

ただし WW のみ。JP はいつ……

  1. トップ
  2. tech
  3. ZenFone2 にようやく Android M (Mashmallow) アップデートが降ってきた