CINXE.COM
自作キーボードの製作 — ファームウェアの実装編 | tech - 氾濫原
<!DOCTYPE html> <html data-auth="" data-permalink="1" itemscope itemtype="http://schema.org/BlogPosting" lang=ja> <head> <meta charset=utf-8> <title>自作キーボードの製作 — ファームウェアの実装編 | tech - 氾濫原</title> <meta content="width=device-width,initial-scale=1,maximum-scale=2,user-scalable=yes" name=viewport> <meta content=#000000 name=theme-color> <link href=/feed rel=alternate title=Feed type=application/atom+xml> <link href="https://lowreal.net/2016/09/01/3" rel=canonical> <meta content=unsafe-url name=referrer> <meta content="自作キーボードの製作 — ファームウェアの実装編 | tech - 氾濫原" property=og:title> <meta content="article" property=og:type> <meta content="https://lowreal.net/2016/09/01/3" property=og:url> <meta content="/images/entry/4aeaa2b8445c95cdd47cb4c031a1f9c1.png" property=og:image> <meta content=cho45@lowreal.net property=og:email> <meta content=cho45 property=fb:admins> <link href="/css/style.css" rel=stylesheet> <link href="/css/github.css" rel=stylesheet> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel=stylesheet> <link href="/api/similar?id=20847&" rel=preload as=fetch crossorigin id=preload-similar-entries> <link href="/api/exif?id=20847&" rel=preload as=fetch crossorigin id=preload-exif-entries> <!-- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:foaf="http://xmlns.com/foaf/0.1/"> <rdf:Description rdf:about="https://lowreal.net/2016/09/01/3"> <foaf:maker rdf:parseType="Resource"> <foaf:holdsAccount> <foaf:OnlineAccount foaf:accountName="cho45"> <foaf:accountServiceHomepage rdf:resource="http://www.hatena.ne.jp/"/> </foaf:OnlineAccount> </foaf:holdsAccount> </foaf:maker> </rdf:Description> </rdf:RDF> --> <!--[if lt IE 9]><script src=https://html5shiv.googlecode.com/svn/trunk/html5.js></script><![endif]--> <script defer src="/js/daterelative.js"></script> <script defer src="/js/balancetext/tinysegmenter.js"></script> <script defer src="/js/balancetext/balance.js"></script> <script defer src="/js/abcjs_basic_5.1.1-min.js"></script> <script defer src="/js/nogag.js"></script> </head> <body> <header id=global-header> <h1 id=header> <a href=/ > <img alt="自作キーボードの製作 — ファームウェアの実装編 | tech - 氾濫原" height=50 src=/images/hanrangen.svg width=60 style=margin:auto;display:block> </a> </h1> </header> <nav id=global-navigation> <ul> <li><a href=/ >最新</a></li> <li><a href=/photo/ >写真</a></li> <li><a href=https://www.lowreal.net/ >誰?</a></li> </ul> </nav> <div id=content> <div class=entries> <div class=date><a href="/2016/09/01/">2016年 09月 01日</a></div> <article class="tech status-public" data-id="20847" id="post-1472657284" > <header> <h2 itemprop=name><a href="/2016/09/01/3" class=bookmark rel=bookmark itemprop=url>自作キーボードの製作 — ファームウェアの実装編</a></h2> <div class=metadata> <a href="/tech/"><span itemprop=keywords>tech</span></a> | <time datetime="2016-08-31T15:28:04Z" data-epoch="1472657284" itemprop=datePublished> 00:28 </time> | <div style=display:none> <meta content="/2016/09/01/3" itemprop=mainEntityOfPage itemscope itemtype=https://schema.org/WebPage> <span itemprop=headline>500 Can't connect to lowreal.net:443 (certificate verify failed)とにかくこれが一番大変だった。BLE +…</span> <span itemprop=author itemscope itemtype=https://schema.org/Person> <a href=http://www.lowreal.net/ itemprop=url> <span itemprop=name>cho45</span> </a> </span> <div itemprop=publisher itemscope itemtype=https://schema.org/Organization> <div itemprop=logo itemscope itemtype=https://schema.org/ImageObject> <meta content=https://www.lowreal.net/images/logo.png itemprop=url> <meta content=189 itemprop=width> <meta content=105 itemprop=height> </div> <meta content=cho45 itemprop=name> </div> <meta content="2016-08-31T15:28:04Z" itemprop=datePublished> <meta content="2020-07-29T09:52:24Z" itemprop=dateModified> <div itemprop=image itemscope itemtype=https://schema.org/ImageObject> <meta content="/images/entry/4aeaa2b8445c95cdd47cb4c031a1f9c1.png" itemprop=url> <meta content=800 itemprop=width> <meta content=800 itemprop=height> </div> </div> </div> </header> <div class=content itemprop=articleBody> <p><a href=https://lowreal.net/2016/08/30/2>500 Can't connect to lowreal.net:443 (certificate verify failed)</a><p>とにかくこれが一番大変だった。BLE + mbed + HID キーボードでちゃんと動くもののサンプルっていうのが見つからないので、そこそこ動くサンプルから頑張らないといけない。<p>ほとんど作り終わってから気付いたけど先に言っておくと、mbed のオンラインコンパイラ環境で BLE Nano の開発をするのは筋が悪い。RedBear も Keil 使って Nordic SDK 直接使って開発しろみたいなことを言ってる。ただ、今回はどうしても、キーカスタマイズとかのために開発環境をゴリゴリ用意するというのが嫌だったので、オンラインコンパイラに拘った。</p> <section class=level-1> <h3>依存と罠</h3> <p> <span itemscope itemtype=http://schema.org/Photograph> <a href=https://picasaweb.google.com/114431815111528304586/6323031960966924593#6323051196830618146 itemprop=url class=picasa><img alt=photo itemprop=image src=/images/entry/4aeaa2b8445c95cdd47cb4c031a1f9c1.png></a> </span> <p>まず、現状の mbed ライブラリと nRF のSDK のどちらにもあるヘッダファイルが競合していて、まともにコンパイルできなかった。mbed を依存からはずして、mbed-dev をインポートして、該当するヘッダファイルをリネームして対応した。しょっぱなからひどい目にあった。<p>BLE_HID というライブラリもあって「お、これいいじゃん」という感じだけど、<a href=https://lowreal.net/2016/07/18/2>500 Can't connect to lowreal.net:443 (certificate verify failed)</a> にある通り、さっぱりペアリングできなくてハマった。<p>BLE_HID は結局中の構造をいじることが多かったので、プロジェクト内にファイルをコピーして依存から消している (競合するので)。</p> </section> <section class=level-1> <h3>セキュリティまわり</h3> <p>これまたハマりまくるポイントで困る。上記のようにそもそもペアリングできないというのもあったし、普通に使えるレベルとするにはペアリング情報を覚えてて自動再接続してほしいところだけど、どうやるかさっぱりわからなかった。<p>結論からいうとセキュリティまわりの処理が終わったら該当デバイスをホワイトリストに入れれば良い。しかし BLE_API のホワイトリストまわり、experimental 扱いになっていて不穏な空気を感じる。</p> </section> <section class=level-1> <h3>BLE と OS X</h3> <p> <span itemscope itemtype=http://schema.org/Photograph> <a href=https://picasaweb.google.com/114431815111528304586/6325024057988039265#6325024057521055778 itemprop=url class=picasa><img alt=photo itemprop=image src=https://lh3.googleusercontent.com/-50155SHdIuw/V8b_3nBXqCI/AAAAAAAAg80/i7_-QSYlNT4XKIPqYm5FDbLwLjUIaPnLwCLcB/s2048/2016-09-01%2B01.03.35.png height=516 width=752></a> </span> <p>まず、よくわからないけど OS X が BLE キーボードをキーボードとしてちゃんと認識しない (具体的にはアイコンが汎用デバイス扱いになるし、バッテリーステータスもちゃんと表示されない。ちゃんと GATT で提供してるのに……)<p>ただ、ペアリングするとちゃんと入力できるので対応されてないわけではない。<p>あと、Bluetooth の環境設定が頻繁に固まる。ジョブズが生きていればこんなことには……<p> </p> <figure class=amazon itemscope itemtype=http://schema.org/Review> <div class=image> <a href="https://www.amazon.co.jp/dp/B01DIDN3JU?tag=nuso-22&linkCode=ogi&th=1&psc=1"><img alt="Apple Magic Keyboard (US配列) MLA22LL/A - アップル" itemprop=image src=https://m.media-amazon.com/images/I/41Km4ucnh0L._SL500_.jpg height=180 width=425></a> </div> <figcaption class=detail> <p class=title itemprop=itemReviewed itemscope itemtype=http://schema.org/Product> <a href="https://www.amazon.co.jp/dp/B01DIDN3JU?tag=nuso-22&linkCode=ogi&th=1&psc=1" itemprop=url><span itemprop=name>Apple Magic Keyboard (US配列) MLA22LL/A</span></a> <span itemscope itemtype=http://schema.org/Review itemprop=review> <span itemscope itemtype=https://schema.org/Person itemprop=author> <span itemprop=name>cho45</span> </span> </span> </p> <p class=author>アップル</p> <div class=rating data-rating=2.0 itemprop=reviewRating itemscope itemtype=http://schema.org/Rating> ★ <meta content=1.0 itemprop=worstRating> <span itemprop=ratingValue>2.0</span> / <span itemprop=bestRating>5.0</span> </div> <span itemscope itemtype=https://schema.org/Person itemprop=author style=display:none> <a href=http://www.lowreal.net/ itemprop=url> <span itemprop=name>cho45</span> </a> </span> </figcaption> </figure> <p> <p>Apple Magic Keyboard (Wireless Keyboard ではなく) は BLE 接続らしいけど、どうなってるのかよくわからない。DeviceInformationService で PnP ID を偽称してみたりしてみたけど、うまく認識しなかった。このキーボード、思いのほか高価なので試しに買ってみて調べるみたいなこともできずモヤモヤした。</p> </section> <section class=level-1> <h3>BLE と Windows</h3> <p> <span itemscope itemtype=http://schema.org/Photograph> <a href=https://picasaweb.google.com/114431815111528304586/6319105697117368497#6319577468983119570 itemprop=url class=picasa><img alt=photo itemprop=image src=/images/entry/blekeyboard.png></a> </span> <p>Windows とのペアリングは非常にスムーズで問題がなかった。ちゃんとキーボードとして認識されるし、OS X よりマトモ。ただ Windows でもバッテリーステータスを確認する方法がわからなかった。</p> </section> <section class=level-1> <h3>BLE と Android</h3> <p> <span itemscope itemtype=http://schema.org/Photograph> <a href=https://picasaweb.google.com/114431815111528304586/InstantUpload#6325020761943799394 itemprop=url class=picasa><img alt=photo itemprop=image src=/images/entry/Screenshot_2016-09-01-00-50-28.png></a> </span> <p>さすがにスマフォは BLE の対応がしっかりしていて、まともにペアリングできるし、ちゃんと使える。<p>nRF Connect で GATT 情報を見ると OS X 上で LightBlue を使って見るよりも多くの情報を得られる。BLE に関してはスマフォも活用してデバッグしたほうが捗る。</p> </section> <section class=level-1> <h3>特にハマったところ</h3> <ul> <li><a href=https://lowreal.net/2016/07/20/2>500 Can't connect to lowreal.net:443 (certificate verify failed)</a></li> <li><a href=https://lowreal.net/2016/08/25/2>500 Can't connect to lowreal.net:443 (certificate verify failed)</a></li> <li><a href=https://lowreal.net/2016/08/26/2>500 Can't connect to lowreal.net:443 (certificate verify failed)</a></li> <li><a href=https://lowreal.net/2016/08/29/2>500 Can't connect to lowreal.net:443 (certificate verify failed)</a></li> </ul><p>別途エントリに起こしたけど、ここらへんでそれぞれハマってる。<p>あとエントリに起こしていないけど、とにかくメモリが足りなくて苦労する。現状の BLE Nano (v1.5) は 32kb RAM があるのだけど、mbed がサポートしておらず、16kb しか使えない。そして SoftDevice とかの使用を除いて 6kb ぐらいしかアプリケーションが使えるメモリ量がない。この中で抽象化された mbed の BLE_API を使うと本当にすぐにメモリが枯渇する。<p>メモリが枯渇してもハードフォルトでランダムに stuck したりする感じなので、おそろしく原因究明が難しい。ヒープが上書きされても致命的でなければ動き続けるわけだし、ヒープの正確な使用容量を知るよしはないし、SoftDevice の割込みのために一定量のスタックメモリも残しておかなければならないしで、とにかくつらい。32kb になれば余裕になるので、さっさと 32kb 対応してほしい。<p>現状のメモリ量だと、たとえばマウスをサービスしたいと思っても不可能だと思う。</p> </section> <section class=level-1> <h3>消費電力の削減</h3> <p> <span itemscope itemtype=http://schema.org/Photograph> <a href=https://picasaweb.google.com/114431815111528304586/6325018319495872033#6325018320382727058 itemprop=url class=picasa><img alt=photo itemprop=image src=/images/entry/IMG_4700-16MP.jpg></a> </span> </p><br> <p>最初にやったのはこれだった。製品に近いぐらいにはしたいという気持ちがあったのと、消費電力削減はテスターで見てすぐ効果が数値でわかるので好きというのもある。<p>別途エントリにした 16MHz HFCLK をオフにするというのが一番支配的だったけど、他にも細かいところに気をつかったつもりではある。<p>必要ないペリフェラルはできるだけ止めているつもり。UART だけデバッグの都合でスリープに入る前後のタイミングで止めてからスリープに入って起きたら再開するというコードになっている。ただし、UART も RX は一切行わないので止めている。<p>また、無接続ピンもプルアップして中途半端な状態にならないようにしている。中途半端な電位になると、他のところとの電位差で無駄に電流が流れたりするので気をつける必要がある。これは直接レジスタをいじっていて、mbed の DigitalIn とかは使ってない。メモリ節約のため。<p>キー入力間でチャタリング防止のつもりで5msのインターバルをいれているけど、これも安易に wait_us(5000) とかにせず、Timeout による割込みをしかけて waitForEvent して寝るという実装にしてある。CPU をスリープさせない限り消費電力は減らないので、起きている時間をとにかく短くしたい。<p>起きている時間をとにかく短く、という視点で、I2C の速度を 250khz に上げてある。100khz よりも2.5倍早いので、I2Cで消費する電力は半減ぐらいになる。ただ、電源電圧が低いので速度をあげると安定性が失われる。オシロで波形を見ると結構なまっている。<p>BLE のコネクションパラメータで一番効果が高いのは slave latency だった。このパラメータは、ホストからのリクエストを一定個数無視するというもので、スリープ中の消費電力を結構減らせる。<p>一方、空中線電力は下げてもそれほど効果がなかった。コンスタントに消費はあるが、極めて短時間なので平均的には支配率が低いように感じた。</p> </section> <section class=level-1> <h3>安定性改善</h3> <p>前述したが特定の変数を宣言するだけで stuck するみたいな挙動で原因がわからずとても苦労した。結局メモリ不足でヒープが上書きくらってたみたいだけど、そんなに使ってるつもりないのに死ぬのでなかなかメモリ量が問題と思いあたらなかった。<p>また MIC エラーもとにかくハマっていた。メモリ使いすぎの件があったので、これもそういう系なのだと思って原因をさがしていたが、そうではなかった。<a href=https://lowreal.net/2016/08/29/2>500 Can't connect to lowreal.net:443 (certificate verify failed)</a></p> </section> <section class=level-1> <h3>レイヤー</h3> <p>めんどくさくて最初は実装してなかったけど、思いのほかHHKB式のカーソルキーにも慣れていることがわかって、仕方なしに実装した。<p>レイヤーの部分はいちいち実機デバッグするのが面倒だったので、<a href=https://developer.mbed.org/users/cho45/code/keyboard/file/b899414e1d34/test_keymap.txt>ユニットテストを雑に書いて</a>ある。</p> </section> <section class=level-1> <h3>バッテリーレベルを mV で見れるようにする</h3> <p> <span itemscope itemtype=http://schema.org/Photograph> <a href=https://picasaweb.google.com/114431815111528304586/6325021140484759905#6325021140206059586 itemprop=url class=picasa><img alt=photo itemprop=image src=https://lh3.googleusercontent.com/-pDK0bN67xG4/V8b9NzLRgEI/AAAAAAAAg8c/ZkOPCoeDWJEqhHmPdSMnYtgrmumUaYTKQCLcB/s2048/2016-09-01%2B00.39.33.png height=568 width=1204></a> </span> <p>カスタムUUIDを定義して、mV 単位のバッテリーレベルもとれるようにした。カスタムUUIDやってみたかったのと、やっぱ % 単位で見れても実際どうなのか不安なので……</p> </section> <section class=level-1> <h3>まとめ</h3> <p>まだちょろちょろいじってはいるけど、ほぼ安定した。「もうこれ安定しないんじゃないか」「USB接続に方針を変えたほうがいいんじゃないか」と思うこともあったが、なんとかなったと思う。</p> </section> <ol itemscope itemtype=http://schema.org/BreadcrumbList><li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem><a href=/ itemprop=item><span itemprop=name>トップ</span></a> <meta content=1 itemprop=position> </li> <li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem> <a href="/tech/" itemprop=item><span itemprop=name>tech</span></a> <meta content=2 itemprop=position> </li> <li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem> <a href="https://lowreal.net/2016/09/01/3" itemprop=item><span itemprop=name>自作キーボードの製作 — ファームウェアの実装編</span></a> <meta content=3 itemprop=position> </li> </ol> </div> <div class="content trackbacks"> <h3>このエントリを参照するエントリ</h3> <ul> <li data-id="20846"> <a href="/2016/09/01/2"> <b>自作キーボードの製作 — 回路設計とアートワーク・ハードの製作編</b><br> <span class=summary>ErgoDox ではないナニか。オープンソースかつ Bluetooth 接続のキーボード | tech - 氾濫原 回路設計 仕様とともに回路の設計もしはじめた。単にス…</span> <time datetime="2016-08-31T15:21:18Z" data-epoch="1472656878" itemprop=datePublished> 00:21 </time> </a> </li> </ul> <ul> <li data-id="20988"> <a href="/2016/12/31/1"> <b>今年やったことを自分で承認する</b><br> <span class=summary>日記を読みかえしてみたら今年もいろいろやっていた。年末にせめて自分で自分を承認してあげたい。おおまかには 高周波関係 アンテナアナライザ製作…</span> <time datetime="2016-12-30T15:04:32Z" data-epoch="1483110272" itemprop=datePublished> 00:04 </time> </a> </li> </ul> </div> <div class="content similar-entries"> </div> <div class=social> <span class=hatena-star></span> <p class=share-buttons> <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Flowreal.net%2F2016%2F09%2F01%2F3" class=share-button rel="noopener nofollow" onclick='ga("send","social","Facebook","Share","https://lowreal.net/2016/09/01/3")' style=background:#3b5998 target=_blank> <img alt=Facebook height=18 src=/images/sharebuttons/FB-f-Logo__white_50.png width=18> </a> <a href="https://bsky.app/intent/compose?text=%E8%87%AA%E4%BD%9C%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%81%AE%E8%A3%BD%E4%BD%9C%20%E2%80%94%20%E3%83%95%E3%82%A1%E3%83%BC%E3%83%A0%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E5%AE%9F%E8%A3%85%E7%B7%A8%20https%3A%2F%2Flowreal.net%2F2016%2F09%2F01%2F3" class=share-button rel="noopener nofollow" onclick='ga("send","social","Bluesky","Share","https://lowreal.net/2016/09/01/3")' style=background:#efefef target=_blank> <img alt=Bluesky height=40 src=/images/bluesky_media_kit_logo_svgs.svg width=40> </a> <a href="http://b.hatena.ne.jp/add?url=https%3A%2F%2Flowreal.net%2F2016%2F09%2F01%2F3" class=share-button rel="noopener nofollow" onclick='ga("send","social","Hatena::Bookmark","Share","https://lowreal.net/2016/09/01/3")' style=background:#00a4de target=_blank> <img alt=はてなブックマーク height=40 src=/images/sharebuttons/hatenabookmark-logomark.svg width=40> </a> </p> </div> </article> </div> <div class=pager> <a href="/2016/09/01/2" rel=next>◀ [tech] 自作キ…</a> <a href="/2016/09/01/">▲ この日のエントリ</a> <a href="/2016/09/01/4" rel=prev>新 ▶</a> </div> </div> <footer id=global-footer> <h2>書いている人</h2> <div class=author> <div class=image> <img alt=Photo height=160 src=/images/profile.jpg width=160 loading=lazy> </div> <div class=desc> <p> cho45 (<a href=https://www.lowreal.net/ rel=author>www.lowreal.net</a>) <<a href=mailto:cho45@lowreal.net>cho45@lowreal.net</a>> </p> <p> JavaScript, Perl, Ruby, HTML, CSS, Web etc </p> <p> <a href=https://github.com/cho45 rel=nofollow class="button github-button" onclick='ga("send","social","GitHub","Follow","cho45")'><i></i> <span class=label> Follow <b>@cho45</b> </span> </a> </p> <p> <a href=/archive>アーカイブ</a> </p> </div> </div> </footer>