/****************************************************** * プロジェクトファイル名:ILI9328_test5.ino * * ハードSPI・横置き表示 * 1文字表示+文字列描画テスト追加:260203 * グラフィック描画テスト追加   :260204 * * 初期化はaitendo参考コード準拠 * コントローラ:ESP32S3 Dev Module * 内蔵MPU:ESP32-WROOM-1:動作クロック周波数=240MHz(max) * * 2026/2/5 N.Ishii *******************************************************/ #include #include "soc/spi_reg.h" // レジスタ操作に必要 #include "soc/soc.h" #include "ASCII12dot.h" #include "imagedata.h" /// LCDピン定義(ESP32S3側のGPIO番号) #define MOSI 11 #define SCK 12 #define CS 10 #define RST 18 // #define DC 7 // 未使用(接続しない) /// SPI2(FSPI)の名前を「SPI2」に統一して定義 SPIClass SPI2(FSPI); // SPIClass *SPI2 = new SPIClass(FSPI); // 設定をグローバルに定義(全関数で使用可能) // ソフトSPIの1.62uS(約600kHz)に合わせて設定 //SPISettings settings(600000, MSBFIRST, SPI_MODE3); SPISettings settings(10000000, MSBFIRST, SPI_MODE3); /******************************************* * 16bit Color Difinition *******************************************/ #define WHITE 0xFFFF #define BLACK 0x0000 #define RED 0xF800 #define GREEN 0x07E0 #define BLUE 0x001F #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define BROWN 0x8000 #define ORANGE 0xFC00 #define PERPLE 0x8010 #define COBALT 0x041F //============================================== #define ENDCOL 320 // X #define ENDROW 240 // Y #define ENDPAGE 239 // Y #define XChar (int)((ENDCOL+1) / 12) #define YLine (int)((ENDPAGE+1) / 14) char Buf[17]; //文字列のバッファー用レジスタ char str_Hellow[] = "Hellow"; char str_World[] = "World !!"; char str_Tokyo[] = "Tokyo"; char str_Japan[] = "Japan"; char str_Chiyodaku[] = "Chiyodaku"; char str_Sotokanda[] = "Sotokanda"; char str_Akihabara[] = "Akihabara"; char str_AKB48[] = "AKB48"; //unsigned char i,j,index; /// プロトタイプ宣言 void WriteData(unsigned int data); void WriteCommand(unsigned int cmd); void LCD_Init(); void LCD_Fill(unsigned int color); void LCD_DrawPixel(int x, int y, unsigned int color); void LCD_DrawChar(int colum, int line, unsigned char letter, unsigned int color1, unsigned int color2); void LCD_DrawString(int colum, int line, char *s, unsigned int color1, unsigned int color2); void LCD_DrawLine(int x0, int y0, int x1, int y1, unsigned int color); void LCD_DrawCircle(int x0, int y0, int r, unsigned int color); void LCD_DrawImage(char line, const unsigned char *ptr, unsigned int color1, unsigned int color2); //============================================ void WriteData(unsigned int data) { SPI2.beginTransaction(settings); digitalWrite(CS, LOW); SPI2.transfer(0x72); // データ識別(スタートバイト:これからデータを送ります) SPI2.transfer(data >> 8); // 上位バイトを送信 SPI2.transfer(data & 0xFF); // 下位バイトを送信 digitalWrite(CS, HIGH); SPI2.endTransaction(); } void WriteCommand(unsigned int cmd) { SPI2.beginTransaction(settings); digitalWrite(CS, LOW); SPI2.transfer(0x70); // コマンド識別(スタートバイト:これからコマンドを送ります) SPI2.transfer(cmd >> 8); // 上位バイトを送信 SPI2.transfer(cmd & 0xFF); // 下位バイトを送信 digitalWrite(CS, HIGH); SPI2.endTransaction(); } void LCD_Init() { // ハードリセット digitalWrite(RST, LOW); delay(20); digitalWrite(RST, HIGH); delay(120); WriteCommand(0x00E5); WriteData(0x78F0); // set SRAM internal timing WriteCommand(0x0001); WriteData(0x0000); // set SS and SM bit WriteCommand(0x0002); WriteData(0x0400); // set 1 line inversion //WriteCommand(0x0003); WriteData(0x1030); // BGR=1 / ORG=0 / ID[1:0]=11 / AM=0 (AM=0とID[1:0]=11の組合せで横表示+水平・垂直ともインクリメント) WriteCommand(0x0003); WriteData(0x1038); // BGR=1 / ORG=0 / ID[1:0]=11 / AM=1 WriteCommand(0x0004); WriteData(0x0000); // Resize register WriteCommand(0x0008); WriteData(0x0202); // set the back porch and front porch WriteCommand(0x0009); WriteData(0x0000); // set non-display area refresh cycle ISC[3:0] WriteCommand(0x000A); WriteData(0x0000); // RGB interface setting WriteCommand(0x000D); WriteData(0x0000); // Frame marker Position WriteCommand(0x000F); WriteData(0x0000); // RGB interface polarity // Power On sequence WriteCommand(0x0010); WriteData(0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB WriteCommand(0x0011); WriteData(0x0007); // DC1[2:0], DC0[2:0], VC[2:0] WriteCommand(0x0012); WriteData(0x0000); // VREG1OUT voltage WriteCommand(0x0013); WriteData(0x0000); // VDV[4:0] for VCOM amplitude WriteCommand(0x0007); WriteData(0x0001); // Dis-charge capacitor power voltage delay(200); WriteCommand(0x0010); WriteData(0x1690); // SAP, BT[3:0], AP, DSTB, SLP, STB WriteCommand(0x0011); WriteData(0x0227); // Set DC1[2:0], DC0[2:0], VC[2:0] delay(50); WriteCommand(0x0012); WriteData(0x008C); // External reference voltage= Vci; delay(50); WriteCommand(0x0013); WriteData(0x1500); // VDV[4:0] for VCOM amplitude 0X1000 WriteCommand(0x0029); WriteData(0x0004); // VCM[5:0] for VCOMH 0X0009 WriteCommand(0x002B); WriteData(0x000D); // Set Frame Rate delay(50); WriteCommand(0x0020); WriteData(0x0000); // GRAM horizontal Address WriteCommand(0x0021); WriteData(0x0000); // GRAM Vertical Address // Gamma WriteCommand(0x0030); WriteData(0x0000); WriteCommand(0x0031); WriteData(0x0607); WriteCommand(0x0032); WriteData(0x0305); WriteCommand(0x0035); WriteData(0x0000); WriteCommand(0x0036); WriteData(0x1604); WriteCommand(0x0037); WriteData(0x0204); WriteCommand(0x0038); WriteData(0x0001); WriteCommand(0x0039); WriteData(0x0707); WriteCommand(0x003C); WriteData(0x0000); WriteCommand(0x003D); WriteData(0x000F); // GRAM area WriteCommand(0x0050); WriteData(0x0000); // Horizontal GRAM Start Address //WriteCommand(0x0051); WriteData(0x013F); // Horizontal GRAM End Address (横置き表示設定) WriteCommand(0x0051); WriteData(0x00EF); // ここは変えない WriteCommand(0x0052); WriteData(0x0000); // Vertical GRAM Start Address //WriteCommand(0x0053); WriteData(0x00EF); // Vertical GRAM End Address (横置き表示設定) WriteCommand(0x0053); WriteData(0x013F); // ここは変えない WriteCommand(0x0060); WriteData(0xA700); // Gate Scan Line WriteCommand(0x0061); WriteData(0x0001); // NDL,VLE, REV WriteCommand(0x006A); WriteData(0x0000); // set scrolling line // Partial Display WriteCommand(0x0080); WriteData(0x0000); WriteCommand(0x0081); WriteData(0x0000); WriteCommand(0x0082); WriteData(0x0000); WriteCommand(0x0083); WriteData(0x0000); WriteCommand(0x0084); WriteData(0x0000); WriteCommand(0x0085); WriteData(0x0000); // Panel Control WriteCommand(0x0090); WriteData(0x0010); WriteCommand(0x0092); WriteData(0x0600); WriteCommand(0x0007); WriteData(0x0133); // 262K color and display ON } /***************************************** * 全画面を指定色で塗潰す ******************************************/ void LCD_Fill(unsigned int color) { WriteCommand(0x0020); WriteData(0x0000); // 本来はX指定だが、AM=1時はY(0-239)を制御 WriteCommand(0x0021); WriteData(0x0000); // Vertical Start Address 本来はY指定だが、AM=1時はX(0-319)を制御 WriteCommand(0x0022); // GRAM write /// 全画面塗りつぶし用(高速化のため一気に送る) SPI2.beginTransaction(settings); digitalWrite(CS, LOW); /// 開始指示 SPI2.transfer(0x72); // データ識別:Start Byte /// 320x240ピクセル分をループ for (int i = 0; i < ENDCOL * ENDROW; i++) { SPI2.transfer16(color); // 16bitを一気に送る } digitalWrite(CS, HIGH); SPI2.endTransaction(); } /*********************************** * 1ピクセル表示関数 * 座標は(0,0)-(319,239) ***********************************/ void LCD_DrawPixel(int x, int y, unsigned int color){ WriteCommand(0x0020); WriteData(y); // 本来はX開始アドレス指定だが、AM=1時はY(0-239)を制御なので、Yを指定 WriteCommand(0x0021); WriteData(x); // 本来はY開始アドレス指定だが、AM=1時はX(0-319)を制御なので、Xを指定 WriteCommand(0x0022); // GRAM write WriteData(color); // 1dot描画 } /***************************************** * ANK文字表示関数 12x12ドット * 320/12=26文字/行 240/14=17行 * (0, 0) - (25, 16)の範囲 ******************************************/ void LCD_DrawChar(int colum, int line, unsigned char letter, unsigned int color1, unsigned int color2){ int j, i, Mask; if((colum < XChar) && (line < YLine)){ // 範囲チェック // ANK表示出力 3バイトの2ラインずつを6回繰り返す for(j=0; j<6; j++){ // 8ドット連続部の表示 Mask = 0x80; for(i=0; i<8; i++){ // 1ライン目前半8ドット表示 if((ANKFont[letter][j*3] & Mask) != 0) LCD_DrawPixel(colum*12+i+4, line*14+j*2+2, color1); else LCD_DrawPixel(colum*12+i+4, line*14+j*2+2, color2); //背景色 // 2ライン目後半8ドット表示 if((ANKFont[letter][j*3+2] & Mask) != 0) LCD_DrawPixel(colum*12+i+8, line*14+j*2+3, color1); else LCD_DrawPixel(colum*12+i+8, line*14+j*2+3, color2); //背景色 Mask = Mask >> 1; } // 分割部4ドットずつ表示 Mask = 0x80; // 1ライン目後半4ドット表示 for(i=0; i<4; i++){ if((ANKFont[letter][j*3+1] & Mask) != 0) LCD_DrawPixel(colum*12+i+12, line*14+j*2+2, color1); else LCD_DrawPixel(colum*12+i+12, line*14+j*2+2, color2); //背景色 Mask = Mask >> 1; } // 2ライン目前半4ドット表示 for(i=4; i<8; i++){ if((ANKFont[letter][j*3+1] & Mask) != 0) LCD_DrawPixel(colum*12+i, line*14+j*2+3, color1); else LCD_DrawPixel(colum*12+i, line*14+j*2+3, color2); //背景色 Mask = Mask >> 1; } } } } /****************************** * 文字列描画関数 * 16文字x20行で指定 ******************************/ void LCD_DrawString(int colum, int line, char *s, unsigned int color1, unsigned int color2) { while (*s){ LCD_DrawChar(colum++, line, *s++, color1, color2); if(colum >= XChar){ line++; colum = 0; if(line >= YLine) line = 0; } } } /*************************** * 直線描画関数 ***************************/ #define abs(a) (((a)>0) ? (a) : -(a)) void LCD_DrawLine(int x0, int y0, int x1, int y1, unsigned int color) { int steep, t; int deltax, deltay, error; int x, y; int ystep; y0=ENDROW-y0 -1; // Y座標反転 y1=ENDROW-y1 -1; /// 差分の大きいほうを求める steep = (abs(y1 - y0) > abs(x1 - x0)); /// x、yの入れ替え if(steep){ t = x0; x0 = y0; y0 = t; t = x1; x1 = y1; y1 = t; } if(x0 > x1) { t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } deltax = x1 - x0; // 傾き計算 deltay = abs(y1 - y0); error = 0; y = y0; /// 傾きでステップの正負を切り替え if(y0 < y1) ystep = 1; else ystep = -1; /// 直線を点で描画 for(x=x0; x<=x1; x++) { if(steep) LCD_DrawPixel(y,x,color); else LCD_DrawPixel(x,y,color); error += deltay; if((error << 1) >= deltax) { y += ystep; error -= deltax; } } } /************************************* * 円を描く関数 * 中心点と半径を指定 * (Fussyさんのアルゴリズムを使用) **************************************/ void LCD_DrawCircle(int x0, int y0, int r, unsigned int color) { int x = r; int y = 0; int F = -2 * r + 3; while(x >= y){ LCD_DrawPixel(x0+x, y0+y, color); LCD_DrawPixel(x0-x, y0+y, color); LCD_DrawPixel(x0+x, y0-y, color); LCD_DrawPixel(x0-x, y0-y, color); LCD_DrawPixel(x0+y, y0+x, color); LCD_DrawPixel(x0-y, y0+x, color); LCD_DrawPixel(x0+y, y0-x, color); LCD_DrawPixel(x0-y, y0-x, color); if(F >= 0){ x--; F -= 4 * x; } y++; F += 4 * y + 2; } } /********************************************************* * イメージ表示関数 *  データは縦方向8ライン分が1バイトで格納されている * 128×128/8=2kバイト/画面 * グラフィック色(color1)と背景色(color2)両方を指定 * 130518追加: N.Ishii **********************************************************/ void LCD_DrawImage(char line, const unsigned char *ptr, unsigned int color1, unsigned int color2) { unsigned char Mask; int i, vline, colum; for(vline=line; vline3) && (j<8)) LCD_DrawChar(i, j, index, GREEN, BLACK); if ((j>7) && (j<12))LCD_DrawChar(i, j, index, RED, BLACK); if ((j>11) && (j<17))LCD_DrawChar(i, j, index, YELLOW, BLACK); } } delay(5000); // 5秒待ち LCD_Fill(BLACK); // 全画面クリア ///文字列描画---------------------------------------------------------------------------------------------- LCD_DrawString(0,0,str_Hellow,BLACK,WHITE); LCD_DrawString(1,1,str_World,RED,WHITE); LCD_DrawString(2,2,str_Japan,BLUE,WHITE); LCD_DrawString(3,3,str_Tokyo,WHITE,BLACK); LCD_DrawString(4,4,str_Chiyodaku,RED,BLACK); LCD_DrawString(5,5,str_Sotokanda,GREEN,BLACK); LCD_DrawString(6,6,str_Akihabara,RED,YELLOW); LCD_DrawString(7,7,str_AKB48,GREEN,YELLOW); delay(5000); // 5秒待ち /// 斜め直線描画------------------------------------------------------------------------------------------ LCD_Fill(WHITE); // クリア for(i=0; i<240; i++){ // 斜め直線の表示: 白ベタ背景・黒線表示 LCD_DrawPixel(i,i,BLACK); // 1本目:始点(0,0)-終点(239,239) // LCD_DrawPixel(240+i, i,BLACK); } for(i=0; i<80; i++){ LCD_DrawPixel(240+i,i,BLACK); // 2本目:始点(240,0)-終点(319,79) } delay(5000); // 5秒待ち LCD_Fill(BLACK); // クリア for(i=0; i<240; i++){ // 斜め直線: 黒ベタ背景・白線表示 LCD_DrawPixel(i,i,WHITE); // 1本目:始点(0,0)-終点(239,239) // LCD_DrawPixel(240+i, i,WHITE); } for(i=0; i<80; i++){ LCD_DrawPixel(240+i,i,WHITE); // 2本目:始点(240,0)-終点(319,79) } delay(5000); // 5秒待ち LCD_Fill(BLACK); // クリア ///----------------------------------------------------------------------------------------------------- /// 直線描画テスト-------------------------------------------------------------------------------------------- i = 0; for(j=0; j<120; j+=10){ // ボックス表示 LCD_DrawLine(j,j, 319-j, j,YELLOW); // 次第に小さなボックスへ LCD_DrawLine(j,j, j, 239 -j,YELLOW); LCD_DrawLine(319-j,239-j, 319-j,j,YELLOW); LCD_DrawLine(319-j,239-j, j,239-j,YELLOW); delay(500); } delay(5000); // 5秒待ち LCD_Fill(BLACK); // クリア ///---------------------------------------------------------------------------------------------------------- /// 円の描画------------------------------------------------------------------------------------------------- for(i = 0; i < 10; i++){ LCD_DrawCircle(320/2 + 5*i,240/2,240/2,GREEN); } delay(5000); // 5秒待ち LCD_Fill(BLACK); // クリア ///---------------------------------------------------------------------------------------------------------- /// イメージグラフィック表示:------------------------------------------------------------------------------ LCD_DrawImage(0, Header1, MAGENTA, BLACK); LCD_DrawImage(8, Header2, CYAN, BLACK); LCD_DrawImage(16, My_PIC_Scope, GREEN, BLACK); while(1); }