ダイヤテックの閉業が突然発表されました。
折しも10年以上愛用している Mejestouch Ninja Tenkeyless の制御基板を改造する工作をしたタイミングだったので、記録に残しておこうと思います。
先日、キーボードの分解清掃をした際に、制御基板が簡単に外せることに気が付きました。
外した基板を見て思ったわけです。「これ、自作基板にできそうだな」と。
仕様を調べる
使用されているのはHALTEKの「RT82K94E」というマイコン(廃品)です。
水晶発振器と電解コンデンサのほかは、チップの抵抗とセラコンが載っているだけのシンプルな基板のようです。
16ピンの2mmピッチピンヘッダx2=32pinでスイッチ基板と接続されています。
うち4ピンは電源とUSBのデータ線なので、必要なGPIOの数は最大28本となります。
Raspberry Pi Picoに使われているRP2040はGPIOが30本あるのでちょうど良さそうです。
左上の2ピンはCAPSLOCKとSCRLOCKのLEDを制御しています。
残りはキーマトリクスのスキャンに使われているようですが、
トッププレートで表面のパターンを追えずどれがCOLでどれがROWかも分かりません。
テスターで1つずつ調べるのも面倒なので、先に基板を作ってから調べることにしました。
全てのGPIOがデジタル出力/入力に対応しているので多分大丈夫です(大丈夫か?)。
基板を設計する
設計にはKiCADを使います。
RP2040ははじめてですが、RP2350の経験があるため割とサクサク進みました。
適宜ハードウェアデザインガイドを参照しつつ設計していきます。
- マイコンの配置
基板サイズが小さいうえにほぼ全てのピンを引き出す必要があるため苦労しました。
配線を0.1mmとかにすればもう少し余裕があったと思います。
両サイドのバイパスコンデンサを省略してますが良くないのでやめましょう。
- USBの配線
ピンヘッダのD+、D-とマイコンのD+、D-の配置が逆でした。
ビアを使って交差させるのはちょっと怖いので基板の外側から引き回しています。
D+、D-は作動ペアですがUSB2.0ならこれでも何とかなっています。
- 周辺回路
フラッシュメモリと発振器は無難に推奨品を採用しました。
3.3Vのレギュレータは手持ちの「MIC5528-3.3YMT-TR」を使います。1.2x1.2mmで500mA流せて、静止電流は38uAなので文句なしです。
- LEDのドライブ回路
当初GPIOで直接制御しようとしましたが、どうもアノードが5V固定・引き込みで制御しているようです。RP2040のGPIOは3.3Vなので電圧が合いません。
適当な2回路入りのMOSFETで制御することにします。
そのほか、BOOTとRESETスイッチ(裏返しても押せるようサイドプッシュタイプを選択)、デバッガ接続用のコネクタ(多分使わないけど)も入れておきます。
デザインルールチェック(DRC)でエラーが出ていないことを確認し、製造用データを出力します。業者に合わせたプラグインを使うとまとめて出力してくれるので便利です。
基板を発注する
基板の製造はいつも使っている JLCPCB にお願いしました。
DFMチェック
見積もり画面でデータをアップロードしたら、発注前にGarber Viewerから DFM check を実行して製造上問題ないかチェックすることをお勧めします。
エラーは修正しましょう。シルクの潰れ・欠けは動作に影響ないので無視します。
Annular ring にエラーが出まくっていますが、図面上スルーホールとビアの区別がつかないため出ているだけで製造上は問題ありません。
オレンジの警告はリスクと修正の面倒くささ要求される仕様を天秤にかけて判断します。
まあ大抵は問題ないと思います。
ステンシルの発注
今回はホットプレートリフローで実装するので、はんだペーストを塗るためのステンシルも発注しておきます。
小さい基板の場合は「Custom Size」でサイズを調整しましょう。
でないとクソデカステンシルが届いて椅子から転げ落ちます(経験済み)。
配送業者の選択
配送業者は最安のOCS NEPを選択しました。
評判は怪しいですがANA系列ですし、今のところ4日程度で届いています。
(途中で追跡不能になっていきなり届くのはやめてほしいですが)
基板5枚とステンシル、送料合わせて 約9.8USD でした。安すぎて怖い。
その他部品の調達
足りない部品はDigiKeyで発注しました。
2mmのピンヘッダなどは手に入るものは秋月電子で購入しています。
基板へ部品を実装する
発注からちょうど1週間で基板が届いたので実装していきます。
実装中の写真はほとんど撮っていないので、代わりにICHIKENさんの動画を貼っておきます。
だいたいこんな感じで実装しています。
結構失敗したので修正
はんだブリッジや部品の浮き・ずれなど実装不良がそこそこありました。
以下の要因が考えられます。
- 期限切れのはんだペースト(1年以上過ぎてる)
- はんだペーストの盛りすぎ(ヘタクソ)
- 加熱のしすぎ(2,000円ホットプレートで温度調節が難しい)
IC部品のブリッジはフラックスを塗ってK型のこて先などでなぞると簡単に修正できます。
ずれていた部品は0201(0.6x0.3mm)のコンデンサで、手はんだでの修正が大変でした。
そのほか、MOSFET(写真のQ1)が浮いていてLEDが片方点灯しませんでしたが、チップを抑えながら横から加熱してなんとか修正しました。
通電前に最低限、電源周り(5V・3V3・1V1・GND)のショートが無いか確認しておきます。
また、今回はUSB周りに保護回路を入れていないので、PCへつなぐ前に別のマイコンボード経由で5Vを通電し、3V3と1V1が正常に出ていることも確認しました。
ここまで来たら基板をキーボードに差し込んでPCへ繋ぎ、SW2(BOOT)を押しながらSW1(RESET)を押してブートモードに入ります。
PCにストレージとして認識されることを確認できたらOKです。
ファームウェアの書き込み
QMK自体使うのは初めてなので環境のセットアップから始めます。
公式のガイドではWindowsの場合「QMK MSYS」というMSYS2のバンドルが推奨されていますが、今回 QMK WSL なるものを見つけたのでこちらを使ってみます。要するにWSL向けのQMKセットアップ済みディストリビューションのようです。
Getting Startedに従いセットアップしたら qmk new-keyboard でキーボードを追加します。
名前は適当に設定して、
-
Default Layout?:58. tkl_ansi(US配列テンキーレス) -
Using a Development Board?:n(既存のマイコンボードではないためno) -
Microcontroller?:21. RP2040(RP2040を選択)
としておきます。
あとは生成されたkeyboard.jsonにピンの割り当てを記述していくだけですが、
どのキーがどのピンに割り当てられているのかまだ分かっていません。
先に割り当てを調べるプログラムを作成して書き込んでいきます。
ピン割り当てを調べるコード(クリックで展開)
#include <stdio.h>
#include "pico/stdlib.h"
static const uint PINS[] = {
2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29
};
static const uint NUM_PINS = sizeof(PINS) / sizeof(PINS[0]);
void init_all_ios() {
// 全ピン初期化
for (uint i = 0; i < NUM_PINS; i++) {
gpio_init(PINS[i]);
gpio_set_dir(PINS[i], GPIO_IN);
gpio_pull_down(PINS[i]);
}
}
void scan_single_key() {
while (true) {
for (int i = 0; i < NUM_PINS; i++) {
uint out_pin = PINS[i];
// ターゲットのピンを出力に切り替えて High にする
gpio_set_dir(out_pin, GPIO_OUT);
gpio_put(out_pin, 1);
sleep_us(10);
// 他のすべてのピンをチェック
for (int j = 0; j < NUM_PINS; j++) {
uint in_pin = PINS[j];
// ターゲットピンは飛ばす
if (out_pin == in_pin) continue;
if (gpio_get(in_pin)) {
// Highを検知したら結果を表示して終了
printf("Detected connection: Output Pin %d -> Input Pin %d\n", out_pin, in_pin);
gpio_put(0, 1); // LED1は点灯
gpio_put(1, 0); // LED2は消灯
return;
}
}
// 次のピンを試す前に元に戻す
gpio_put(out_pin, 0);
gpio_set_dir(out_pin, GPIO_IN);
gpio_pull_down(out_pin);
}
}
}
int main() {
stdio_init_all();
// インジケーターLED初期化
gpio_init(0); // LED1:押下検知
gpio_init(1); // LED2:待機中
gpio_set_dir(0, GPIO_OUT);
gpio_set_dir(1, GPIO_OUT);
uint count = 0;
while (true) {
// IO初期化
init_all_ios();
printf("%03d: Starting matrix scan... ", count);
// LED初期化
gpio_put(0, 0);
gpio_put(1, 1);
sleep_ms(500);
// 押下検知までスキャン
scan_single_key();
count++;
// 検知してから1秒たったら押下待機
sleep_ms(1000);
}
}
キーを押下するとシリアルモニタで対応するピンが表示されるので、これを頼りにピンを設定していきます。
余談ですが、
同じ列でもCOLとROWがバラバラだったりして少し混乱しました。もう少し整然と並べても良さそうですが、なにか理由があるんでしょうか?(Majestouchの初代は片面基板だったらしいのでその頃の名残とか?)
CAPSLOCKとSCRLOCKの設定も以下のように入れておきます(一応 keymap.c にハンドラを定義する方法もあるようです)。
"indicators": {
"caps_lock": "GP1",
"scroll_lock": "GP0",
"on_state": 1
}
レイアウトが完成したら qmk compile を実行して、生成されたuf2ファイルを書き込んで完成です。キーボードテストなどで動作を確認しましょう。
本来USB接続では出来ないNキーロールオーバーが実現できました。
おわりに
ゆくゆくはキーマップをカスタムしたり、ファームウェアを書き換えずにキーマップを変更できる Vial など導入してみたいですが、今回はここまで。
Majestouch Ninja Tenkeylessは10年以上前のキーボードです。
全体的な質感や打鍵感など、最新の高級キーボードとは比べるべくもないと思います。
一方で使用感にこれといった不満もなく、
初めて自作PCを組んだ時に買った思い入れのあるキーボードなので、これからも使い続けていくことになるでしょう。なんだかキーボード作りたくなってきたな...。
ここまで読んでいただきありがとうございました。
参考
-
【基板作成編】Majestouchキーボードの改造: 暫定ぶろぐぺーじNEXT
同じタイプの制御基板を自作されている記事です。LEDの配線など大変参考にさせていただきました。






