Elite-Cや一部のPro Micro互換機における挙動の問題と対策
はじめに
多くの自作キーボードにおいて、そのMCUにPro Microおよびその互換機が使用されており、多くの場合がPro Micro互換機だと思います。当店においても互換機を取り扱っております。その互換機ですが、最近流通しているいくつか製造ロットにおいてVCCでの出力電圧が5Vきっちりに出力されるために、ファームウェア側で対応が必要になる場合があります。またElite-Cにおいても同様の問題が報告されております。
対応が必要になるのは分離型キーボードのみです。下記症状にあたった場合には、ご確認いただければと思います。
- ファームウェア書き込み後、片手ずつでは動作する
- 両手をTRRS/TRSケーブルで接続し、片手(primary側)をUSBケーブルにてPCにつなぐと、もう片手(secondary側)がまったく反応しない*1
TL;DR
QMKファームウェアにて keymap.c
あるいは config.h
等にて下記のように SPLIT_USB_DETECT
を定義してファームウェアを焼き直してください。
#define SPLIT_USB_DETECT
詳細
この症状に関しての詳細は @kaoriya さんの記事に解説されています。
以下、この SPLIT_USB_DETECT
のフラグを立てることでどういった影響があるのか、QMK Firmware内での動作に関する簡単な解説です*2。
このフラグを立てると、split_util.c
というファイル内の次のセクションの最初のケースが呼ばれます。
#if defined(SPLIT_USB_DETECT) # if defined(PROTOCOL_LUFA) static inline bool usbHasActiveConnection(void) { return USB_Device_IsAddressSet(); } static inline void usbDisable(void) { USB_Disable(); USB_DeviceState = DEVICE_STATE_Unattached; } # elif defined(PROTOCOL_CHIBIOS) static inline bool usbHasActiveConnection(void) { return usbGetDriverStateI(&USBD1) == USB_ACTIVE; } static inline void usbDisable(void) { usbStop(&USBD1); } # elif defined(PROTOCOL_VUSB) static inline bool usbHasActiveConnection(void) { usbPoll(); return usbConfiguration; } static inline void usbDisable(void) { usbDeviceDisconnect(); } # else static inline bool usbHasActiveConnection(void) { return true; } static inline void usbDisable(void) {} # endif bool usbIsActive(void) { for (uint8_t i = 0; i < (SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL); i++) { // This will return true if a USB connection has been established if (usbHasActiveConnection()) { return true; } wait_ms(SPLIT_USB_TIMEOUT_POLL); } // Avoid NO_USB_STARTUP_CHECK - Disable USB as the previous checks seem to enable it somehow usbDisable(); return false; } #elif defined(PROTOCOL_LUFA) && defined(OTGPADE) static inline bool usbIsActive(void) { USB_OTGPAD_On(); // enables VBUS pad wait_us(5); return USB_VBUS_GetStatus(); // checks state of VBUS } #else static inline bool usbIsActive(void) { return true; } #endif
ここで実装されている usbIsActive()
は、同ファイル下部の is_keyboard_master()
という関数内で呼ばれています。*3
__attribute__((weak)) bool is_keyboard_master(void) { static enum { UNKNOWN, MASTER, SLAVE } usbstate = UNKNOWN; // only check once, as this is called often if (usbstate == UNKNOWN) { usbstate = usbIsActive() ? MASTER : SLAVE; } return (usbstate == MASTER); }
ここで usbstate
が UNKNOWN
の場合にのみ usbIsActive()
が呼ばれ、その結果で usbstate
が MASTER
および SLAVE
となります。この usbstate
はstaticローカル変数のため、関数の実装を見る限り、UNKNOWNの状態なるのは一度だけであとは必ず MASTER
か SLAVE
の値が設定されています。(コメントにも「 is_keyboard_master()
は頻繁に呼ばれるので、UNKNOWN
に関する処理は一度しか行われないようにする」と記載があります)
つまり、 SPLIT_USB_DETECT
のフラグを設定して影響が起きるのは、キーボードをPCにつないで初めて左右のprimaryの判定をするときだけ、ということになります。私もこのフラグをオンにして使用してみていますが、キーボードの使用中にパフォーマンスが劣化する、といった症状は一切見られていません。
(2021.03.14 00:00 追記)@kaoriya さんが追加の記事を書いてくださっています。キーボードとしての動作自体には影響がないものの、装飾のLEDなどに対して注意するべきポイントを解説してくださっています。
参照
- 30キー左右分離キーボードfoobarをPico Micro Cで作った - golden-luckyの日記
SPLIT_USB_DETECT
をオンにして快適に使用されているそうです
- The Case of the Wayward Elite-C. For some DIY mechanical keyboards… | by Keebio | Medium
- Elite-Cにおける電圧問題を詳細に解説しています
- Lunakey Miniが片手だけ動かなかったときに確認すること
- @yoichiro さんによる検証記事です