前回こちらの記事で紹介したディスプレイについて、カラー指定の青と赤が逆になっていて困ったのでその修正方法についてメモしておく。
thom.hateblo.jp
ライブラリ「Adafruit_ST7735_and_ST7789_Library」に入っているサンプルコード「graphictest.ino」内に以下のようなコードがある。
void tftPrintTest() { tft.setTextWrap(false); tft.fillScreen(ST77XX_BLACK); tft.setCursor(0, 30); tft.setTextColor(ST77XX_RED); tft.setTextSize(1); tft.println("Hello World!"); tft.setTextColor(ST77XX_YELLOW); tft.setTextSize(2); tft.println("Hello World!"); tft.setTextColor(ST77XX_GREEN); tft.setTextSize(3); tft.println("Hello World!"); tft.setTextColor(ST77XX_BLUE); tft.setTextSize(4); //以下略
不思議な事にST77XX_REDと指定している部分は青文字でHello World!と表示され、ST77XX_YELLOWと指定しているところは水色でHello World!と表示される。ただ、ST77XX_GREENだけはちゃんと緑色で表示される。
定義がおかしいのかと思って確認してみた。Arduino IDE 2で右クリックして定義に飛ぶことが出来る。
そうすると次のようなコードが見つかる。
// Some ready-made 16-bit ('565') color settings: #define ST77XX_BLACK 0x0000 #define ST77XX_WHITE 0xFFFF #define ST77XX_RED 0xF800 #define ST77XX_GREEN 0x07E0 #define ST77XX_BLUE 0x001F #define ST77XX_CYAN 0x07FF #define ST77XX_MAGENTA 0xF81F #define ST77XX_YELLOW 0xFFE0 #define ST77XX_ORANGE 0xFC00
見たことない形式だけどコメントのおかげでこれが16ビットカラーの指定だということが分かった。
一般的にパソコンやWebサイト等の色指定は24ビットとなっており、赤、緑、青をそれぞれ8諧調に分けてその組み合わせで表現される。
例えばArduino IDEのカラーであるブルーグリーンは次のような感じ。
これが16ビットになると赤と青が5諧調、緑だけは人間の感度が高いため6諧調という構成になるようだ。これがRGB565という形式。
ただ商品名にフルカラーモジュールってあるのにほんとに16ビットなのか?と調べたところ、商品名に65kとも書いてあり、調べると約65,000色という意らしい。
2進数で16ビットということは2の16乗で65,536種類の色を表現できるから概算で65kという略記になっているようだ。
で、なんで青が赤になるんだということで調べてみると、どうやらRGBのほかにBGRという方式もあるようで、このディスプレイはRGB565じゃなくてBGR565で指定するとうまくいくことが分かった。
24ビットならRとBを入れ替えるだけなので簡単なんだけど先ほどの図で示した通り16ビットだと切れ目が16進数の2~3桁目が赤と緑、緑と青の情報が混じっているのでちょっと面倒くさい。
そこで変換関数を作って対応することにした。
以下は24ビットのR・G・Bをそれぞれ10進数で受け取り、BGR565に変換する関数である。
uint16_t RGB888_to_BGR565(byte red, byte green, byte blue) { uint16_t bgr565 = 0; bgr565 = blue>>3; bgr565 = bgr565<<6; bgr565 += green>>2; bgr565 = bgr565<<5; bgr565 += red>>3; return bgr565; }
仕組みとしてはこんな感じ。
1) blueを3ビット右にシフトすることで下位3ビットを削ったものをbgr565に代入
2) bgr565を左に6ビットシフトすることでgreenが入るスペースを作り、2ビット削ったgreenを足し合わせる
3) bgr565を左に5ビットシフトすることでredが入るスペースを作り、3ビット削ったredを足し合わせる
この関数は実際にテキストカラー指定に組み込んで使用した。
tft.setTextColor(RGB888_to_BGR565(0,109,112));
非力なArduinoで逐一演算させるのもどうかなとは思ったんだけどもともとプロセッサーはビットレベルの演算が大得意なのでこの程度の計算は朝飯前。私の用途ではテキストをたまに更新するくらいなので仮に遅延が起きているとしても気づかないレベルだった。
以上