YAMAGUCHI::weblog

海水パンツとゴーグルで、巨万の富を築きました。カリブの怪物、フリーアルバイター瞳です。

QMK FirmwareでバックライトLEDを制御する

はじめに

こんにちは、Google Cloud Operations担当者です。もうStackdriverという名前は忘れてください。最近はキーボードをたくさん作っていますが、Helix 4行ではじめてバックライトLEDなキーボードを作って、その後foobarやLet's SplitをテープLEDでアンダーグロー化しました。最初はプリセットのアニメーションで遊んでただけだったんですが、どうせならちゃんとレイヤーやキーに応じてバックライトの色を変えたいと思ったので実際にやってみました。

HelixはバックライトLEDでより多くの制御が可能で、キートップからも見えて楽しいので、以下Helix 4行での実装となります。ただしRGB Lightingをつかっている実装であればどれでも同様に可能です。

QMK RGB Lighting

docs.qmk.fm

QMKにはいくつかのLEDの制御方法がありますが、HelixはバックライトがシリアルLEDとして動作していることもあり、RGB Lightingを使って制御するのが良さそうです。(ドキュメント見ながら調べていたらSMKIJのscrapboxにそう書いてあったので、そのまま参考にした)

rules.mk

RGB Lightingを使うときはいくつかのフラグを有効にしたりヘッダファイルをincludeしてあげる必要があります。LEDを制御する場合は次のフラグを有効にします。

RGBLIGHT_ENABLE = yes

Helixの場合はデフォルトでいろいろ設定されていて、 LED_ANIMATIONS = yes とすれば諸々アニメーションに関するフラグが設定されます。このフラグはプリセットのLEDアニメーション(グラデーションで色が時間変化していくとか)を動かすためのフラグで、それ以外に必要なフラグはHelixでは上の階層の rules.mklocal_features.mk で設定してくれています。

config.h

次に config.h でマクロ定数をいくつか定義します。ビルドガイドに何かしらフルカラーLEDに対応というようなことが書いてあれば、キーボードのデフォルトの config.h ですでに設定されていると思いますが、2017年かそれ以前に設計されたような基板ではまずProMicroのどのピンでLEDを制御するかのマクロ変数を定義します。次の例はfoobarでLEDテープを実装したときのものです。

#define RGB_DI_PIN B6

ここのピンの番号はProMicroのポートの番号です。

f:id:ymotongpoo:20200909213604p:plain

で、それ以外の細かな部分のマクロ変数を定義します。各変数の細かな説明は公式ドキュメントを読んでください。(非常に投げやりな説明)次の例はHelix 4行でのものです。

#define RGBLIGHT_LAYERS
#undef RGBLED_NUM
#define RGBLED_NUM 50
#define RGBLED_SPLIT {25, 25}
#define RGBLIGHT_MAX_LAYERS 8

#define LED_LAYOUT( \
    L00, L01, L02, L03, L04, L05,           R00, R01, R02, R03, R04, R05, \
    L10, L11, L12, L13, L14, L15,           R10, R11, R12, R13, R14, R15, \
    L20, L21, L22, L23, L24, L25,           R20, R21, R22, R23, R24, R25, \
    L30, L31, L32, L33, L34, L35, L36, R30, R31, R32, R33, R34, R35, R36 \
) { \
    L05, L04, L03, L02, L01, L00, \
    L10, L11, L12, L13, L14, L15, \
    L25, L24, L23, L22, L21, L20, \
    L30, L31, L32, L33, L34, L35, L36, \
    R00, R01, R02, R03, R04, R05, \
    R15, R14, R13, R12, R11, R10, \
    R20, R21, R22, R23, R24, R25, \
    R36, R35, R34, R33, R32, R31, R30 \
}

#define RGBLIGHT_LED_MAP LED_LAYOUT( \
   0,  1,  2,  3,  4,  5,            30, 29, 28, 27, 26, 25, \
   6,  7,  8,  9, 10, 11,            36, 35, 34, 33, 32, 31, \
  12, 13, 14, 15, 16, 17,            42, 41, 40, 39, 38, 37, \
  18, 19, 20, 21, 22, 23, 24,    49, 48, 47, 46, 45, 44, 43)

RGBLIGHT_LAYERS を呼ぶのを忘れると、次のようにエラーがでます。(ドキュメントにちゃんと書いてあったのに雰囲気でやったらはまった)

$ sudo ./util/docker_build.sh helix/rev2:ymotongpoo
QMK Firmware 0.9.55
Making helix/rev2 with keymap ymotongpoo

avr-gcc (GCC) 5.4.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Size before:
   text    data     bss     dec     hex filename
      0   26300       0   26300    66bc .build/helix_rev2_ymotongpoo.hex

Compiling: keyboards/helix/rev2/keymaps/ymotongpoo/keymap.c                                        keyboards/helix/rev2/keymaps/ymotongpoo/keymap.c:52:7: error: type defaults to 'int' in declaration of 'rgblight_segment_t' [-Werror=implicit-int]
 const rgblight_segment_t PROGMEM _default_layer[] = RGBLIGHT_LAYER_SEGMENTS(
       ^
keyboards/helix/rev2/keymaps/ymotongpoo/keymap.c:52:34: error: expected ',' or ';' before '_default_layer'
 const rgblight_segment_t PROGMEM _default_layer[] = RGBLIGHT_LAYER_SEGMENTS(
                                  ^
...(中略)...

keyboards/helix/rev2/keymaps/ymotongpoo/keymap.c:70:25: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
 const rgblight_segment_t* const PROGMEM rgblight_layers[] = RGBLIGHT_LAYERS_LIST(
                         ^
cc1: all warnings being treated as errors
 [ERRORS]
 |
 |
 |
make[1]: *** [tmk_core/rules.mk:386: .build/obj_helix_rev2_ymotongpoo/keyboards/helix/rev2/keymaps/ymotongpoo/keymap.o] Error 1
Make finished with errors
make: *** [Makefile:584: helix/rev2:ymotongpoo] Error 1

シリアルLEDとして扱うので、LEDの長さと左右のキーボードでの分割のされ方を教えるために、RGBLED_NUM, RGBLED_SPLIT を設定します。またデフォルトだとLEDの番号は左手右上から始まり、そこからジグザグに番号がついていてわかりにくいので、番号のアサインを変更するために LED_LAYOUTRGBLIGHT_LED_MAP を設定します。 (下の図は参照のブログより転載)

f:id:ymotongpoo:20200824010006p:plain

これで下準備が完了です。

keymap.c

keymap.c ではまず上のように配置されたLEDを各々どのような色にするかの設定を RGBLIGHT_LAYER_SEGMENTS マクロで行います。マクロ内で指定する値は {LEDマップ名の番号, 連続して設定するLEDの数, 色} となります。たとえば {6, 4, HSV_GREEN} であれば、番号6から9までの4つを緑にします。

const rgblight_segment_t PROGMEM rgb_default_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    {0, 1, HSV_GREEN}, // left
    {6, 1, HSV_GREEN},
    {12, 1, HSV_GREEN},
    {18, 4, HSV_GREEN},
    {22, 2, HSV_CHARTREUSE},
    {24, 1, HSV_PURPLE},

    {25, 1, HSV_GREEN}, // right
    {31, 1, HSV_GREEN},
    {37, 1, HSV_GREEN},
    {43, 4, HSV_WHITE},
    {48, 2, HSV_PURPLE}
);

const rgblight_segment_t PROGMEM rgb_lower_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    {1, 5, HSV_PINK}, // left
    {6, 12, HSV_CORAL},

    {26, 5, HSV_PINK}, // right
    {31, 12, HSV_AZURE},
    {43, 4, HSV_BLUE}
);

const rgblight_segment_t PROGMEM rgb_raise_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    {1, 5, HSV_CORAL}, // left
    {7, 4, HSV_WHITE},

    {26, 5, HSV_CORAL}, //right
    {32, 4, HSV_WHITE},
    {43, 4, HSV_BLUE}
);

ここでは3つのLED用のレイヤーを定義しました。これらのレイヤを使うことをRGBLIGHT_LAYERS_LISTを使って登録します。

const rgblight_segment_t* const PROGMEM rgb_layers[] = RGBLIGHT_LAYERS_LIST(
    rgb_default_layer,
    rgb_lower_layer,
    rgb_raise_layer
);

この状態ではLEDのレイヤーを使うことを定義して宣言したまでなので、次は実際にキーマップのレイヤーと対応させる必要があります。その対応は layer_state_set_user() 内で rgblight_set_layer_state() で行います。書き方は

rgblight_set_layer_state(RGBLIGHT_LAYER_SEGMENTSマクロで返される配列でのインデックス, 何かしらのbool条件)

キーマップのレイヤーの状態が state に入ってくるので、keymaps[] に指定した添字で対応させるのに layer_state_cmp() を使います。

layer_state_t layer_state_set_user(layer_state_t state) {
    rgblight_set_layer_state(0, layer_state_cmp(state, _QWERTY));
    rgblight_set_layer_state(1, layer_state_cmp(state, _LOWER));
    rgblight_set_layer_state(2, layer_state_cmp(state, _RAISE));
    return state;
}

これでレイヤーに応じて左右の両方のキーボードで異なるパターンのLEDを光らせられるようになり、ぱっと見ただけでレイヤーに配置した特殊キーの場所が把握できるようになりました。便利!

f:id:ymotongpoo:20200908235822j:plain

www.youtube.com

参照

rephtone.com

www.tnksoft.com