ESP-WROOM-02でグラッフィク液晶を使う

#はじめに
ESP-WROOM-02で漢字表示がしたかったのでグラッフィク液晶のAQM1248を使ってみました。
https://synapse.kyoto/hard/MGLCD_AQM1248A/page010.html
を参考に簡単にできるかと思ったのですが、単純にコンパイルが通らなかったのでほぼ作り直しました。
フォントの変換などはPHPを使っています。
ST7565を使った液晶であれば、ほかでも使えます。

ファイルは以下からダウンロードしてください。
https://github.com/mag02243/ESP-WROOM-02_AQM1248


#ESP-WROOM-02とAQM1248の接続
　CS（チップセレクト）: IO 5、RS(レジスタセレクト): IO 12、SCK(クロック): IO 14、MOSI(データ出力): IO 13
　に接続します。ソフトウエアSPIで制御していますのでどのピンに接続してもプログラムを変更すれば使えます。

初期化は以下のようにします。
接続ピンを変えた場合には
uint8_t cs = 5, uint8_t rs = 12, uint8_t sck = 14, uint8_t mosi = 13

```GLCD_sketch.ino
#include "GLCD.h"

GLCD lcd;
...

void setup() {
    ...
//  lcd.begin(uint8_t cs = 5, uint8_t rs = 12, uint8_t sck = 14, uint8_t mosi = 13);
    lcd.begin();
    ...

}


```


#Arduinoプログラム
　ソフトウエアSPIで制御していますし、文字描画にもドット単位で描画していますので決して早くはありません。
　また、AQM1248ではグラフィックメモリの内容を読み取れないため、グラフィックメモリと同じ内容のバッファを用意して、表示内容に重ね書きできるようにしています。

コマンドとデータを直接送ります。ST7565のマニュアルを参照してください。
  lcd.sendCmd(uint8_t cmd);
  lcd.sendData(uint8_t data);

描画を一括で行うときには beginBackGroundDraw()、endBackGroundDraw() を使います。
endBackGroundDraw()で液晶全体に内部メモリを一括転送します。
  lcd.beginBackGroundDraw();
  lcd. いろいろな描画をここでします
  lcd.endBackGroundDraw();
※この機能を使わなくとも直接描画することもできます。

画面をクリアします。
  lcd.clear();

x,y位置（左上が0,0）に点を画面をcolorで描きます。
GLCD_BLACK で黒、GLCD_WHITE で白、GLCD_CLEAR で書き換えません
  lcd.SetPixel(uint8_t x, uint8_t y, uint8_t color = 1);

(x1,y1)-(x2,y2)にcolorで線を描きます。
  lcd.Line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color = 1);

(x1,y1)-(x2,y2)の四角形をborderで枠線を、fillで内部を描きます。
  lcd.Rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2,
      uint8_t border = GLCD_BLACK, int8_t fill = GLCD_CLEAR);

5x7ドットフォントの表示位置を(x,y)に設定します。
  lcd.FontPos(uint8_t x, uint8_t y);

5x7ドットフォントの文字cを表示位置に描きます。
reverse=trueで背景黒、文字白で描きます。
  lcd.put(char c, bool reverse = false);

5x7ドットフォントの文字列strを表示位置に描きます。
reverse=trueで背景黒、文字白で描きます。
  lcd.print(char *str, bool reverse = false);

5x7ドットフォントの文字列strを表示位置に描きます。
noは0～15で、fontはuint8_tの5個の配列です。
最初のバイトが左側でMSBが下側のドットになります。
  lcd.setFont(uint8_t no, uint8_t *font);

8x12ドットフォントの文字列strを(x, y)に描きます。
文字色を one = GLCD_BLACK で 背景色を uint8_t zero = GLCD_WHITE で描きます。
全角文字はUTF-8Nで書きます。（ArduinoIDEで普通に入力すれば大丈夫です）
  lcd.kprint(uint8_t x, uint8_t y, char *str, uint8_t one = GLCD_BLACK, uint8_t zero = GLCD_WHITE);

32x32ドットフォントの文字列strを(x, y)に描きます。
文字色を one = GLCD_BLACK で 背景色を uint8_t zero = GLCD_WHITE で描きます。
全角文字はUTF-8Nで書きます。（ArduinoIDEで普通に入力すれば大丈夫です）
  lcd.kprint32(uint8_t x, uint8_t y, char *str, uint8_t one = GLCD_BLACK, uint8_t zero = GLCD_WHITE);


#5x7ドット文字（英数カナ）
https://synapse.kyoto/hard/MGLCD_AQM1248A/page010.html
のフォントをそのまま使っています。

```GLCD_sketch.ino
    lcd.clear();
    lcd.FontPos(0, 0);
    lcd.print("0123456789012345678901");
    lcd.FontPos(1, 8);
    lcd.print("ABCDEFGHIJKLMNOPQRSTUV", true);
    lcd.FontPos(2, 16);
    lcd.print("abcdefghijklmnopqrstuv");
    lcd.FontPos(3, 24);
    lcd.print("ｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅ", true);
```

読むために使うには、AQM1248 ではかなり小さいですね。
![IMG_2090.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82334/4ae897be-a5bf-a4ab-e112-eb3bb94a6295.jpeg)


#8x12ドット文字（漢字を含む）
https://littlelimit.net/k8x12.htm
を使いました。
フォントをダウンロードして、FontForgeで開きます。
エンコーディング　－　エンコーディングを強制 ー　ISO 10646-1(Unicode,完全)　を選択
編集　－　選択 － 出力に値するグリフ
ファイル　－　フォントを出力　アウトラインフォント無し　BDF

保存したBDFファイル名を web/font.php の2行目に設定します。
WEBへアップロードしてアクセスすると、GLCD_font.cppの内容が表示されます。必要に応じて編集してください。
1文字16バイトです。
各文字の最初の3つはユニコード、次の1バイトは文字幅で、残り12バイトは文字データです。
文字の順番はユニコードの昇順に並べておきます。

```GLCD_sketch.ino
    lcd.clear();
    lcd.kprint( 0,  0, "01234567890123456");
    lcd.kprint( 0, 12, "ABCDEFGHIJKLMNOPQ");
    lcd.kprint( 0, 24, "あいうえおかきくけこ漢字も");
    lcd.kprint( 0, 36, "アイウエオカキクケ表示できます！");
```

![IMG_2092.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82334/5555cbde-d268-d38f-9e99-d93410d63674.jpeg)


#32x32ドット文字（漢字を含む）
フォントをダウンロードして、FontForgeで開きます。
サンプルはIPAGothicを使っています。

エンコーディング　－　エンコーディングを強制 ー　ISO 10646-1(Unicode,完全)　を選択
編集　－　選択 － 出力に値するグリフ
エレメント　－　Bitmap Strikes Avaiable でピクセルサイズ 31を入力
ファイル　－　フォントを出力　アウトラインフォント無し　BDF

保存したBDFファイル名を web/font32.php の2行目に設定します。
WEBへアップロードしてアクセスすると、GLCD_font32.cppの内容が表示されます。必要に応じて編集してください。
1文字136バイトです。
各文字の最初の1つはユニコード、次の1つは文字幅で、残り32は文字データです。
文字の順番はユニコードの昇順に並べておきます。
サンプルでは、あまりにも大きくなるので英数記号カナの158文字のみ変換しています。

```GLCD_sketch.ino
    lcd.clear();
    lcd.kprint32( 0,  0, "ABCDEFGH");
    lcd.kprint32( 0, 24, "abcdefgh");
```

![IMG_2094.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82334/1b5c3799-a977-f5cd-4ea3-e6a6e6195295.jpeg)


#ロゴ表示（白黒画像）
白黒2値のPNG画像を用意します。（サンプルは128x48)
PNGファイル名を web/logo.php の2行目に設定します。
WEBへアップロードしてアクセスすると、GLCD_sketch.inoの内容が表示されます。必要に応じて編集してください。
logo()関数で表示していますので、サイズや位置を考えて修正してください。

```GLCD_sketch.ino
const uint8_t _logo[16 * 48] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
...
};

void logo()
{
  lcd.clear();
  for (uint8_t y = 0; y < 48; y++) {
    for (uint8_t x = 0; x < (128 + 7) >> 3; x++) {
      const uint8_t *p = _logo + y * 16 + x;
      uint8_t c = pgm_read_byte(p);
      for (uint8_t k = 0; k < 8; k++) {
        lcd.SetPixel(x * 8 + k, y, (c & (1 << (7 - k))) != 0 ? GLCD_BLACK : GLCD_WHITE);
      }
    }
  }
}
```

![IMG_2096.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82334/f8fab7c2-f629-2bcd-3a4c-bd832a28979b.jpeg)


#さいごに
バグはまだ残っているようですが、とりあえず使えます。
修正内容がありましたら、教えてください。