編集履歴一覧に戻る
momoのアイコン画像

momo が 2021年08月27日02時07分12秒 に編集

初版

タイトルの変更

+

カラーLCDビットマップ表示テスト

タグの変更

+

XIAO

+

ST7789

+

カラーLCD

メイン画像の変更

メイン画像が設定されました

本文の変更

+

# はじめに 何かに使えないかと買っておいた204x204のカラーLCDを動かしてみました。 Amazonで1000円くらいでした。 ``` DiyStudio 1.3" カラーIPS LCDディスプレイ 240X240解像度 ドライバーIC ST7789VW  SPIインターフェース RGB 65Kフルカラー 3.3V ``` ![キャプションを入力できます](https://camo.elchika.com/ed992491c7447a8512dd19ca301654e6c1326534/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f65343964323538632d663631612d346363642d393865302d3439323165303732366539302f65633839326338642d613935612d346666342d393331332d363633356236386138643761/) サンプルプログラムなどでグラフィック描画(線や円など)は一通り動かしてみたのですが、 せっかくのカラーLCDなので写真やカラー画像を表示してみたくなりました。 ただ、SDカードから画像ファイルを読み出すサンプルプログラムしか見つけられず、 SDカードスロットモジュールも手元になかったのでシリアル通信でビットマップファイルを転送して表示してみました。 # システム構成 PCからシリアル通信(TeraTerm)でビットマップファイルをマイコン(Seeeduino XIAO)に送信しLCDを制御します。 ファイルのパース処理を簡単にするため、ビットマップのサイズは今回使うLCDに合わせて幅は240ピクセル固定とし、 色深度は24bitのみとしました。ただし、LCDに表示する際にには16bit(R:G:B=5:6:5)に減色しています。 # ハードウェア ### 部品 - Seeeduino XIAO - 1.3 inc カラー LCD(ST7789) - ブレッドボード、ジャンパ、など ### 回路図 今回使ったLCDはI2Cっぽい端子名になっていますがSPIで接続します。 Backlight(BLK端子)は無くても十分明るく表示できたので使いませんでした。 ![キャプションを入力できます](https://camo.elchika.com/6fe758250b6ebeb09d5f1414a9b88249a45c5d02/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f65343964323538632d663631612d346363642d393865302d3439323165303732366539302f66343032326465652d323139662d343730352d626565362d343833666434643633663061/) # ソフトウェア グラフィック描画には Adafruit GFX ライブラリを使いました。 ちなみに、このLCDはCS端子がなくXIAO+ST7789でのサンプルプログラムが見つからずSPI設定にちょっとハマしました。 いろいろ調べて試行錯誤してみてSPI_MODE=3、CS=-1の設定で表示する事ができました。 ```arduino:プログラム #include <Adafruit_GFX.h> #include <Adafruit_ST7789.h> #include <SPI.h> #define TFT_CS (-1) #define TFT_RST (4) #define TFT_DC (5) Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST); void setup(void) { Serial.begin(115200); // XIAOの場合は効かない? tft.init(240, 240, SPI_MODE3); // MODE3 is for the display without /CS line tft.setRotation(2); tft.fillScreen(ST77XX_BLACK); tft.setTextColor(ST77XX_YELLOW); tft.setTextSize(2); tft.setCursor(0, 60); tft.println("Transfer Bitmap..."); } void loop() { unsigned long width, height; if (0 == Serial.available()) { return; } if (0 == rcv_bitmap_header(&width, &height)) { rcv_bitmap_data(width, height); // 残りは捨てる while (0 < Serial.available()) { volatile unsigned char tmp = Serial.read(); } } } int rcv_bitmap_header(unsigned long *p_width, unsigned long *p_height) { unsigned char buf[64]; unsigned long bm, size = 0; int err = 0; *p_width = 0; *p_height = 0; // 面倒なので固定 rcv_n(buf, sizeof(buf), 0x36); bm = get_val(&buf[0], 2); if (0x4d42 != bm) { // BM err = -1; } else { size = get_val(&buf[2], 4); if ((size == 0) || (size > (tft.height() * tft.width() * 3 + 64))) { err = -2; } else { *p_width = get_val(&buf[0x12], 4); if ((*p_width == 0) || (*p_width > tft.width())) { err = -3; } else { *p_height = get_val(&buf[0x16], 4); if ((*p_height == 0) || (*p_height > tft.height())) { err = -4; } } } } // Error message if (err < 0) { tft.fillRect(0, 50, tft.width(), 100, ST77XX_BLACK); tft.setCursor(0, 60); tft.printf("Error : %d\n", err); tft.printf("BM : %x\n", bm); tft.printf("Size : %d\n", size); tft.printf("Width : %d\n", *p_width); tft.printf("Height: %d\n", *p_height); } return err; } void rcv_bitmap_data(unsigned long width, unsigned long height) { for (int y=height; y>=0; y--) { for (int x=0; x<width; x++){ tft.drawPixel(x, y, get_pielx()); } } } unsigned long get_pielx(void) { unsigned char pix[3]; rcv_n(pix, sizeof(pix), sizeof(pix)); return tft.color565(pix[2], pix[1], pix[0]); } int rcv_n(unsigned char buf[], int buf_size, int num) { int i=0, t = 0; while (1) { if (Serial.available()) { t = 0; if (i < buf_size) { buf[i++] = Serial.read(); } if (i >= num) { break; } if (i >= buf_size) { return -2; } } else { t++; if (t > 1000) { return -1; // Timeout } } } return 0; } unsigned long get_val(unsigned char *pb, int n) { unsigned long v = 0; for (int i=0; i<n; i++) { v |= ((*pb++) << (8*i)); } return v; } ``` # 動作の様子 ビットマップファイルは上下反転してデータが格納されているので下から表示させています。 XIAOのシリアル通信は仮装シリアル(CDC)として認識させて通信しているので、 通常のUARTより高速にデータ通信ができるようです。それでも6~7秒くらいかかりますが…。 @[twitter](https://twitter.com/serebent/status/1430911146433802247) ※注:TeraTermで送信する際はバイナリのチェックをしないと正常に送信できません。 ![キャプションを入力できます](https://camo.elchika.com/0cde9a5eff607eea6ee1434c84ffb4ebdc1e87d4/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f65343964323538632d663631612d346363642d393865302d3439323165303732366539302f30653865303866362d316134302d346261382d623862662d666538396335313930386536/) # まとめ 思ったより鮮明に表示できました。 何に使おうかな~