/****************************************************** * プロジェクトファイル名:ILI9328_test4.ino * * ハードSPI・横置き表示 * 1文字表示+文字列描画テスト追加版 * * 初期化はaitendo参考コード準拠 * コントローラ:ESP32S3 Dev Module * 内蔵MPU:ESP32-WROOM-1:動作クロック周波数=240MHz(max) * * 2026/2/3 N.Ishii *******************************************************/ #include #include "soc/spi_reg.h" // レジスタ操作に必要 #include "soc/soc.h" #include "ASCII12dot.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 YELLOW 0xFFE0 //============================================== #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(unsigned int x, unsigned int y, unsigned int color); void LCD_DrawChar(char colum, char line, unsigned char letter, unsigned int color1, unsigned int color2); void LCD_DrawString(char colum, char line, char *s, 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(unsigned int x, unsigned 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(char colum, char line, unsigned char letter, unsigned int color1, unsigned int color2){ unsigned char 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(char colum, char 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; } } } //======================================================================= void setup() { // Serial.begin(115200); // Serial.println("setup start"); // 一度確実に終了させてから開始(初期化の安定化) SPI2.end(); /// CS,RSTは手動制御なので設定が必要 /// SCK, MOSIはbeginに任せる(pinModeは不要) /// これで SPI.transfer() を呼び出した際に、ESP32のハードウェアが自動的に /// SCKピンからロック信号を出力してくれる SPI2.begin(SCK, -1, MOSI, CS); pinMode(CS, OUTPUT); pinMode(RST, OUTPUT); digitalWrite(CS, HIGH); digitalWrite(RST, HIGH); /// ビットずれ対策:レジスタ直接操作 /// SPI2(FSPI)の送信タイミングを半サイクル遅らせて安定させます /// (1 << 2) は DOUT_MODE ビットを指す //WRITE_PERI_REG(SPI_DIN_MODE_REG(2), (1 << 2)); WRITE_PERI_REG(SPI_DIN_MODE_REG(2), 0); // 入力遅延をリセット LCD_Init(); LCD_Fill(BLACK); // 全画面クリア // Serial.println("setup end"); } void loop() { unsigned char i,j,index; /// ASCII文字の描画---------------------------------------------------------------------------------------- for(j=0; j<17; j++){ // ASCII文字全表示: 26文字/行 * 17文字/列=442キャラクタ for(i=0; i<26; i++){ index = j*26+i+0x20; // スペースコードから開始し、1行26文字で繰返し if (j<4) LCD_DrawChar(i, j, index, WHITE, BLACK); // 文字表示制御 if ((j>3) && (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); while(1); }