QMK の OLED 基礎知識

# はじめに

これは、私が 2020/12/08 現在で理解している、 QMK での OLED に関するあれこれをまとめたものです
私が実際に確認したものなどに限るので、全機能の中の一部にすぎません

これから OLED でいろいろ試してみたいなと思うユーザーや設計者に向けた記事となっています

まずは、 OLED とは切っても切れない `glcdfont.c` の中身について解説します
次に、 OLED に文字やロゴを表示する方法について解説します

# `glcdfont.c` とは何か

QMK で OLED をいじろうと思ったとき、こんな画像を見たことがあるのではないでしょうか

![glcdfont.png][glcdfont_img]

これは、 `qmk_firmware/drivers/oled/glcdfont.c`（[ソース][qmk_glcdfont]） を画像に変換（デコード）したものです
（master ブランチのものはなぜか Apple と Windows のアイコンが崩れているので直しています）

`glcdfont.c` の実際の中身は以下です

```cpp
#include "progmem.h"

// Helidox 8x6 font with QMK Firmware Logo
// Online editor: http://teripom.x0.com/

static const unsigned char font[] PROGMEM = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, 0x26, 0x29, 0x79, 0x29, 0x26, 0x00, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
    0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
    0x72, 0x49, 0x49, 0x49, 0x46, 0x00, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
    0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0x28, 0x00,
    0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
    0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0xF0, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0x3F, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0xF0, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0xF8, 0xFC, 0x3E,
    0x1E, 0x06, 0x01, 0x00, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x7E, 0x5B, 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE, 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x49, 0x49, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xDF, 0xBF, 0xBF, 0x00, 0xBF, 0xBF, 0xDF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x60, 0x60, 0xE0, 0xBF, 0x1F, 0x00, 0x7F, 0x7F, 0x07, 0x1E, 0x38, 0x1E, 0x07, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x0E, 0x1F, 0x3B, 0x71, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x0C, 0x0C, 0x0C, 0x00, 0x7E, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x7E, 0x7E, 0x03, 0x03, 0x7F, 0x7E, 0x00, 0x0F,
    0x3E, 0x70, 0x3C, 0x06, 0x3C, 0x70, 0x3E, 0x0F, 0x00, 0x32, 0x7B, 0x49, 0x49, 0x3F, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x1E, 0x3F, 0x69, 0x69, 0x6F, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x3C, 0x78, 0x70, 0x60, 0x00, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x30, 0x7B, 0x7F, 0x78, 0x30, 0x20, 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00, 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F, 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x07, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x7E, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
```

実態は16進数の配列である、 `font[]` と言えます
このソースがどうして上のようにデコードできるのか、順を追って見ていきましょう

## `font[]` の中身は何を意味しているのか

`font[]` は OLED に表示する文字や図形のデータ群です
16進数の配列がなぜ文字や図形になるのか、 `A` を例に見ていきましょう

### `font[]` から `A` をデコードする

まずは、 `font[]` 内で `A` を表す16進数の配列を抜き出します
`font[]` の391番目から397番目の要素がこれに当たります

```cpp
0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00
```

次に、これらを2進数に変換します

```cpp
01111100, 00010010, 00010001, 00010010, 01111100, 00000000
```

`01111100` について、下の桁から確認し、 `0` のときは塗らず、 `1` のときは塗っていきます

余談ですが、下の桁から判定していくのは、1ビットずつ右シフトしながら `00000001` と `AND` をとることで判定が簡単に行えるからでしょう

![][font_A_img1]

これを順番に行うことで `A` ができあがります

![][font_A_img2]

つまり、 `font[]` の要素1つで縦8ドット（8bit）分の情報が含まれています
そして、要素6つで1文字を表しているのです

`font[]` の768番目までの要素は文字用として予約されていると考えていいと思います
もしこの範囲を変更してしまうと、 OLED で文字を表示するときにおかしくなってしまうと考えられます

### ロゴについて考える

これまでで `font[]` の各要素が縦8ドット分の情報を持っていることがわかりました
そう考えると、ロゴがどのように表現されているかもおのずとわかってくると思います

つまり、なにか表示したいモノクロ画像（ロゴなど）があった場合、以下のようなルーチンでエンコードできます

1. 画像を縦8ドット分ずつに分割する
2. 左から1ドット分ずつ順番に `白 -> 0, 黒 -> 1` のルールで2進数化する（順番に注意）
3. 2進数を16進数に変換する
4. 分割された画像の右端まで行ったら、次の分割された画像に対して同様の操作を行う
5. 以上の操作を画像全体に対して行う

## `glcdfont.c` のまとめ

* `glcdfont.c` は OLED に表示する文字やロゴを定義している
* 文字やロゴは `font[]` で16進数の配列として定義されている
* `font[]` の要素1つは縦8ドット分の情報を持っている
* `font[]` の要素を6つずつにまとめると1文字分となる

# OLED への表示

文字やロゴの表示について解説します
なお、標準的な 128 x 32 の OLED を前提とします

## 単純な文字の表示

文字を OLED に表示するには `keymap.c` 内で次のように記述します

```cpp
void oled_task_user(void) {
    oled_write_P(PSTR("Some Text"), false);
}
```

この例では OLED の左上に `Some Text` と表示されます
第2引数の `false` を `true` に変えると、白背景に黒抜き文字で `Some Text` と表示されます

## 指定した場所への文字の表示

左上にただ表示するだけでは面白くありません
左下に表示してみましょう

```cpp
void oled_task_user(void) {
    oled_set_cursor(0, 3);
    oled_write_P(PSTR("Some Text"), false);
}
```

変化したのは `oled_set_cursor(0, 3)` です
`oled_set_cursor(col, row)` というように使います
これは、次に OLED に表示する文字やロゴなどの開始位置を設定します

QMK ではデフォルトでフォントサイズが 8 x 6 ドットになっているので、 `col` を増やすと6ドットずつ右にずれ、 `row` を増やすと8ドットずつ下にずれます
もちろん、フォントサイズを変えた場合はそれに準じます

## ロゴの表示

QMK のドキュメントの [Logo Example][qmk_doc_logo-example] の項には、 QMK のロゴを表示するためのコードとして以下のものが示されています

```cpp
static void render_logo(void) {
    static const char PROGMEM qmk_logo[] = {
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94,
        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4,
        0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00
    };

    oled_write_P(qmk_logo, false);
}

```

`qmk_logo[]` は何を意味しているのでしょうか
16進数が並んでいるので、 `glcdfont.c` の `font[]` と同じと思うかもしれませんが、違います

### `qmk_logo[]` の中身は何を意味しているのか

これは何番目の文字を表示するかを定義しています
といっても何のことやらわからないと思います

まずは、こちらの画像を見てください

![glcdfont.png][glcdfont_img]

最初の画像と同じですね
しかし、これがヒントとなります

まず、 `qmk_logo[]` の最初の行を見てみましょう

```cpp
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94,
```

最初の要素は `0x80` となっています
これを10進数に変換すると `128` です

では、上の画像で128番目の文字は何でしょうか
なお、左上の空白を0番目として右に数えていきます

![][glcdfont_a_img]

正解はこの空白です
そこから148まで21文字分あるので、最初の行が示す文字は以下の範囲となります

![][glcdfont_b_img]

次の行も同様に考えます

```cpp
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4,
```

`0xA0` (160) 番目から21文字は以下の範囲です

![][glcdfont_c_img]

さて、最後の行ですが、最後に `0x00` が追加されています
これは終端を表すマーカーの役割があります
ですので、最後の `0x00` を除いた21文字を示しています

```cpp
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00
```

![][glcdfont_d_img]

これで、 `qmk_logo[]` の配列が示すところが理解できたのではないでしょうか
なお、 `qmk_logo[]` は `<keyboard>.h` で宣言すればいいので、任意の名前で大丈夫です（ `your_logo[]` など）

ところで、なぜ21文字ごとの塊になっているのでしょう
QMK では1文字が 8 x 6 と（デフォルトでは）決まっていました
つまり、 `6 x 21 = 126` で、21文字が表示できる最大の文字数なのです

## OLED への表示まとめ

* OLED へ文字を出力するときは `oled_write_P(PSTR("Some Text"), false)` を使う
* 文字を任意の場所に出力するときは `oled_set_cursor(col, row)` でカーソル位置を調整する
* ロゴを表示するときは `your_logo[]` などで使う文字を羅列する
* `your_logo[]` には「何文字目か」を16進数で記述する
* `your_logo[]` の最後には `0x00` を付ける

# おわりに

以上、 OLED の基礎知識として、 `glcdfont.c` とは何か、 OLED に文字やロゴを表示すればいいか、簡単に解説を行いました
これらのことがわかれば、 `glcdfont.c` を編集してオリジナルのロゴに差し替えたり、オリジナルの `glcdfont.c` を作って好きな画像を表示させたりできるようになると思います

わかりにくいところや間違っているところがあれば、コメントをいただけると嬉しいです
それでは、よき自作キーボードライフを

[glcdfont_img]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553901/d210b973-20e8-9923-defc-2bfd6cc411e0.png
[qmk_glcdfont]:https://github.com/qmk/qmk_firmware/blob/master/drivers/oled/glcdfont.c
[font_A_img1]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553901/b02eaaf0-ce4e-d2b2-2511-2cfff2cee291.png
[font_A_img2]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553901/5fea637f-596f-1fe8-3655-cc104d010890.png
[git_bs_macro_keymap]:https://github.com/koktoh/qmk_firmware_koktoh/blob/dev/bs_macro/keyboards/bs_macro/keymaps/default/keymap.c
[qmk_doc_logo-example]:https://docs.qmk.fm/#/feature_oled_driver?id=logo-example
[glcdfont_a_img]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553901/93af1bd9-5393-6719-0dfe-8b6aa57bf737.png
[glcdfont_b_img]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553901/621fbe65-ec87-02e0-c3a4-0c23c6b38cbf.png
[glcdfont_c_img]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553901/54f5d990-6e42-f21f-b1a1-9903658d8680.png
[glcdfont_d_img]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553901/1326e24a-3754-00ba-14b8-97aa1b004b17.png