/*************************************************** STM32 Support added by Jaret Burkett at OSHlab.com This is our library for the Adafruit ILI9488 Breakout and Shield ----> http://www.adafruit.com/products/1651 Check out the links above for our tutorials and wiring diagrams These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional) Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution ****************************************************/ #include #include "ILI9488.h" #include // if using software spi this optimizes the code #define ILI9488_START start(); #define ILI9488_STOP stop(); const uint16_t ili9488_colors[]={ILI9488_BLACK,ILI9488_WHITE,ILI9488_RED,ILI9488_GREEN,ILI9488_BLUE,ILI9488_CYAN,ILI9488_MAGENTA,\ ILI9488_YELLOW,ILI9488_NAVY,ILI9488_DARKGREEN,ILI9488_DARKCYAN,ILI9488_MAROON,ILI9488_PURPLE,ILI9488_OLIVE,\ ILI9488_LIGHTGREY,ILI9488_DARKGREY,ILI9488_ORANGE,ILI9488_GREENYELLOW,ILI9488_PINK}; // Constructor when using software SPI. All output pins are configurable. ILI9488::ILI9488(int8_t cs,int8_t mosi,int8_t sclk,int8_t bp) : Renderer(ILI9488_TFTWIDTH, ILI9488_TFTHEIGHT) { _cs = cs; _mosi = mosi; _sclk = sclk; _bp = bp; _hwspi = 0; } /* CPU Clock = 80 Mhz max clock of display is 15 Mhz (66ns sclk cycle) so cpu/8 => 10 Mhz should be ok HSPI CLK 5 GPIO14 HSPI /CS 8 GPIO15 HSPI MOSI 7 GPIO13 HSPI MISO 6 GPIO12 GPIO names for your easy reference: GPIO0: PERIPHS_IO_MUX_GPIO0_U GPIO1: PERIPHS_IO_MUX_U0TXD_U GPIO2: PERIPHS_IO_MUX_GPIO2_U GPIO3: PERIPHS_IO_MUX_U0RXD_U GPIO4: PERIPHS_IO_MUX_GPIO4_U GPIO5: PERIPHS_IO_MUX_GPIO5_U GPIO6: PERIPHS_IO_MUX_SD_CLK_U GPIO7: PERIPHS_IO_MUX_SD_DATA0_U GPIO8: PERIPHS_IO_MUX_SD_DATA1_U GPIO9: PERIPHS_IO_MUX_SD_DATA2_U GPIO10: PERIPHS_IO_MUX_SD_DATA3_U GPIO11: PERIPHS_IO_MUX_SD_CMD_U GPIO12: PERIPHS_IO_MUX_MTDI_U GPIO13: PERIPHS_IO_MUX_MTCK_U GPIO14: PERIPHS_IO_MUX_MTMS_U GPIO15: PERIPHS_IO_MUX_MTDO_U */ uint8_t ili9488_start; #ifndef ESP32 // ESP8266 #include "spi_register.h" #define SWSPI_OPTMODE // this enables the 27 bit packed mode #define RGB_PACK_MODE uint32_t ili9488_clock; uint32_t ili9488_usr; uint32_t ili9488_usr1; uint32_t ili9488_usr2; uint32_t ili9488_spi1c; uint32_t ili9488_spi1c1; uint32_t ili9488_spi1p; uint32_t ili9488_gpmux; uint32_t ili9488_mtdo; uint32_t ili9488_clock_prev; uint32_t ili9488_usr_prev; uint32_t ili9488_usr1_prev; uint32_t ili9488_usr2_prev; uint32_t ili9488_spi1c_prev; uint32_t ili9488_spi1c1_prev; uint32_t ili9488_spi1p_prev; uint32_t ili9488_gpmux_prev; uint32_t ili9488_mtdo_prev; // code from espressif SDK /****************************************************************************** * FunctionName : spi_lcd_mode_init * Description : SPI master initial function for driving LCD 3 wire spi *******************************************************************************/ void ILI9488::spi_lcd_mode_init(void) { ili9488_clock_prev=SPI1CLK; ili9488_usr_prev=SPI1U; ili9488_usr1_prev=SPI1U1; ili9488_usr2_prev=SPI1U2; ili9488_spi1c_prev=SPI1C; ili9488_spi1c1_prev=SPI1C1; ili9488_spi1p_prev=SPI1P; ili9488_gpmux_prev=GPMUX; ili9488_mtdo_prev=READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U); SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE; SPI1U1=0; SPI1C = 0; SPI1C1 = 0; //bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock //bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9 //PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure miso to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure mosi to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure sclk to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure cs to spi mode // the current implementation leaves about 1 us between transfers ???? // due to lack of documentation i could not find the reason // skipping this would double the speed !!! //SET_PERI_REG_MASK(SPI_USER(1), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND); SET_PERI_REG_MASK(SPI_USER(1), SPI_USR_COMMAND); CLEAR_PERI_REG_MASK(SPI_USER(1), SPI_FLASH_MODE); // SPI clock=CPU clock/8 => 10 Mhz /* WRITE_PERI_REG(SPI_CLOCK(1), ((1&SPI_CLKDIV_PRE)<>1)&0x7f; ILI9488_START regvalue= ((8&SPI_USR_COMMAND_BITLEN)<>1)|0x80; ILI9488_START regvalue= ((8&SPI_USR_COMMAND_BITLEN)<>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(d&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); } #else // ESP32 section void ILI9488::writedata(uint8_t d) { ILI9488_START fastSPIwrite(d,1); } void ILI9488::writecommand(uint8_t c) { ILI9488_START fastSPIwrite(c,0); } #include "soc/spi_reg.h" #include "soc/spi_struct.h" #include "esp32-hal-spi.h" #include "esp32-hal.h" #include "soc/spi_struct.h" #define RGB_PACK_MODE // since ardunio transferBits ia completely disfunctional // we use our own hardware driver for 9 bit spi void ILI9488::fastSPIwrite(uint8_t d,uint8_t dc) { digitalWrite( _cs, LOW); uint32_t regvalue=d>>1; if (dc) regvalue|=0x80; else regvalue&=0x7f; if (d&1) regvalue|=0x8000; REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI); REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1); uint32_t *dp=(uint32_t*)SPI_W0_REG(3); *dp=regvalue; REG_SET_BIT(SPI_CMD_REG(3), SPI_USR); while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); digitalWrite( _cs, HIGH); } SPISettings ili9488_spiSettings; void ILI9488::start(void) { if (ili9488_start) return; SPI.beginTransaction(ili9488_spiSettings); ili9488_start=1; } void ILI9488::stop(void) { if (!ili9488_start) return; SPI.endTransaction(); ili9488_start=0; } #endif uint16_t ILI9488::GetColorFromIndex(uint8_t index) { if (index>=sizeof(ili9488_colors)/2) index=0; return ili9488_colors[index]; } void ILI9488::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { setRotation(rot); invertDisplay(false); setTextWrap(false); // Allow text to run off edges cp437(true); setTextFont(font&3); setTextSize(size&7); setTextColor(ILI9488_WHITE,ILI9488_BLACK); setCursor(0,0); fillScreen(ILI9488_BLACK); ILI9488_STOP } void ILI9488::DisplayOnff(int8_t on) { if (on) { writecommand(ILI9488_DISPON); //Display on if (_bp>=0) { digitalWrite(_bp,HIGH); /* writecommand(ILI9488_WRCTRLD); writedata(0x0c); writecommand(ILI9488_CAPC9); writedata(0x3f);*/ } } else { writecommand(ILI9488_DISPOFF); if (_bp>=0) { digitalWrite(_bp,LOW); //writecommand(ILI9488_WRCTRLD); //writedata(0x04); } } ILI9488_STOP } void ILI9488::begin(void) { pinMode(_cs, OUTPUT); digitalWrite(_cs,HIGH); pinMode(_sclk, OUTPUT); pinMode(_mosi, OUTPUT); if (_bp>=0) { pinMode(_bp, OUTPUT); digitalWrite(_bp,HIGH); } #ifndef ESP32 if ((_sclk==14) && (_mosi==13) && (_cs==15)) { // we use hardware spi SPI.begin(); _hwspi=1; spi_lcd_mode_init(); } else { // we must use software spi _hwspi=0; } #else SPI.begin(_sclk,-1,_mosi, -1); ili9488_spiSettings = SPISettings(10000000, MSBFIRST, SPI_MODE3); _hwspi=1; #endif ILI9488_START delay(1); writecommand(0xE0); writedata(0x00); writedata(0x03); writedata(0x09); writedata(0x08); writedata(0x16); writedata(0x0A); writedata(0x3F); writedata(0x78); writedata(0x4C); writedata(0x09); writedata(0x0A); writedata(0x08); writedata(0x16); writedata(0x1A); writedata(0x0F); writecommand(0XE1); writedata(0x00); writedata(0x16); writedata(0x19); writedata(0x03); writedata(0x0F); writedata(0x05); writedata(0x32); writedata(0x45); writedata(0x46); writedata(0x04); writedata(0x0E); writedata(0x0D); writedata(0x35); writedata(0x37); writedata(0x0F); writecommand(0XC0); //Power Control 1 writedata(0x17); //Vreg1out writedata(0x15); //Verg2out writecommand(0xC1); //Power Control 2 writedata(0x41); //VGH,VGL writecommand(0xC5); //Power Control 3 writedata(0x00); writedata(0x12); //Vcom writedata(0x80); writecommand(0x36); //Memory Access writedata(0x48); writecommand(0x3A); // Interface Pixel Format writedata(0x66); //18 bit writecommand(0XB0); // Interface Mode Control writedata(0x80); //SDO NOT USE writecommand(0xB1); //Frame rate writedata(0xA0); //60Hz writecommand(0xB4); //Display Inversion Control writedata(0x02); //2-dot writecommand(0XB6); //Display Function Control RGB/MCU Interface Control writedata(0x02); //MCU writedata(0x02); //Source,Gate scan dieection writecommand(0XE9); // Set Image Functio writedata(0x00); // Disable 24 bit data writecommand(0xF7); // Adjust Control writedata(0xA9); writedata(0x51); writedata(0x2C); writedata(0x82); // D7 stream, loose writecommand(ILI9488_SLPOUT); //Exit Sleep delay(120); writecommand(ILI9488_DISPON); //Display on ILI9488_STOP } /* void ILI9488::setScrollArea(uint16_t topFixedArea, uint16_t bottomFixedArea){ writecommand(0x33); // Vertical scroll definition writedata(topFixedArea >> 8); writedata(topFixedArea); writedata((_height - topFixedArea - bottomFixedArea) >> 8); writedata(_height - topFixedArea - bottomFixedArea); writedata(bottomFixedArea >> 8); writedata(bottomFixedArea); ILI9488_STOP } void ILI9488::scroll(uint16_t pixels){ writecommand(0x37); // Vertical scrolling start address writedata(pixels >> 8); writedata(pixels); ILI9488_STOP }*/ void ILI9488::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { uint8_t flag=0; if (!x0 && !y0 && !x1 && !y1) { x0=0; y0=0; x1=_width; y1=_height; flag=1; } if (x1>_width) x1=_width; if (y1>_height) y1=_height; writecommand(ILI9488_CASET); // Column addr set writedata(x0 >> 8); writedata(x0 & 0xFF); // XSTART writedata(x1 >> 8); writedata(x1 & 0xFF); // XEND writecommand(ILI9488_PASET); // Row addr set writedata(y0>>8); writedata(y0 &0xff); // YSTART writedata(y1>>8); writedata(y1 &0xff); // YEND writecommand(ILI9488_RAMWR); // write to RAM if (flag) ILI9488_STOP } /* void ILI9488::drawImage(const uint8_t* img, uint16_t x, uint16_t y, uint16_t w, uint16_t h){ return; // rudimentary clipping (drawChar w/big text requires this) if((x >= _width) || (y >= _height)) return; if((x + w - 1) >= _width) w = _width - x; if((y + h - 1) >= _height) h = _height - y; setAddrWindow(x, y, x+w-1, y+h-1); // uint8_t hi = color >> 8, lo = color; #if defined(USE_FAST_PINIO) && !defined (_VARIANT_ARDUINO_STM32_) *dcport |= dcpinmask; *csport &= ~cspinmask; #else digitalWrite(_dc, HIGH); digitalWrite(_cs, LOW); #endif uint8_t linebuff[w*3+1]; uint16_t pixels = w*h; // uint16_t count = 0; uint32_t count = 0; for (uint16_t i = 0; i < h; i++) { uint16_t pixcount = 0; for (uint16_t o = 0; o < w; o++) { uint8_t b1 = img[count]; count++; uint8_t b2 = img[count]; count++; uint16_t color = b1 << 8 | b2; linebuff[pixcount] = (((color & 0xF800) >> 11)* 255) / 31; pixcount++; linebuff[pixcount] = (((color & 0x07E0) >> 5) * 255) / 63; pixcount++; linebuff[pixcount] = ((color & 0x001F)* 255) / 31; pixcount++; } // for row #if defined (__STM32F1__) SPI.dmaSend(linebuff, w*3); #else for(uint16_t b = 0; b < w*3; b++){ spiwrite(linebuff[b]); } #endif }// for col #if defined(USE_FAST_PINIO) && !defined (_VARIANT_ARDUINO_STM32_) *csport |= cspinmask; #else digitalWrite(_cs, HIGH); #endif if (hwSPI) spi_end(); } */ void ILI9488::pushColor(uint16_t color) { write16BitColor(color); ILI9488_STOP } void ILI9488::pushColors(uint16_t *data, uint8_t len, boolean first) { uint16_t color; uint8_t buff[len*3+1]; uint16_t count = 0; uint8_t lencount = len; while(lencount--) { color = *data++; buff[count] = (((color & 0xF800) >> 11)* 255) / 31; count++; buff[count] = (((color & 0x07E0) >> 5) * 255) / 63; count++; buff[count] = ((color & 0x001F)* 255) / 31; count++; } for(uint16_t b = 0; b < len*3; b++){ writedata(buff[b]); } ILI9488_STOP } void ILI9488::write16BitColor(uint16_t color){ // #if (__STM32F1__) // uint8_t buff[4] = { // (((color & 0xF800) >> 11)* 255) / 31, // (((color & 0x07E0) >> 5) * 255) / 63, // ((color & 0x001F)* 255) / 31 // }; // SPI.dmaSend(buff, 3); // #else uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; uint8_t b = color & 0x001F; r = (r * 255) / 31; g = (g * 255) / 63; b = (b * 255) / 31; #ifndef SWSPI_OPTMODE writedata(r); writedata(g); writedata(b); #else if (_hwspi) { writedata(r); writedata(g); writedata(b); } else { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); } #endif ILI9488_STOP } void ILI9488::drawPixel(int16_t x, int16_t y, uint16_t color) { if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; setAddrWindow(x,y,x+1,y+1); write16BitColor(color); ILI9488_STOP } void ILI9488::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { // Rudimentary clipping if((x >= _width) || (y >= _height)) return; if((y+h-1) >= _height) h = _height-y; setAddrWindow(x, y, x, y+h-1); uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; uint8_t b = color & 0x001F; r = (r * 255) / 31; g = (g * 255) / 63; b = (b * 255) / 31; while (h--) { #ifndef SWSPI_OPTMODE writedata(r); writedata(g); writedata(b); #else if (_hwspi) { writedata(r); writedata(g); writedata(b); } else { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); } #endif } ILI9488_STOP } void ILI9488::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { // Rudimentary clipping if((x >= _width) || (y >= _height)) return; if((x+w-1) >= _width) w = _width-x; setAddrWindow(x, y, x+w-1, y); uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; uint8_t b = color & 0x001F; r = (r * 255) / 31; g = (g * 255) / 63; b = (b * 255) / 31; while (w--) { #ifndef SWSPI_OPTMODE writedata(r); writedata(g); writedata(b); #else if (_hwspi) { writedata(r); writedata(g); writedata(b); } else { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); } #endif } ILI9488_STOP } // this moves 460 kbytes // now at 475 ms with 13,3 Mhz clock void ILI9488::fillScreen(uint16_t color) { //uint32_t time=millis(); fillRect(0, 0, _width, _height, color); //time=millis()-time; //Serial.printf("time %d ms\n",time); ILI9488_STOP } //#define WAIT_9BITS asm_nop_9bits(); #define WAIT_9BITS //#define WAIT_BEFORE while(*((uint32_t *)0x60000100)&SPI_USR); //waiting for spi module available #define WAIT_SPI_READY while(READ_PERI_REG(SPI_CMD(1))&SPI_USR); //#define WAIT_SPI_READY //#define DIAG_PIN_SET WRITE_PERI_REG( PIN_OUT_SET, 1<<2); //#define DIAG_PIN_CLR WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<2); #define DIAG_PIN_SET #define DIAG_PIN_CLR //#define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val) // CMD 0x60000200-1*0x100 // SPI_USER2 0x60000200-1*0x100 + 0x24 //#define WRITE_SPI_REG WRITE_PERI_REG(0x60000124, regvalue_r);SET_PERI_REG_MASK(0x60000100, SPI_USR); // THIS TAKES 1 us => 80 cpu clock cycles !!!!!!!!!!!!!!!!!!!!!!!!!! // probably the memw causes this delay #define WRITE_SPI_REG(A) WRITE_PERI_REG(SPI_USER2(1), A); SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); //#define WRITE_SPI_REG(A) *((uint32_t *)0x60000124)=A; *((uint32_t *)0x60000100)|=SPI_USR; //#define WRITE_SPI_REG // extremely strange => if this code is merged into pack_rgb() the software crashes // swap bytes uint32_t ulswap(uint32_t data) { union { uint32_t l; uint8_t b[4]; } data_; data_.l = data; // MSBFIRST Byte first data = (data_.b[3] | (data_.b[2] << 8) | (data_.b[1] << 16) | (data_.b[0] << 24)); return data; } // pack RGB into uint32 uint32_t pack_rgb(uint32_t r, uint32_t g, uint32_t b) { uint32_t data; data=r<<23; data|=g<<14; data|=b<<5; data|=0b10000000010000000010000000000000; return ulswap(data); } #ifndef ESP32 // fill a rectangle void ILI9488::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { ILI9488_START // rudimentary clipping (drawChar w/big text requires this) if((x >= _width) || (y >= _height)) return; if((x + w - 1) >= _width) w = _width - x; if((y + h - 1) >= _height) h = _height - y; setAddrWindow(x, y, x+w-1, y+h-1); //ILI9488_START uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; uint8_t b = color & 0x001F; r = (r * 255) / 31; g = (g * 255) / 63; b = (b * 255) / 31; uint32_t regvalue_r,regvalue_g,regvalue_b; uint32_t data; if (_hwspi) { // precalculate the register values for rgb #ifndef RGB_PACK_MODE uint8_t bytetemp; bytetemp=(r>>1)|0x80; regvalue_r= ((8&SPI_USR_COMMAND_BITLEN)<>1)|0x80; regvalue_g= ((8&SPI_USR_COMMAND_BITLEN)<>1)|0x80; regvalue_b= ((8&SPI_USR_COMMAND_BITLEN)< MSBFIRST SPI1U = SPIUMOSI; SPI1C1 = 0; data=pack_rgb(r,g,b); #endif } for(y=h; y>0; y--) { delay(0); for(x=w; x>0; x--) { #ifndef SWSPI_OPTMODE writedata(r); writedata(g); writedata(b); #else if (_hwspi) { //noInterrupts(); #ifdef RGB_PACK_MODE while(SPI1CMD & SPIBUSY) {} SPI1W0 = data; SPI1CMD |= SPIBUSY; #else DIAG_PIN_CLR WAIT_SPI_READY DIAG_PIN_SET WRITE_SPI_REG(regvalue_r) WAIT_9BITS DIAG_PIN_CLR WAIT_SPI_READY DIAG_PIN_SET WRITE_SPI_REG(regvalue_g) WAIT_9BITS DIAG_PIN_CLR WAIT_SPI_READY DIAG_PIN_SET WRITE_SPI_REG(regvalue_b) WAIT_9BITS //interrupts(); #endif } else { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); for(uint8_t bit = 0x80; bit; bit >>= 1) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); } WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); } #endif } } #ifdef RGB_PACK_MODE // reinit old mode while(SPI1CMD & SPIBUSY) {} ILI9488_STOP //spi_lcd_mode_init(); #endif } #else // ESP32 void ILI9488::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { // rudimentary clipping (drawChar w/big text requires this) if((x >= _width) || (y >= _height)) return; if((x + w - 1) >= _width) w = _width - x; if((y + h - 1) >= _height) h = _height - y; setAddrWindow(x, y, x+w-1, y+h-1); uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; uint8_t b = color & 0x001F; r = (r * 255) / 31; g = (g * 255) / 63; b = (b * 255) / 31; #ifdef RGB_PACK_MODE // init 27 bit mode uint32_t data=pack_rgb(r,g,b); REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI); REG_WRITE(SPI_MOSI_DLEN_REG(3), 27 - 1); uint32_t *dp=(uint32_t*)SPI_W0_REG(3); digitalWrite( _cs, LOW); #endif for(y=h; y>0; y--) { for(x=w; x>0; x--) { #ifndef RGB_PACK_MODE writedata(r); writedata(g); writedata(b); #else while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); *dp=data; REG_SET_BIT(SPI_CMD_REG(3), SPI_USR); #endif } } #ifdef RGB_PACK_MODE while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); digitalWrite( _cs, HIGH); #endif ILI9488_STOP } #endif // Pass 8-bit (each) R,G,B, get back 16-bit packed color uint16_t ILI9488::color565(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } #define MADCTL_MY 0x80 #define MADCTL_MX 0x40 #define MADCTL_MV 0x20 #define MADCTL_ML 0x10 #define MADCTL_RGB 0x00 #define MADCTL_BGR 0x08 #define MADCTL_MH 0x04 void ILI9488::setRotation(uint8_t m) { writecommand(ILI9488_MADCTL); rotation = m % 4; // can't be higher than 3 switch (rotation) { case 0: writedata(MADCTL_MX | MADCTL_BGR); _width = ILI9488_TFTWIDTH; _height = ILI9488_TFTHEIGHT; break; case 1: writedata(MADCTL_MV | MADCTL_BGR); _width = ILI9488_TFTHEIGHT; _height = ILI9488_TFTWIDTH; break; case 2: writedata(MADCTL_MY | MADCTL_BGR); _width = ILI9488_TFTWIDTH; _height = ILI9488_TFTHEIGHT; break; case 3: writedata(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); _width = ILI9488_TFTHEIGHT; _height = ILI9488_TFTWIDTH; break; } ILI9488_STOP } void ILI9488::invertDisplay(boolean i) { writecommand(i ? ILI9488_INVON : ILI9488_INVOFF); ILI9488_STOP }