[自作キーボード]QMKファームウェアでシリアルLED(WS2812B)に対応する ~基本編~

目次

Abstract

  • RP2040, QMK環境でシリアルLED(RGB LED)に対応してみた
  • LEDの操作は直接QMKのシリアルLED操作用の関数を使って制御
  • レイヤー機能とかを使う方は次回

Introduction

前回記事から半年近く空いちゃってますが、気が向いたのでまた自作キーボード作りに取り組みたいと思います。 LCDとか分割キーボードの前にやる話なような気がしますが、LED対応してなかったのでLED対応の記事です。

Preparation

シリアルLED(フルカラーLED)とは

通常の2本足生えたLEDと異なり、制御信号を送ってあげることでRGBの色や輝度を変更できるLED。 詳細はマルツの解説ページがわかりやすいです。

シリアルLEDの使用方法

QMKのドキュメントページ(https://docs.qmk.fm)を見るとシリアルLEDを使うページは以下の2種類有ります。

  • RGB Lighting
    • キーボードマトリクスなどとは連動しない方で、アンダーグローなどに使われる方。
    • 個別のキー押下などには連携しない。
  • RGB Matrix
    • キーボードマトリクスと同じようにLEDでマトリクスを組んで制御する方
    • 個別のキー押下に応じた動作とかも可能。

作りたいキーボードではフルカラーLCDも使う予定ですし、キーボード前面をビカビカ光らせてもごちゃごちゃしそうなのです。使うとしたらアンダーグローやインジゲータ的な使い方をすると思うので今回はRGB Lightingの方を見ていきます。

RGB Lightingのページを見ると使用可能なシリアルLEDが列挙されていますが、WS2812BのRev5が3.3Vの信号入力に対応していてRP2040に接続しやすそうなのでそちらを使います。

使用部品

今回のお試しでは以下の部品を使用します。

回路

  • シリアルLED繋ぐだけなので、回路図は用意無し。RP2040と1つ目のWS2812Bの各ピンに以下を割り当てます。
  • WS2812BのV5はパスコンとかも不要なので直接繋ぐだけ。
  • 2番目以降のLEDはDOUT->DINとなるようにして数珠つなぎに繋ぐ
  • 今回は2個だけつなぎます
WS2812B PIN RP2040 PIN NOTE
VDD VBUS(5V)
DOUT - 後続のWS2812BのDINに接続
VSS(GND) GND
DIN GP16 どのピンでも問題無し

Method

QMKのRGB Lighting, info.json Reference※のページを参考にシリアルLEDに対応します。 ※RGB Lightningのページでは、info.json使わない古い記載方法しかないので、そちらはinfo.json Referenceのページを参考にしてます。

やることはRGB Lighting機能の有効化, RGB Lightingの設定、WS2812ドライバの設定、デフォルトの発光設定の4つです。

0. QMKで新規でキーボードファイルを作成する

久しぶりなので以前の記事を参考にqmk new-keyboardでファイルを作成します。今回はrp2040ledという名前のフォルダにしました。

[自作キーボード]QMKでRP2040用のファームウェアを作成する~その1~


1. RGB Lighting機能の有効化

  • info.jsonのfeaturesキーのところで以下のようにrgblightをtrueを記載するだけ

info.json

    "features": {
        ~~省略~~
        "rgblight": true
    },

2.RGB Lighting機能の設定

  • info.json のrgblightキーの中に設定を記載します
  • 設定できる項目については、以下に記載があります
  • Mustで必要なのは接続するシリアルLEDの数を示すled_countのみです
  • 今回は必要最低限ということでled_countのみ設定します
    • 今回は2つ繋ぐので2を設定しています。

info.json

    "rgblight": {
        "led_count": 2
    },

3. WS2812ドライバの設定

  • info.json のws2812キーで設定します
  • 設定可能な値は以下を参照
  • Mustで設定が必要なのはdriver, pinの2つ
    • driver
    • pin
      • DINに接続するGPIOピンを設定します
        • RP2040でPIOを使用する場合、ピン配置の制約は無いです。

info.json

    "ws2812": {
        "driver": "vendor",
        "pin": "GP16"
    },

4. LEDのデフォルトの発光設定を行う

  • keymap.cでシリアルLED操作用の関数を叩くことで設定を行います。
  • シリアルLED操作用の関数は以下のページに一覧があります。
  • 今回は簡単な3つの操作関数だけピックアップ
    • void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val)
      • 接続している全てのシリアルLEDに対して同一の値で設定をする関数
      • HSVの各値はデザイン系でよくあるH:0-360°, S:0-100%, V:0-100%での設定ではなく、それを8bitの0-255に落とし込んだ値を使用するので注意
    • void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index)
      • 引数indexで指定したLEDにだけ設定をする関数
        • LEDのIndexはDINに最初に接続されたものから順番に1,2,3,・・・と振られていく
    • void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end)
      • 引数start, endの間のIndexのLEDにだけ色設定をする関数
      • 1行のみ色変えるとかみたいなときに使うといいかも
  • 今回はせっかく2つあるので、rgblight_sethsv_at()でそれぞれ別々の色を設定します。
  • 処理はキーボード接続時の初期の発光設定なので、keyboard_post_init_user()関数の中に記載します。

keymap.c

void keyboard_post_init_user(void) {
    // すべてのLEDに同じ設定をする場合はこちらの関数
    // rgblight_sethsv(127, 255, 100) CYAN

    // 1つ1つのLEDに設定をする場合はこちらの関数
    rgblight_sethsv_at(127, 255, 100, 0);   // 1番目のLEDの設定, CYAN
    rgblight_sethsv_at(0, 255, 100, 1);   // 2番目のLEDの設定, RED
}

※MAXの255輝度だと眩しいので100くらいに抑えています。

補足 info.json内でのLEDのデフォルト発光設定

info.jsonのrgblight - defaultの中でできるはずなのですが、私の環境ではうまくいきませんでした。そのため、↑のようにkeymap.c内で直接シリアルLED用操作用の関数を叩いています。

Result

qmk compile -kb cepst/rp2040led -km defaultでコンパイルを実施、特に問題なくビルドできたので、書き込みして確認。無事に1番目と2番目を別々の色で光らせられました。


↑写真だと上手く色出てないですが、青と赤で発光してます

Conclusion

info.jsonkeymap.cにちょっとコードを記載するだけで、シリアルLEDの制御できて楽ちんですね。ビカビカ光らせるのはあれですが、アンダーグローとかインジゲーターとかでは使いたいと思っていたので簡単につかえて良かったです。あと、QMKではシリアルLEDの色の調整機能を持つキーコードがあり、そのキーコードをキーに割り当てることでLEDの状態を制御できます。そちらについては本編に書けなかったのでAppendixの方に記載することにします。

次回は、直接LEDを操作せずQMKのレイヤー機能を使用してLEDを制御しようと思います。



Appendix

キーコードを使用してシリアルLEDを制御する

  • QMKでRGB Lighting, RGB Matrix用にLEDを制御するキーコードが用意されてます。
  • keymap.cのkeymapでキーにそれらのキーを割り当ててあげることで、LEDの発光を制御できます
    • HSVの調節は以下の3パターンのキーコードを使用します("~I"が増加(Increase), “~D"が減少(Decrease)です)
      • Hue
        • RGB_HUI, RGB_HUD
      • Saturation
        • RGB_SAI, RGB_SAD
      • Value
        • RGB_VAI, RGB_VAD
    • LED自体のON/OFFは以下
      • RGB_TOG

keyamap.c

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT_ortho_1x4(
        RGB_VAI,    RGB_VAD,    KC_A	, KC_B
        // KC_A, KC_B, KC_C, KC_D
    )
};

↑の設定のキーコード使用して操作してみた動画
上側のキーがValue, 下側のキーがHueを操作しています


シリアルLED操作用の関数を使用して制御する

↑の動画を見ると、LED1に青、LED2に赤を設定しているのにValueを下げる操作をすると全て同一の色に変わっており、キーコードを使用して操作をすると、全てのLEDに対して同一の色設定が適用されてしまうようです。

全てのLEDに対してHue/Sat/Valだけを独立して操作する※ことは↑のやり方だとできなそうなので、 それをやりたい場合はkeymap.c側でrgblight_sethsv_at()を使って自分で制御書くのが手っ取り早そうです。
 ※各LEDのHueだけ+方向に変化させて、Sat/Valは独立させて変化させないなど

追記)
調べたら、レイヤー機能使ってRGBLIGHT_LAYERS_RETAIN_VAL を使えば、各LEDの色を別々に定義でき、RGB_VAI/RGB_VADを使って独立してVal(輝度)だけを増減させるというのはできるみたい。Hue/Satだけ変化させたいことはあまりなさそうなのでそちらの手段でも良いかも。レイヤー機能は次回で解説予定なので詳細はそちらで。ただ、結局1個1個のLEDを独立制御したいとかの場合は、低級関数のrgblight_sethsv~()を使うしか無いかも。