ほかにもやりたいことがあるのだが、ここ数ヶ月やってることがなかなか「これでよし」とならなくて、とりかかれない。ぶっちゃけそろそろ飽きてきたのでさっさと日記に書きだして一旦おわりにしたい。

ここ数ヶ月ぐらいキーボードを作っていた。そのためにいろいろ yak-shaving としかいいようがないことも多々していた。

いろいろ書くことが多いので、細かい設計などについては別途エントリを分ける。

  • コンセンプトとキーレイアウトおよび技術仕様の決定
  • 回路設計とアートワーク・実際の製作
  • ファームウェアの実装

あたりをそれぞれ別途詳細なエントリを書く。だいたいの人は細かいことはどうでもいいと思うので、概要のみこのエントリにまとめる。

コンセプトや特長

UNIX ベースのキーレイアウト (というかHHKBをベース) とし、違和感なしに分割キーボードとする。

キー配列

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

特長

  • Bluetooth 4.0 (Bluetooth LE) HID over GATT 接続。Windows と OS X で接続可能
  • Bluetooth 経由によるファームウェアアップデート
  • mbed オンラインコンパイラによるファームウェア開発環境
  • 全てオープンソース (MIT)
  • 1900mAh の NiMH 充電池で約6ヶ月のバッテリーライフ
    • キー入力時 3.3mA、非アクティブ時10uA〜100uA(OSの挙動による)

FOTA/DFU (Firmware On The Air / Device Firmware Update) かつオンラインコンパイラによりキーカスタマイズのために環境構築が不必要。あるいは MK20 による書きこみなので、3ピンの配線でUSBからマスストレージクラス経由で書きこみ可能。

技術的な仕様

UNIX配列のBluetoothキーボードというのが希少で前々から欲しいと思っていたので、接続インターフェイスは Bluetooth としてみた。

インターフェイスとして RedBear BLE Nano というのを使うことにした。国内技適にも通っており結構安い。mbed が開発環境に使える。名前の通り BLE (Bluetooth 4.0) 接続になる。ただ、なんというか、この選択(無線化)は割と悪夢の始まりだった。

回路設計


BLE Nano はピン数が少ないため、I2C GPIO 拡張の MCP23017 を2つ使っている。消費電力削減のため GPIO の割込みを活用している。キーの部分は単にキーマトリクスなので特におもしろいところはない。

ステータスLEDを1つだけつけている。これはペアリングステータスを示すため。キーボードにLEDあっても見ることないし消費電力の無駄なのでほとんど消灯させておく。

基板設計

KiCAD のプロジェクトは github に置いてあります。https://github.com/cho45/Keble

PCB Milling (CNCフライスによる基板切削) でやることを前提としたので、片面基板+最低限のジャンパで構成した。

複雑ではないが配線数は多いので、片面という制約をつけると結構厳しい。がオートルータでなんとかなった。製作しやすくするため、デザインルールで最小幅を0.3mmとした。

製作

とりあえず左を作ってファームウェアと共に実装を検証し、それから右側を作った。そのため、右に比べると左側のクオリティが明らかに低い。

設計がちゃんとできている前提で、無心ではんだ付けをするだけ。振動とたわみの負荷がSMDにかかるのがなんとなく嫌で全てリード部品としたため、特に難しいところはない。

基板以外に、バックプレート(2mm)とフロントプレート(1mm)をさらにプラ版から切り出している。なので、3層構造になっている。側面はない。

ファームウェアの実装

mbed レポジトリ

mercurial:

hg clone https://developer.mbed.org/users/cho45/code/keyboard/

前述の通りだけど、今回は mbed のオンラインコンパイラで全て実装した。BLE Nano + mbed でセキュアペアリングして HID デバイスとして動かす例なんてのは例がさっぱりなくて大変苦労した。

HID キーボードとして簡単に動かすぐらいまでは、既にやってる人がいるので難しくない。しかし、実用キーボードとして安定して動かすようにするまでがかなり辛かった。

70%ぐらいの完成度まではすぐできるけど、そこから90%ぐらいまで完成度を上げるには大変な労力がいる。ハマったポイントが蓄積されていて、使えるぐらいに安定して動くコードがある状態にできたので、まぁ良かった…… ハードウェアよりもファームウェアの実装の知見のほうが遥かに価値があると思う……

基本的に mbed 環境でがんばるってのが筋が悪いのだけど、なんとなくオンラインコンパイラにこだわって意固地になって苦労している感じ。

現状の実装クオリティ

主観的には90%といったところと思ってる。温度感としては「ブログ書くぐらいなら全く問題がなく、仕事で使うのにもまぁまぁ使える」ぐらい。

仕事で1日使ったところ、数回再接続(約5〜10秒ぐらい)が必要になったのと、1度完全に刺さった(WDTで復帰せず、リセットで復帰)。0dBmで送信しているので、普通の距離なら物理要因で接続が切れることはないと思うので、他の再接続もファームウェアのバグだと思うが原因不明。

自分の主観的には割と稀ぐらいまできて普通に使える、バリバリ集中してコード書きまくる人だとイライラするかもしれない。

キーマップが HHKB と同じ (Fnキーによる矢印キーも実装してある。レイヤーってやつ)なので、基本的にどっちも全く違和感なく使える。

部品とコスト

  • BLE Nano Kit: 3300円 (Red Bear Store)
  • Gateron Brown キー 108 セット: 3300円 (ebay) 余ります
  • キーキャップ 104 セット: 5700円 (ebay) 余ります (無刻印・メタキー用)
  • キーキャップ 104 セット: 3500円 (AliExpress) 余ります (有刻印)
  • 生基板 1.6×150×250 2枚: 1000円 (monotaro)
  • 1mm プラバン B00CF9RSTU : 540円 (Amazon)
  • 2mm プラバン B001Q0ZHTW : 550円 (Amazon)
  • ビス・ナットなど 500円ぐらい

キーキャップ2セット買ってるがメタキー用の無刻印のものと通常キーの刻印ありのものを分けたかったからで、1セット+必要なキーだけとかならもっと安くはできるはず。いずれにせよキーキャップの原価支配率が高い。これだけ買ってるのに右シフトキーサイズのキーが Caps Lock しかなくて、しかたなく代用している。

基板切削を自力でやっているので注意がいる。もし基板を外注するなら、左右別のデザインにするとサイズ的に5枚組み1万ぐらいはかかるはず。とはいえ、外注しても2〜3万ぐらいの原価なので、趣味で作るのはまぁまぁ現実的といえる。基板をシェアするともだち(笑)がいるならもうちょっと安くて楽をできる。(趣味で、というのは自分の作業コストをゼロとして見積るという意味です)

製作期間

ヤパチーで ErgoDox を見て触発されて、ErgoDox について調べた(買わないけど) | tech - 氾濫原 このエントリを書いた時点でさいきょうのキーボード自作の実現性について考えていたので、そこから約1ヶ月半ぐらい。ebay や aliexpress が部品調達のメインで、かなり待ち時間があるので、実働は1ヶ月ぐらいかな。休日も平日も夜中にしか開発できないので、やる気があれば半月ぐらいで形になりそう。主観的には(大変すぎて)3ヶ月ぐらいずっとやってるつもりだったけど、案外早くできたっぽい……

ぶっちゃけ1ヶ月ぐらいじっくり取り組むと飽きる。

現時点での感想

キーボード自作は結構面白い。というか奥が深いと感じる。自分が一番よく触るインターフェイスを自分である程度作れるというのは満足度が高い。

いきなりイチから盛り盛りで作ったわりには良くできたと思うが、特にハードウェア部分は製品レベルではない。自分で作って自分で使うぶんには十分といえる。

「さいきょうのきーぼーど」追い求めると沼にハマるので、ほどほどにしたほうがよさそう。

フルキーボード作るのは結構コストがかかるので、既存のキーボードと組合せる前提で、カーソルキーだけとか、ファンクションキーだけ、みたいな無線キーボードなら安く作れて良さそう。そして十分実用にできると思われる。

  1. トップ
  2. tech
  3. ErgoDox ではないナニか。オープンソースかつ Bluetooth 接続のキーボード

このエントリを参照するエントリ

BLE Nano は書きこみ器セットで購入しても $32.90 とかなりお得。BLE Nano Kit - Product 単体 なら $17.90。RedBear は香港みたい。公式の通販から最低送料のオプションで買っても割とすぐ届く。

ただのビーコンとして使うには高価に感じるかもしれないが、PCとの低消費電力無線通信デバイスでこの価格帯のものは殆どない。

そしてARM かつ、mbed を開発環境につかえる。なお Arduino からも書きこめる。ナイス。

載っている BLE モジュールも nRF51822 という界隈でデファクトスタンダートみたいなやつなので比較的情報が豊富。

そして小さい。小さいのは正義。その分IOは少ないが割となんとかなる。

  1. トップ
  2. tech
  3. なぜ BLE Nano にご執心なのか

0x3d はMessage Integrity Check (MIC)が失敗した、というエラーらしい。ホスト側で発生する。デバイス側から送られてきたメッセージのセキュリティチェックエラーのようだ。

ということで、デバイススタックの SoftDevice のバグでは? と思うところだけど、そうではないらしい。どうやら mbed と相性が悪いらしい。

解決の糸口

0x3d が出るのは最初はファームウェアのバグでどこかが stuck しているからだと思っていた。しかしどうも stuck していなくても 0x3d が起こることがある。で、そろそろ Nordic スタックのバグを疑ってみる。しかしそこのバグなら既にハマっている人がいるはずなのでググる。

すると Implement BLE security · Issue #44 · lancaster-university/microbit-dal · GitHub あたりに Nordic のバグじゃね? みたいな話がでてくる。そこからサブイシューがつくられている。


MIC failures observed with secure BLE · Issue #61 · lancaster-university/microbit-dal · GitHub

Problem is caused by mbed-classic disabling interrupts when a timer interrupt is triggered. This was too long for the underlying BLE stack to code with during critical radio events.

と原因と、さらに解決策がいくつか示されている。一番簡単なのが3つめなので、このプロジェクトでは3つめが採用されたっぽい。しかし肝心のコミットへのリンクはないので頑張って探す。

Merge branch 'secure-ble' · lancaster-university/microbit-dal@3c31479 · GitHub このコミットをつらつら眺めていくと、どうやら対策コードっぽいものが見つかった。

	// configure the stack to hold on to CPU during critical timing events.
 	// mbed-classic performs __disabe_irq calls in its timers, which can cause MIC failures 
 	// on secure BLE channels.
    ble_common_opt_radio_cpu_mutex_t opt;
    opt.enable = 1;
    sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);

ここで SoftDevice の API を呼んで、無線アクティビティがあるときはCPUを完全にブロックしてアプリケーションの実行を止めるらしい。簡単なコードだ。

コピペしてみるとエラーの発生がなくなった。まじ良かった……

備考:エラーのログ

Apple が提供している Bluetooth Explorer の Event Log を開きっぱなしにしておけば、接続情報について常にデバッグログに残る。

  1. トップ
  2. tech
  3. BLE Nano (nRF51) + mbed でセキュリティ付きペアリングをして 0x3d エラーがでる

仕様に書いてあるが標準だと 0.5mA になっている。これは超高輝度LEDなら直接光るかもしれない。電源電圧がそもそも低いので青色とかはやめたほうがよさそう。

なお、設定を変えると最大3ピンまで5mAのドライブ能力に拡張することができる。これは特にピンの制約はなくて、どのピンでも可能なようだ。LEDぐらいしか駆動するものがないのなら、LED ピンのドライブ能力を拡張しておくと安心できる。

設定方法は例えば以下の通りで、

	NRF_GPIO->PIN_CNF[PIN_STATUS_LED] =
		(NRF_GPIO->PIN_CNF[PIN_STATUS_LED] & ~GPIO_PIN_CNF_DRIVE_Msk) |
		(GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos);

PIN_CNF の DRIVE を変更すれば良い。この例だとソースもシンクも5mAになる。ソースとシンクは別々に設定可能。

なお mbed 環境で DigitalOut とかしている場合 PIN_CNF レジスタは変更済みなので、必要ないところは上書きしないように注意する必要がある。

  1. トップ
  2. tech
  3. BLE Nano (nRF51822) のドライブ能力を外付け部品なしで拡張する

nRF51 での FOTA の仕組み

DFUService というのが mbed の BLE_API だと提供されていて勘違いしたけど、これは実際のファームウェア書きこみ処理は一切行わない。これがやっていることは bootloader を起動するということだけだ。

FOTA の仕組みとしては

  1. クライアントは DFUService に対してリクエスト
  2. DFUService はアプリケーション抜けて bootloader として再起動する
  3. クライアントは再度 DFU を見つけて通信を行う
  4. bootloader はBLE経由でデータを受けとってFlashに書きこむ
  5. bootloader はアプリケーションを起動する

という感じですすむ。

mbed 環境でのやりかた

まず、コンパイル済みの bootloader が必要で、これを USB 経由で書きこむ。これで準備完了になるので、これ以降は FOTA だけで書く必要がある。USB 経由で書きこむと bootloader を上書きしてしまうので、FOTA は無効になる 。

bootloader はどれを使うか

https://github.com/RedBearLab/nRF51822-Arduino/tree/S130/bootloader

Arduino IDE 経由で書きこめる bootloader になっているが、FOTA の機能もついている。BLE Nano だとこれ使っておけば良さそう。他のも使ってみたがこれだけ動いた。

mbed からデフォルトでダウンロードされる hex は書けない

ただ、上記 bootloader.hex を書きこんでも、mbed のオンラインコンパイラでコンパイル・リンクして生成される hex ファイルでは基本的に書きこめずに失敗する。これは mbed 環境でコンパイルした場合、親切にも SoftDevice などをマージした状態で hex を作ってくれるから。しかし FOTA するのはアプリケーションの部分だけなので、余計な部分を取り除く必要がある。

これは nRF51_OTA_strip.py を使えばできる。単に引数に入力と出力を与えればアプリケーション部分だけの hex ファイルを吐いてくれる。

ここを変えれば FOTA 版が落とせるみたいです。気付かなかった。ここで FOTA 版を選択すると、DFUService は自動的に組込まれてコンパイルされます。

書きこみかた

できた hex ファイルをなんとかして Android か iPhone に転送する。Google Drive に突っ込むのがてっとり早い。

そして nRF Toolbox を使って DFU をする。このとき、Init packet がどうたらというダイアログがでるが No を選択する。

Device を選択して Upload をタップすれば DFU がはじまる。結構時間がかかる。

bootloader のソースコードは?

https://github.com/ARMmbed/nrf5x-dfu-bootloader

たぶんこれがそれっぽい。ビルドしてないので確認はしてない。

OS X で DFU できないの?

公式ツールは Android / iPhone だけなので、できない。

サードパーティで作ってる人がいる。https://github.com/jeremysf/nrfDFU が、手元だとうまく動かすことができなかった。追試が必要。

  1. トップ
  2. tech
  3. mbed + BLE Nano で FOTA (DFUService) を使うには?