概要
4年ほど前、 PC9800シリーズ用のASKeyboard(アスキーボード)を親指シフトのUSBキーボードとして使えるようにした。もともとコントローラーとして入っていたi8051を抜き、その代わりに SparkFun Pro Micro(コピー品)を手作り基板に載せて装着し、hoboNicolaライブラリを使って実現した。
以前の投稿では、ASKeyboardの中身や紹介についてはその1に、作成した基板の回路などはその2に掲載した。
4年前に改造したものも問題なく動いていたのだが、hoboNicolaライブラリもいろいろと進歩してきているので新しく作り直すことにし、以下のような作業を行った。
- マイコンの32ビット化
Seeed Studio XIAO-m0 (ATSAMD21G-18) を使う。機能や性能だけでなく大きさの面でも適している。 - プリント基板を作成
前にやったときはユニバーサル基板を使って手作りしたが、今回はFusion PCBに小さなプリント基板を発注した。回路図などは後ほど。 - I/Oエクスパンダを利用
利用できるGPIOが少ないXIAOで、12 x 8 キー構成のスイッチマトリックスをスキャンする必要があるので、SPI接続のI/Oエクスパンダ、MCP23S17とMCP23S08を使うことにした。
XIAOとこれらのデバイスの組み合わせでちゃんとマトリックススキャンができるのか確認することも今回の目的の一つ。 - LEDを交換
ASKeyboardにはもともとLEDが5つ入っているが、点灯時の消費電流は1個あたり10mA近い(そのため7407でドライブしていた)。省エネのため1mA前後でも十分明るい新しめのLEDに変更。
LEDについては当初は考えていなかったのでプリント基板に配線を反映しておらず、後から手張りで対応した。 - hoboNicolaライブラリ1.6.2に対応
現在の最新バージョンに対応した。 - HIDキーボードとして以下のようなレイアウトにする。
赤字になっている部分が、ASKeyboardのキーキャップ印字から大きく異なっている部分になる。キーキャップの印字と実際が異なっていても、どうせキーボードはあまり見ないので問題ない。
キースイッチマトリックス
ASKeyboard (sono1)の中身は以下のような回路になっている。スイッチマトリックスやスイッチ自体は1988年の製造時のままである。以前の投稿に載せたものから信号の名称などを若干変更している。
この回路図は独自研究に基づくものなので、正しい保証はありません。
本体部分(sono1)のキースイッチは、12列×8行のマトリックス構成になっており、ダイオードの向きは行(ROW)から列(COLUMN)。つまり、ある一つの列をLOWとしたとき、その列にオンになっているスイッチがあれば、対応する行がLOW状態になる。他の列はすべてHIGHにしておくので、LOWにした列とLOW状態になっている行の交点が、オン状態のスイッチということになる。なお、右側の点線で囲んだ部分が別体のテンキーパッド(ASKeyboard sono2)になるが、使わないので今回は対象外とした。
スイッチ番号とキーの関係
Keyboard-layout-editor.comでASKeyboard sono1の配列とスイッチ番号の関係を書いてみた。
SW41は抜け番になっているが、残りはおおねねレイアウトに基づいたナンバリングになっている。基板上のスイッチの並びとは必ずしも一致していない。
プログラムでは、後述するI/Oエクスパンダによるマトリックススキャンの結果から、変化のあったキーを表すコード(スキャンコード)を生成し、PCに送信するHID Usage IDの表をスキャンコードで参照している。
スキャンコードは、(列番号 – 1) × 8 + 行番号 で算出している。たとえば回路図でC08とR07の交点にある SW42 がオンになっていればスキャンコードは、(8 – 1) × 8 + 7 = 63 ということになる。このスキャンコードで以下のコード表を引くことで、hoboNicolaライブラリに渡すHID Usage ID (この場合は、HID_ENTER) が決まる。
キーボードのスキャンを伴う実装でhoboNicolaライブラリを使う際には、マトリックススキャンして得られるONキーやOFFキーのコード(HID UsageID)を、USBキーボードインタフェース(MAX3421EやCH9350Lなど)から得られるコードと同じようにライブラリの key_event() に渡せばよい。
コード対応表
先に載せたHIDキーボードとしてのレイアウトを実現するため、以下のようなコード表を用いた。スイッチ番号、スキャンコード、HID Usage IDの関係を表している。HIDコード欄のシンボルが表す値は、hoboNicolaライブラリ 1.6.2 が含んでいる hid_keycode.h を参照のこと。
スイッチ 番号 |
内部 スキャンコード |
キーの印字 | 実際のキー | HIDコード | 備考 |
1 | 1 | STOP | Pause | HID_PAUSE | |
2 | 2 | COPY | 半角/全角 | HID_ZENHAN | |
3 | 3 | F1 | HID_F1 | Fn (F11) | |
4 | 4 | F2 | HID_F2 | Fn (F12) | |
5 | 5 | F3 | HID_F3 | Fn (F13) | |
6 | 6 | F4 | HID_F4 | Fn (PrtSc) | |
7 | 7 | F5 | HID_F5 | Fn (ScrLock) | |
8 | 8 | F6 | HID_F6 | ||
9 | 9 | F7 | HID_F7 | ||
10 | 10 | F8 | HID_F8 | ||
11 | 11 | F9 | HID_F9 | ||
12 | 12 | F10 | HID_F10 | ||
13 | 13 | ESC | Escape | HID_ESCAPE | |
14 | 14 | 1 ! | HID_1 | ||
15 | 15 | 2 “ | HID_2 | ||
16 | 16 | 3 # | HID_3 | ||
17 | 17 | 4 $ | HID_4 | ||
18 | 18 | 5 % | HID_5 | ||
19 | 19 | 6 & | HID_6 | ||
20 | 20 | 7 ‘ | HID_7 | ||
21 | 21 | 8 ( | HID_8 | ||
22 | 22 | 9 ) | HID_9 | ||
23 | 23 | 0 | HID_0 | ||
24 | 24 | – = | HID_MINUS | ||
25 | 25 | ^
|
^ ~ | HID_EQUALS | |
26 | 26 | ¥ | | ¥ | | HID_J_BSLASH | |
27 | 61 | BS | HID_BACKSP | ||
28 | 62 | TAB | HID_TAB | ||
29 | 27 | Q | HID_Q | ||
30 | 28 | W | HID_W | ||
31 | 29 | E | HID_E | ||
32 | 30 | R | HID_R | ||
33 | 31 | T | HID_T | ||
34 | 32 | Y | HID_Y | ||
35 | 33 | U | HID_U | ||
36 | 34 | I | HID_I | ||
37 | 35 | O | HID_O | ||
38 | 36 | P | HID_P | ||
39 | 37 | @ ~ | @ ` | HID_LBRACK | |
40 | 38 | [ { | HID_RBRACK | ||
42 | 63 | RETURN | Enter | HID_ENTER | |
43 | 64 | CTRL | Left Ctrl | HID_L_CTRL | |
44 | 40 | A | HID_A | ||
45 | 41 | S | HID_S | ||
46 | 42 | D | HID_D | ||
47 | 43 | F | HID_F | ||
48 | 44 | G | HID_G | ||
49 | 45 | H | HID_H | ||
50 | 46 | J | HID_J | ||
51 | 47 | K | HID_K | ||
52 | 48 | L | HID_L | ||
53 | 49 | ; + | HID_SEMICOLON | ||
54 | 65 | : * | HID_QUOTE | NICOLA時 後退(BS) |
|
55 | 66 | ] } | HID_J_RBR_32 | NICOLA時 取消(Esc) |
|
56 | 67 | SHIFT | Left Shift | HID_L_SHIFT | |
57 | 50 | Z | HID_Z | ||
58 | 51 | X | HID_X | ||
59 | 52 | C | HID_C | ||
60 | 53 | V | HID_V | ||
61 | 54 | B | HID_B | ||
62 | 55 | N | HID_N | ||
63 | 56 | M | HID_M | ||
64 | 57 | , < | HID_COMMA | ||
65 | 58 | . > | HID_PERIOD | ||
66 | 59 | / ? | HID_SLASH | ||
67 | 60 | _ | HID_J_UL | ||
68 | 68 | SHIFT | Right Shift | HID_R_SHIFT | |
69 | 69 | CAPS | 英数 | HID_CAPS | |
70 | 70 | GRPH | Left Gui | HID_L_GUI | Win |
71 | 71 | カナ | Left Alt | HID_L_ALT | |
72 | 72 | TAB | ひらがな | HID_HIRAGANA | |
73 | 73 | 親指左 | 無変換 | HID_MUHENKAN | ※1 |
74 | 74 | 親指右 | 変換 | HID_HENKAN | ※1 |
75 | 75 | 空白 | SPC | HID_SPACE | |
76 | 76 | CTRL | right Ctrl | HID_R_CTRL | |
77 | 77 | ALT | App | HID_APP | ※2 長押しFn |
78 | 78 | 無変換 | 英数 | HID_CAPS | ※3 |
79 | 79 | 変換 | ひらがな | HID_HIRAGANA | ※3 |
80 | 80 | ROLL UP | Page Up | HID_PGUP | |
81 | 81 | ROLL DN | Page Down | HID_PGDOWN | |
82 | 82 | INS | Insert | HID_INSERT | |
83 | 83 | HOME | Home | HID_HOME | |
84 | 84 | DEL | Delete | HID_DELETE | |
85 | 85 | HELP | End | HID_END | |
86 | 89 | ↑ | HID_U_ARROW | ||
87 | 90 | ← | HID_L_ARROW | ||
88 | 91 | → | HID_R_ARROW | ||
89 | 92 | ↓ | HID_D_ARROW |
※1 親指キーのコード
左右の親指キーには、ふつうの日本語キーボードをhoboNicolaアダプターで使う場合とほぼ同様に、無変換キーと変換キーのコードを割り当てた。日本語入力時に単独打鍵と判断した場合は表内のコードを生成し、同時打鍵時にはコードを出力しない。
ASKeyboardは、写真のように親指キーの下に専用の無変換、変換キーを備えているので、親指キーを内部の同時打鍵専用(コード出力なし)として変換操作や無変換操作は専用のキーに任せることもできる。今回は※3に関係して親指周りで日本語と英数の切替え操作をまかなうため親指キー共有型とした。
※2 Appキーについて
hoboNicolaライブラリでは、指定のキーを 長押しFnキー とすることができる。長押しFnキーを所定の時間(200msec程度)以上押し続けることで、そのキー本来のコードは生成せず、キーボード内部でのみ有効な一種の修飾キーに化ける(単独で押した場合、キーを離した時点でそのキー本来のコードを出力する)。
hoboNicolaライブラリを使った他の実装と同じように、ASKeyboardでも滅多に活躍しないAppキー(ALTキー)を長押しFnキーとして利用している。Fn キーと併用することで、ふつうのUSBキーボードにあってASKeyboardにはないキー(F11, F12, PrtScr, ScrLockなど)やマルチメディア機能の音量変更、システムスリープのためのコード出力を実装。また、hoboNicolaライブラリの設定モードの開始にも用いる (Fn + Right Ctrl + S)。
※3 無変換、変換キーのコード
親指キーの下にあるNFER(無変換)とXFER(変換)は、それぞれ英数キーとひらがなキーとした。
日本語入力と英数入力の切り替えについて
hoboNicolaライブラリは、内部がNICOLAモードのときに同時打鍵(NICOLA配列)を有効とするようになっている。NICOLAモードとする/しないを決める方法はいくつかあるのだが、今のところひらがなキーが押されたらNICOLAモード有効、英数キーが押されたらNICOLAモード解除となるように設定している。モード変更はトグルではなく一方通行である。
また日本語入力IMEの文字種の変更操作についても、ひらがなキーを打てば日本語(ひらがなまたはカタカナ)、英数キーを打てばIMEオフとなるよう、IME (Google 日本語入力)をカスタマイズして使っている。これらにより、2つのキーの操作だけでNICOLA配列による日本語入力と英数文字の入力を切り替えることできる。
hoboNicolaアダプターとIME状態通知プログラム(observe_ime.exe) を使っているとき、HTMLフォームのIDやパスワード欄にフォーカスすると、IMEの文字種がWindows APIで正しくとれずパスワードが正しく打てないことがある(Google Chromeを利用)。今回の実装ではそのような状況でも英数キーを打てばNICOLAモードが解除されるので、妙なパスワードを打ってしまうこともない。
ASKeyboard用のhoboNicolaの動作設定
上記のように動作させるため、hoboNicolaライブラリの設定は以下のようにしている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
CURRENT SETTINGS OF HOBO_NICOLA : 162... 1 : SPC -> LEFT OYAYUBI *2 : SPC -> RIGHT OYAYUBI 3 : SPC -> NONE 4 : SINGLE OYAYUBI (override 1-3) 5 : REPEAT ON 6 : SCRLOCK = NICOLA MODE *7 : EISU -> NICOLA OFF *8 : HIRAGANA -> NICOLA ON 9 : HAN/ZEN -> TOGGLE NICOLA *0 : HAN/ZEN -> NICOLA OFF - : IMMEDIATE OUTPUT A : R-ALT -> HIRAGANA C : CAPS <-> LEFT CTRL *H : HENKAN -> SPC U : US LAYOUT M : MSC NOTIFY (TINYUSB) K : KEYBOARD SUSPEND N : NUMLOCK = NICOLA MODE S : HAN/ZEN -> SHIFT+SPACE ... 0000131a : 00000000 : 3 : 32 |
設定2で右親指キーを空白キーとし、設定Hで変換キーを空白キーに置き換えているのは、IME文字種が英数となっているとき、右親指キーを空白キーとして利用するためである。IMEに対しては、空白キーでも変換キーでも同じような変換動作をするように設定している。
4年前の実装時には、内部がNICOLAモードのとき右親指キーがオンになったら空白キーのスキャンコードを生成するようにしていたが、今回は英数字のときも変換キーの操作で何かやらせたくなるかもしれないので、hoboNicolaの動作設定だけで切り替えられるようにした。
設定0の半角/全角キーでNICOLAモード解除 を有効にしているのは、IMEオン(ひらがな)状態で全角英数字を入力するようなときに備えるため。住所を入れるときに全角じゃないと番地を受け付けないとか迷惑なフォームが結構あるから、全角英数字の入力をしやすくした。
IMEの設定について
ついでにIMEの文字種切り替え設定について。この設定は、ASKeyboardにかぎらずhoboNicolaアダプターでふつうの日本語キーボードをつかうときも同じ設定を使っている。IMEは Google日本語入力(GoogleJapaneseInput-2.28.4650.0+24.10.9)。
モード | 入力キー | コマンド |
直接入力 | Hankaku/Zenkaku | 全角英数に入力切替 |
直接入力 | Hiragana | ひらがなに入力切替 |
直接入力 | Katakana | 全角カタカナに入力切替 |
入力文字なし | Eisu | IMEを無効化 |
入力文字なし | Hankaku/Zenkaku | 全角英数に入力切替 |
入力文字なし | Hiragana | ひらがなに入力切替 |
入力文字なし | Katakana | 全角カタカナに入力切替 |
変換前入力中 | Eisu | IMEを無効化 |
変換前入力中 | Hankaku/Zenkaku | 全角英数に入力切替 |
変換前入力中 | Hiragana | ひらがなに入力切替 |
変換前入力中 | Katakana | 全角カタカナに入力切替 |
入力文字種切替(あるいは、IMEのオン/オフ切替)がトグル式になっていると、画面の文字種(あ、A)を見て操作することになるが、切替えが一方通行になっていれば、ひらがなキーや英数キーを叩けば思い通りの文字種に変わるのがいいところ。
LEDまわりの改造
以前やったときには、オリジナルと同様にOCドライバの7407でLEDを駆動していたが、今回は+3.3V電源になったことや消費電流を減らすため7407を外してXIAOのGPIOと(抵抗を介して)直結した。
直列抵抗も220~280Ωのものが使われていたので1kΩに変更した。従来は点灯時にLED1個あたり10mAほど流れていたが、今回は0.8~1.5mAほどになっている(青が0.8mA、赤が1.1mA、緑が1.5mAだった。色ごとに抵抗値変えるのも面倒なので)。
とりあえず3つもあれば十分なので、回路図でのL1、L2、L3の3つだけ使うことにした。L1(緑)がNICOLAモードLED、L2(赤)がCapsLock LED、L3(青)がScrLock LEDとした。
その他の改造点
各行には集合抵抗を使ったプルアップ抵抗が接続されているが、電源電圧が+3.3Vになったことと、 スイッチ・オフ時の立上りを速くするため、もともとは22kΩ x 8だったものを10kΩ x 8に変更した。
3ポジションある側面のスライドスイッチもマトリックスの一部になっておりスイッチポジションもスキャン時点で検出することができる(今回のプログラムでは特に何もやっていない)。写真右側のコネクタは、テンキーパッドを接続するためのもの。
基板について
以前作った手作り基板は薄いフレキシブルなユニバーサル基板にPro MicroとHC138を2つ(2つで4 to 16のデコーダーとして使用)載せた構成だった。
この基板をキーボードの上部(COPYキーの上あたり)にあるi8051用の40ピンソケットに挿すことで、キーマトリックスのスキャンやLEDのオン/オフを行っていた。キーボードケースの上側(上蓋)を被せたときに当たらないよう、基板上のデバイスは裏側に配置していた(デバイスの高さはソケットの高さの程度なのでケースに干渉しない)。
今回作成した基板をセットすると以下のようになる。
今回はキーボード基板のソケットを外し、自作基板を直付けした。ソケットを外した分だけ上部に余裕があるので、2つのI/OエクスパンダとXIAO(およびUSBケーブル)はケースに干渉しない。
上から見るとこんな具合でキースイッチ側はギリギリの位置。PCBを設計しているときにはLEDのことを考えていなかったので、キーボードに装着した後で手張りで対処したが、ちょっと残念な感じ。
USBケーブルは、とりあえずケースの裏側まで引っ張り出せる長さのType-Cのオスーメスケーブルを作って接続した。裏側にメスコネクタが出るので、ふつうのType-Cケーブルに接続して使う。最近はダイソーの充電転送ケーブル(USB2.0 Type-C)をよく使っている。
もともとはちゃんとしたケーブルをケース内まで引き込むつもりでいたが、Type-Cのプラグやレセプタクルが開口部を通過しないし、ケースに穴をあけるのもためらわれるのでこんな具合にした。USB2.0なのでD+、D-、VBUS、GND がつながっていれば問題ない。
作成したPCB
PCB単体(表と裏)は以下のようになった。高さを抑えるため基板の厚さは1mm。
回路図や配線図は以下のようにシンプルである。MCP23S17と23S08 のシンボルやフットプリントはKiCADに含まれていた。
MCP23S17と23S08については、面実装タイプを使いたかったのだけど、入手が厄介そうだったので秋月で買えるスルーホールのDIPタイプを使った。
MCP23S17, 23S08ともに、SPI接続ではなくI2C接続のバリエーションもあるのだが、今回は+3.3V動作でも転送速度が速いSPI版を選択した (SPI版は最大10MHz@+2.7~+5.5V。ただし-40~+85℃。I2C版は最大1.7MHz@+5V、400kHz@+3.3V)。面実装タイプについて、I2C版は比較的入手しやすいようだが SPI版は品薄のようである。
I/Oエクスパンダについて
今回使ったMCP23S17, 23S08はSPI接続なのにスレーブアドレスを送信してアクセスする必要がある。そのため、あるレジスタにデータを書き込むときには、スレーブアドレス、レジスタアドレス、データの3バイトも送信する必要がある。こうなっている理由は、同じバスに接続するデバイスが複数あるとき、それらのスレーブセレクト(SS)を共通として、アドレスを変更してアクセス先を識別するためということのようである。
今回は異なるデバイスを1つずつしか使わないので、両デバイスともにスレーブアドレスの初期値である0x40のままとし、マイコンで制御するスレーブセレクト信号を分けた(23S17の選択はSS_COL、23S08の選択はSS_ROWと表記)。
マトリックススキャンの実際
回路図からわかるように、8ビット必要な行(ROW)側をMCP23S08、12ビット必要な列(COL)側をMCP23S17に接続している。マトリックススキャンは以下のような手順で実行する。
あらかじめ(初期化時に)23S17のGPIOをすべてHIGHにしておく(COL01~COL12はすべてHIGH)。
- SS_COL をLOWにして23S17を選択
- 23S17のGPIO出力のうち1つだけLOWに (COLn=LOWとする)。
- SS_COLをHIGHに戻す。(COLn はLOWを維持)。
- SS_ROWをLOWにして23S08を選択
- 23S08のGPIOを読み出して、COLnのデータとして保存
- SS_ROWをHIGHに戻す
- SS_COL をLOWにして23S17を選択
- (2) でLOWにしたGPIOをHIGHに (COLn=HIGHとする)。
- SS_COLをHIGHに戻す。(COL01~COL12はすべてHIGH)。
すべてのスイッチ状態を読み出すには、上記の1~9を12回繰り返す必要があり、実行時間が気になるところなのでロジアナを使ってモニタしてみた。
1列のスキャン
SPI_SCLK, SPI_MOSI, SPI_MISOは23S17と23S08で共通。MOSIはマイコンからの出力なので23S17に対する列選択の指示で、MISOは23S08が出力するGPIOポートの状態(行データ)になる。
上記の番号の処理に要する時間は以下のようになった。
- 1~3 : COLnの選択に 7.2usec
- 4~6 : COLnの状態読出しに 7.1usec
- 7~8 : COLnの選択解除に 7.3usec
つまり、1列だけのスキャンならば約21.5usec程度で実行できることになる。
全列のスキャン
12列すべてをスキャンするのに要する時間は以下のようになった。こちらの場合、実際の全キースキャン時と同じように、COLnの状態を配列に保管する処理や12列処理するためのループなど、プログラム上のオーバーヘッドが加わっている。
COL01の立下がりエッジをトリガとし、次の立下がりまでの波形をキャプチャした。最初のCOL01 = LOWから次のCOL01 = LOWまでの期間が433usecなので、12列分の読出しにかかる時間は約400usecといったところだろう(図のSS_ROW == HIGHが37.9usecとなっている部分は次のスキャンまでのオーバーヘッドにあたるので、実使用時には無視できる)。
たとえば2msecごとに全キーの読み取りを行うとすると、処理時間全体の20%を占めることになるが、実用上問題はない。
スキャン用のコード
ある1列の状態を読み出すコードは以下のようにした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <SPI.h> static const uint8_t spi_address = 0x40; #define SPI_CLOCK 10000000 spi_ss_port ss_row(SS_ROW); spi_ss_port ss_col(SS_COL); uint8_t spi_read_row(uint8_t reg_addr, uint8_t data) { // COLn選択 SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0)); ss_col.Clear(); uint8_t c[3]; // spi_addr, reg_addr, data c[0] = spi_address; c[1] = reg_addr; c[2] = data; // COLn選択用データ SPI.transfer(c, 3); ss_col.Set(); // COLn状態読出し ss_row.Clear(); c[0] = spi_address + 1; c[1] = GPIO; // GPIO レジスタが対象 SPI.transfer(c, 2); uint8_t value = SPI.transfer(0); ss_row.Set(); // COLn選択解除 ss_col.Clear(); c[0] = spi_address; c[1] = reg_addr; c[2] = 0xff; // 全COL = HIGH SPI.transfer(c, 3); ss_col.Set(); SPI.endTransaction(); return value; } static const uint8_t scan_lines = 12; // 呼び出し側 { // scan all keys. ... uint8_t tmp_scan[scan_lines]; uint8_t col_index = 0; for(uint8_t i = 0; i < 8; i++) tmp_scan[col_index++] = spi_read_row(OLATA, 0xff & ~(1 << i)); for(uint8_t i = 0; i < 4; i++) tmp_scan[col_index++] = spi_read_row(OLATB, 0xff & ~(1 << i)); ... } |
ここに登場しているspi_ss_portというクラスは、SAMD21のポート操作を行うために用意したクラスで中身についてはソースを参照のこと。
プログラム
プログラムの中身については、hoboNicola関係のダウンロードページにある、askb_xiao_hid1.zip を参照のこと。このzipファイルは、Arduino IDEでビルドするメインスケッチ( askb_xiao_hid1.ino )と、ハードウェア周りを担当する askb_xiao.cpp/.h を含んでいる。Arduinoスケッチを置いているフォルダに展開してから開くことで、Arduino IDEに各ファイルのタブができるはず。
ビルドのためには、Adafruit Tiny USB Library(1.14.1) 、hoboNicolaライブラリ1.6.2と、Seeed Stduio XIAO SAMD21 を Adafruit SAMD BSP を使ってビルドするための準備が必要で、手順についてはこちらなどを参照。なお、ビルドには、Arduino IDE 1.8.19を使った。
消費電流など
現在のスケッチを使うと、定常時(通常の入力時、LED全オフ)の平均消費電流は約8mAでスリープ時は0.3mA程度に落ち着いている。スリープ時の最初の30分間は、1秒ごとにスイッチのスキャンを行ってキーによるリジューム要求を確認するようになっているので、もうちょっと大きめの値だろう。消費電流の値は、XIAO-SAMD21のUSB VBUSに流れる電流を測定したもの。スリープ時にUSBを無効化してよいならばもっと小さな値にできるだろう。
なお、XIAO-SAMD21のオンボードのパワーオンLEDは基板から除去している。このLEDのオン/オフはプログラムで制御できず常に1.3mAほど消費する。下の写真の左上がパワーオンLED。他のLEDについては点灯する機会もなさそうなので、そのままにしてある(どうせ見えないが)。
きょうのまとめ
MCP23S17/23S08を使った96キー分のマトリックススキャンは、約400usecに一度の頻度で実行できることがわかった。今回のプログラムではデバウンス処理のために2回のスキャンで1セットとしているが、それでも1msec以内に完結するのでまーまーだろう。デバウンス処理の内容については、4年前の投稿を参照のこと。
このブログの記述はテストも兼ねてすべてASKeyboard を使って行った。こういう文章では、英文と和文の切り替えを頻繁に行う必要があるが、親指キーの周辺で切替え操作を行うことで手指が動く量も減り、結果として誤打鍵も減って楽である。
NICOLAキーボード用のPCBを作るならば親指キーの左右に文字種切替用のキーを配置したいと考えているが、親指を左右に動かすより上下の方が楽かも、とか思ったりする。ただ、変換確定操作のつもりで(従来の無変換キーを押して)英数字にしてしまったりもするので、もうちょっと使い込んでみたい。
親指シフトキーボードとしての動作は自分で使う上で何も問題がない。気になる点は、左側のWindowsキーがちょっと押しにくいこと(Win+EやWin+Dなどはよく使う)。現在は左Altにしている「カナ」キーをWindowsキーとし、その右隣のTAB(NFER)キーをAltにしてもいいかな、とか感じている。文字図形配列以外の部分については、先に載せた表に相当する配列やプログラムコードをちょっと直すだけなので、気が向けばすぐに変更することもできる。こういった表の更新を利用中に行う方法については現在検討中です。