⌨️

QMKでPro Micro用のファームを小さくする

2022/01/22に公開
2

本記事はSqueezing the most out of AVR (AVRの性能を最大限に引き出す)の抄訳とちょっとした解説です。

QMKとPro Microを用いた自作キーボードにおいては、増大する機能に対してMCUであるAVR ATmega32U4の容量制限がわずか28KBとあまりに小さく、ファームウェアの容量が逼迫しがちです。上記の記事にはそんなファームウェアのサイズを小さくするためのTIPSが紹介されています。

本記事はそんな省サイズ化のTIPSを日本語で要約し補足説明するものです。各施策ごとにどのような内容なのか、それによりファームウェアサイズをどの程度削減できるのか、考えられるデメリットは…といったことを説明します。なお記載した削減サイズはあくまでも目安であり、必ずしもそこで示した分が削減できるとは限らないことに注意してください。

本記事の末尾には私のオススメ度ともに一覧表としてまとめてあります。


AVRの性能を最大限に引き出す

rules.mkファイルでの設定

LTO_ENABLE = yes

リンク時最適化を行います。リンク時にオブジェクトファイルを超えて関数をインライン展開することで関数呼び出しにかかるオーバヘッドを削減できます。どのくらい容量が削減できるかはプログラムの内容に依存するのですが概ね3000~4000バイトくらい減るでしょう。

副作用としてNO_ACTION_MACRONO_ACTION_FUNCTIONが設定されます。これらは古い機能なので通常は問題になりません。またリンクにかかる時間が伸びますが、そもそもが小さいプログラムなので問題にはならないでしょう。

デフォルトでは無効化されていますが、少し機能の多いファームをビルドするには必須といえる機能です。

CONSOLE_ENABLE = no

コンソール機能を無効化します。必要なのは開発時にprintfデバッグをする時くらいなので特に必要とはなりません。

デフォルトでは無効化されています。約3800バイトくらい削減できます。

COMMAND_ENABLE = no

コマンド機能を無効化します。コマンド機能はファームを書いたりプラグを抜いたりせずにキーボードの動作を変更する機能で、多くの機能がMagicキーコードと重複しています。そのためこの機能が必要とされるケースは少ないと言えます。

デフォルトでは無効化されています。約350バイトくらい削減できます。

MOUSEKEY_ENABLE = no

マウスキー機能を無効化します。マウスキーはキー操作でマウスポインタを動かしたりマウスボタンを押したりする機能です。使えれば便利な機能ではありますが、通常はマウスやトラックボールなどのポインティングデバイスのほうが使いやすいので有効化する動機は強くありません。

デフォルトでは無効化されています。約1100バイトくらい削減できます。

EXTRAKEY_ENABLE = no

エクストラキー機能を無効化します。エクストラキーとはオーディオのボリュームやその他システムの制御を行うキーのことです。これも使えれば便利な機能ではありますが、無くても許容しやすい機能です。

デフォルトでは無効化されています。約330バイトくらい削減できます。

SPACE_CADET_ENABLE = no

スペース・カデット機能を無効化します。スペース・カデットは左右のシフトキーとコントロールキーのタッピングに開閉カッコ(&)を割り当てる機能です。

デフォルトでは有効化されています。約360バイトくらい削減できます。

GRAVE_ESC_ENABLE = no

GRAVE_ESCキーコードを無効化します。GRAVE_ESCキーコードは単体ならばエスケープ、シフトかGUIボタンと一緒に押すと~(GRAVE)を入力できるキーコードです。

デフォルトでは有効化されています。約90バイトくらい削減できます。

MAGIC_ENABLE = no

マジックキーコードを無効化します。マジックキーコードはファームウェアを書き換えたりせずに、一部のキーボードの動作を変更する機能です。

デフォルトでは有効化されています。約600バイトくらい削減できます。

config.hファイルでの設定

LOCKING_XXXの無効化

メカニカルロックサポートを無効化します。2015年に製造中止になったCherry MX Lockキースイッチ(ラッチ動作)をサポートする機能なので、現在必要とされる可能性は低いです。無効化するにはconfig.hに以下のように記述します。

#undef LOCKING_SUPPORT_ENABLE
#undef LOCKING_RESYNC_ENABLE

デフォルトでは有効化されています。テンプレートdata/templates/avrに記載されているため普通は有効化されています。約170バイトくらい削減できます。

NO_ACTION_ONESHOT

ワンショットキー機能を無効化します。ワンショットキー機能はキーの同時押しを好まない(もしくはそれが難しい)人のための機能です。そのため一概に無効化して良いとは言えません。

デフォルトでは有効化されています。約350バイトくらい削減できます。

NO_ACTION_TAPPING

タップダンスやその他のタッピング機能を無効化します。タッピングは自作キーボードにおいて人気の機能であるため無効化するのはとても難しいのですが、削減できるサイズがかなり多きいので魅力的とも言えます。

デフォルトでは有効化されています。約1800バイトくらい削減できます。

NO_ACTION_ONESHOTと合わせて無効化することでさらに約280バイト削減でき、合計約2440バイトも削減が見込めます。

オーディオ設定

オーディオ機能を使っている場合、ミュージックモードが有効になっています。しかし使ってない場合が多いのではないでしょうか? そんな場合はconfig.hに以下を書いた上で

#define NO_MUSIC_MODE

rules.mkに次を書くことで無効化できます。

MUSIC_ENABLE = no

本設定は試せていないのでどの程度の削減効果があるかは不明です。

レイヤー

レイヤーステートを表すビット数(≒レイヤーの数)を制限します。QMKは最大で32枚のレイヤーを持てます。これを16枚、もしくは8枚に制限することでレイヤーを表す値に小さいビット数を用いることが可能になりファームウェアを小さくできます。

特にVIAを使用する場合にはデフォルトではレイヤーが4枚に制限されます。そのためレイヤーステートを32枚用に32ビットにしておくのは無駄となってしまうため、変更を強くお勧めします。

レイヤーステートを8ビットにするには以下をconfig.hに記述します。

#define LAYER_STATE_8BIT

レイヤーステートを16ビットにするには以下をconfig.hに記述します。

#define LAYER_STATE_16BIT

デフォルトでは32ビットです。16ビットにすることで約330バイト削減でき、8ビットにした際には32ビットに比べて約450バイト削減できます。

仮にレイヤーを全く使わないのであれば次をconfig.hに書くことで無効化してしまうこともできますが、現実的な選択肢ではないでしょう。現実的ではないので試しておらず削減できるサイズは不明です。

#define NO_ACTION_LAYER

Magic関係の関数

マジックキーコードをカスタマイズするために2つのオーバーライド可能な関数があります。MAGIC_ENABLE = noを設定してマジックキーコードを無効にしているのならば、ほぼ間違いなくこれらの関数(の中身)は必要ありません。以下のような関数を書き加えてその内容を無効化できます。

uint16_t keycode_config(uint16_t keycode) {
    return keycode;
}

uint8_t mod_config(uint8_t mod) {
    return mod;
}

これにより500~600バイトを削減できます。

OLEDの微調整

OLEDに情報を表示する際にsprintfsnprintfといった関数を使うのを止めましょう。これらのフォーマット関数はそれだけで約1500バイトも消費してしまいます。

以下のようなsprintfを使った情報表示ルーチンがあったとします。

// OLD CODE
char wpm_str[9] = {0};
sprintf(wpm_str, "WPM: %3d", get_current_wpm());
oled_write(wpm_str, false);

これは次のようにget_u8_strを使って書き換えられます。

// NEW CODE
oled_write_P(PSTR("WPM: "), false);
oled_write(get_u8_str(get_current_wpm(), ' '), false);

RGB(LED)の設定

RGB LightやRGB Matrixを使っているならば、効果やアニメーションを個別に無効化することでサイズを削減できます。計測はしていないので個々で削減できる量は不明です。
(その後RGB Lightについては計測しました)

RGB Lightでは以下をキーマップのconfig.hに書くことで個別に無効化できます。
またundefdefineに変えれば個別に有効化できます。

#undef RGBLIGHT_ANIMATIONS
#undef RGBLIGHT_EFFECT_BREATHING
#undef RGBLIGHT_EFFECT_RAINBOW_MOOD
#undef RGBLIGHT_EFFECT_RAINBOW_SWIRL
#undef RGBLIGHT_EFFECT_SNAKE
#undef RGBLIGHT_EFFECT_KNIGHT
#undef RGBLIGHT_EFFECT_CHRISTMAS
#undef RGBLIGHT_EFFECT_STATIC_GRADIENT
#undef RGBLIGHT_EFFECT_RGB_TEST
#undef RGBLIGHT_EFFECT_ALTERNATING
#undef RGBLIGHT_EFFECT_TWINKLE

RGB Matrixでは以下をキーマップのconfig.hに書くことで個別に無効化できます。

#undef ENABLE_RGB_MATRIX_ALPHAS_MODS
#undef ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#undef ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
#undef ENABLE_RGB_MATRIX_BREATHING
#undef ENABLE_RGB_MATRIX_BAND_SAT
#undef ENABLE_RGB_MATRIX_BAND_VAL
#undef ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#undef ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
#undef ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
#undef ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
#undef ENABLE_RGB_MATRIX_CYCLE_ALL
#undef ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
#undef ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
#undef ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
#undef ENABLE_RGB_MATRIX_CYCLE_OUT_IN
#undef ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
#undef ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
#undef ENABLE_RGB_MATRIX_CYCLE_SPIRAL
#undef ENABLE_RGB_MATRIX_DUAL_BEACON
#undef ENABLE_RGB_MATRIX_RAINBOW_BEACON
#undef ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
#undef ENABLE_RGB_MATRIX_RAINDROPS
#undef ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
#undef ENABLE_RGB_MATRIX_HUE_BREATHING
#undef ENABLE_RGB_MATRIX_HUE_PENDULUM
#undef ENABLE_RGB_MATRIX_HUE_WAVE
#undef ENABLE_RGB_MATRIX_PIXEL_FRACTAL
#undef ENABLE_RGB_MATRIX_PIXEL_RAIN

#undef ENABLE_RGB_MATRIX_TYPING_HEATMAP
#undef ENABLE_RGB_MATRIX_DIGITAL_RAIN

#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
#undef ENABLE_RGB_MATRIX_SPLASH
#undef ENABLE_RGB_MATRIX_MULTISPLASH
#undef ENABLE_RGB_MATRIX_SOLID_SPLASH
#undef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH

最後の選択肢

それでもだめならARMに切り替えましょう。


まとめ: 各施策でおよそどのくらい減るのか

施策 削減バイト オススメ度
LTO_ENABLE = yes ~4000
CONSOLE_ENABLE = no 3800
COMMAND_ENABLE = no 350
MOUSEKEY_ENABLE = no 1100
EXTRAKEY_ENABLE = no 330
SPACE_CADET_ENABLE = no 360
GRAVE_ESC_ENABLE = no 90
MAGIC_ENABLE = no 600
LOCKING_XXXの無効化 170
NO_ACTION_ONESHOT 350
NO_ACTION_TAPPING 1800 ×
both above 2 2440 ×
disable MUSIC mode ? ?
LAYER_STATE_8BIT 450
LAYER_STATE_16BIT 330
NO_ACTION_LAYER ? ?
Magic関連の関数 500
without printf 1500
RGB LED ?

RGB LightのEFFECT毎のサイズ

Effect姪 サイズ
RGBLIGHT_USE_TIMER [1] 330
RGBLIGHT_EFFECT_BREATHING 550
RGBLIGHT_EFFECT_RAINBOW_MOOD 300
RGBLIGHT_EFFECT_RAINBOW_SWIRL 390
RGBLIGHT_EFFECT_SNAKE 560
RGBLIGHT_EFFECT_KNIGHT 520
RGBLIGHT_EFFECT_CHRISTMAS 620
RGBLIGHT_EFFECT_STATIC_GRADIENT 280
RGBLIGHT_EFFECT_RGB_TEST 310
RGBLIGHT_EFFECT_ALTERNATING 250
RGBLIGHT_EFFECT_TWINKLE 1330

POINTING_DEVICE_AUTO_MOUSE_ENABLE

POINTING_DEVICE_AUTO_MOUSE_ENABLE機能を有効にすると追加で約1100バイトが消費されることがわかった。

参考: https://github.com/Yowkees/keyball/pull/508

脚注
  1. RGBLIGHT_EFFECT_STATIC_GRADIENT以外のeffectに付随して有効になる ↩︎

Discussion

jupemarajupemara

オーディオ設定

ですが、自分の手元で試してみたところ

# disable 前
* The firmware is too large! 29140/28672 (468 bytes over)
# disable 後
* The firmware is too large! 29108/28672 (436 bytes over)

32 bytes ほど削減できました :v:

tntn

つい先日も、すごく参考になりました