#ifndef LCD_ILI9341 #define LCD_ILI9341 #include "../../Debug.h" #include // https://www.displayfuture.com/Display/datasheet/controller/ILI9486L.pdf // https://www.waveshare.com/3.5inch-tft-touch-shield.htm // https://www.waveshare.com/wiki/File:3.5inch_TFT_Touch_Shield_Code.7z // https://github.com/ZinggJM/ILI9486_SPI/blob/master/src/ILI9486_SPI.cpp static constexpr const uint8_t ili9486_init[] = { }; //template class ILI9341 { template class ILI9486 { private: int w = 320; int h = 240; static constexpr const char* MOD = "ILI9486"; static constexpr const uint8_t REG_SWRESET = 0x01; // Software Reset static constexpr const uint8_t REG_RDDID = 0x04; // Read display identification information static constexpr const uint8_t REG_RDDST = 0x09; // Read Display Status static constexpr const uint8_t REG_CASET = 0x2A; // Column Address Set static constexpr const uint8_t REG_PASET = 0x2B; // Page Address Set static constexpr const uint8_t REG_RAMWR = 0x2C; // Memory Write static constexpr const uint8_t REG_RAMRD = 0x2E; // Memory Read SPI& spi; public: ILI9486(SPI& spi) : spi(spi) { MyGPIO::setOutput(PIN_DATA_COMMAND); MyGPIO::setOutput(PIN_CS); } /** perform display software reset and initialization */ void init() { // send reset command wait(); sendCommand(REG_SWRESET); wait(); getStatus(); //sendCommandAndData(0xb0, {0x00}); // Interface Mode Control sendCommandAndData(0x11, {}); // disable sleep wait(); sendCommandAndData(0x3A, {0x55}); // Interface Pixel Format, 16 bits / pixel sendCommandAndData(0x36, {0x28}); // Memory Access Control sendCommandAndData(0xC2, {0x44}); // Power Control 3 (For Normal Mode) sendCommandAndData(0xC5, {0x00, 0x00, 0x00, 0x00}); // VCOM Control sendCommandAndData(0xE0, {0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00}); // PGAMCTRL(Positive Gamma Control) sendCommandAndData(0xE1, {0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00}); // NGAMCTRL (Negative Gamma Correction) sendCommandAndData(0xE2, {0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00}); // Digital Gamma Control 1 sendCommandAndData(0x36, {0x28}); // Memory Access Control, BGR sendCommandAndData(0x11, {}), // # Sleep OUT sendCommandAndData(0x29, {}), // Display ON wait(); /* sendCommand(0x3A); sendData(0x55); // use 16 bits per pixel color sendCommand(0x36); sendData(0x48); // MX, BGR == rotation 0 // PGAMCTRL(Positive Gamma Control) sendCommand(0xE0); sendData(0x0F); sendData(0x1F); sendData(0x1C); sendData(0x0C); sendData(0x0F); sendData(0x08); sendData(0x48); sendData(0x98); sendData(0x37); sendData(0x0A); sendData(0x13); sendData(0x04); sendData(0x11); sendData(0x0D); sendData(0x00); // NGAMCTRL(Negative Gamma Control) sendCommand(0xE1); sendData(0x0F); sendData(0x32); sendData(0x2E); sendData(0x0B); sendData(0x0D); sendData(0x05); sendData(0x47); sendData(0x75); sendData(0x37); sendData(0x06); sendData(0x10); sendData(0x03); sendData(0x24); sendData(0x20); sendData(0x00); // Digital Gamma Control 1 sendCommand(0xE2); sendData(0x0F); sendData(0x32); sendData(0x2E); sendData(0x0B); sendData(0x0D); sendData(0x05); sendData(0x47); sendData(0x75); sendData(0x37); sendData(0x06); sendData(0x10); sendData(0x03); sendData(0x24); sendData(0x20); sendData(0x00); sendCommand(0x11); // Sleep OUT wait(); sendCommand(0x29); // Display ON wait(); */ } void sendCommandAndData(uint8_t cmd, std::initializer_list data) { sendCommand(cmd); for (uint8_t b : data) {sendData(b);} } uint32_t getID() { sendCommand(REG_RDDID); uint32_t res = 0xFFFFFFFF; spi.read(reinterpret_cast(&res), 4); // dummy-byte + 3 data bytes return res; } void getStatus() { uint8_t buf[5]; sendCommand(REG_RDDST); uint32_t res = 0xFFFFFFFF; spi.read(buf, 5); // dummy-byte + 4 data bytes printf("Status: %02x %02x %02x %02x \n", buf[1],buf[2],buf[3],buf[4]); } /* void read() { chipSelect(); setAddrWindow(0,0,100,100); sendCommand(REG_RAMRD); uint8_t buf[32]; readBytes(buf, 32); for (int i = 0; i < 32; ++i) { printf("%d ", buf[i]); } printf("\n"); chipDeselect(); } */ void draw(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t* data) { setAddrWindow(x,y,w,h); modeDATA(); chipSelect(); spi.write((const uint8_t*)data, w*h*2); chipDeselect(); } void fillRand() { setAddrWindow(0,0,w,h); modeDATA(); chipSelect(); for (int y = 0; y < h; ++y) { uint16_t buf[w]; for (int x = 0; x < w; ++x) {buf[x] = rand();} spi.write(reinterpret_cast(buf), w*2); } chipDeselect(); } void fillColor(uint16_t color) { setAddrWindow(0,0,w,h); modeDATA(); chipSelect(); for (uint32_t i = 0; i < w*h; ++i) { spi.writeWord(color); } chipDeselect(); } private: void wait() { vTaskDelay(250 / portTICK_PERIOD_MS); } void setAddrWindow(const uint16_t x1, const uint16_t y1, const uint16_t w, const uint16_t h) { // end (x,y) uint16_t x2 = x1 + w - 1; uint16_t y2 = y1 + h - 1; sendCommand(REG_CASET); // Column addr set sendData(x1 >> 8); //Set the horizontal starting point to the high octet sendData(x1 & 0xff); //Set the horizontal starting point to the low octet sendData(x2 >> 8); //Set the horizontal end to the high octet sendData(x2 & 0xff); //Set the horizontal end to the low octet sendCommand(REG_PASET); // Row addr set sendData(y1 >> 8); sendData(y1 & 0xff ); sendData(y2 >> 8); sendData(y2 & 0xff); sendCommand(REG_RAMWR); // write to RAM // transmit data now } /** send the given command to the display */ void sendCommand(const uint8_t cmd) { modeCMD(); chipSelect(); spi.writeByte(0x00); // 16 bit transfer! spi.writeByte(cmd); chipDeselect(); } /** send the given data to the display */ void sendData(const uint8_t data) { modeDATA(); chipSelect(); spi.writeByte(0x00); // 16 bit transfer! spi.writeByte(data); chipDeselect(); } // /** send the given data to the display */ // void sendBytes(const uint8_t* data, const size_t len) { // spi.write(data, len); // } // /** read the given data from the display */ // void readBytes(uint8_t* data, const size_t len) { // spi.read(data, len); // } /** select the display (CS=0) */ inline void chipSelect() { //asm("nop");asm("nop");asm("nop");asm("nop"); MyGPIO::clear(PIN_CS); //asm("nop");asm("nop");asm("nop");asm("nop"); } /** unselect the display (CS=1) */ inline void chipDeselect() { //asm("nop");asm("nop");asm("nop");asm("nop"); MyGPIO::set(PIN_CS); //asm("nop");asm("nop");asm("nop");asm("nop"); } /** switch to command-mode */ inline void modeCMD() { //asm("nop");asm("nop");asm("nop");asm("nop"); MyGPIO::clear(PIN_DATA_COMMAND); //asm("nop");asm("nop");asm("nop");asm("nop"); } /** switch to data-mode */ inline void modeDATA() { //asm("nop");asm("nop");asm("nop");asm("nop"); MyGPIO::set(PIN_DATA_COMMAND); //asm("nop");asm("nop");asm("nop");asm("nop"); } }; #endif