#ifndef LCD_SSD1306 #define LCD_SSD1306 //#include "../../io/SoftSPI.h" /** * https://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf * https://www.aliexpress.com/item/1-8-inch-TFT-color-screen-module-ST7735-SPI-at-least-4IO-support-C51-STM32-with/32809505663.html?spm=2114.search0302.3.266.14d83b8cQXOxfz&ws_ab_test=searchweb0_0,searchweb201602_0_450_452_532_533_534_10618_535_317_318_319_10059_10696_10084_100031_10083_10547_10304_10546_10843_10887_320_10307_10548_204_448_10065_449_10068_10320_10103_10884_10820,searchweb201603_0,ppcSwitch_0&algo_pvid=7cf0bb24-ac60-4e97-9878-8716f61a79f3&algo_expid=7cf0bb24-ac60-4e97-9878-8716f61a79f3-33 * https://sites.google.com/site/arduinomega2560projects/microchip-pic/level-3/st7735-1-8-tft (!!!!) * * display is SPI * CLK = clock * SDA = mosi * RS = data/command * RST = reset * CS = chip-select */ template class ST7735 { private: static constexpr const char* NAME = "ST7735"; SPI& spi; public: /** ctor */ ST7735(SPI& spi) : spi(spi) { MyGPIO::setOutput(PIN_DATA_COMMAND); MyGPIO::setOutput(PIN_CS); init(); } #define ST7735_NOP 0x00 #define ST7735_SWRESET 0x01 #define ST7735_RDDID 0x04 #define ST7735_RDDST 0x09 #define ST7735_SLPIN 0x10 #define ST7735_SLPOUT 0x11 #define ST7735_PTLON 0x12 #define ST7735_NORON 0x13 #define ST7735_INVOFF 0x20 #define ST7735_INVON 0x21 #define ST7735_DISPOFF 0x28 #define ST7735_DISPON 0x29 #define ST7735_CASET 0x2A #define ST7735_RASET 0x2B #define ST7735_RAMWR 0x2C #define ST7735_RAMRD 0x2E #define ST7735_PTLAR 0x30 #define ST7735_COLMOD 0x3A #define ST7735_MADCTL 0x36 #define ST7735_FRMCTR1 0xB1 #define ST7735_FRMCTR2 0xB2 #define ST7735_FRMCTR3 0xB3 #define ST7735_INVCTR 0xB4 #define ST7735_DISSET5 0xB6 #define ST7735_PWCTR1 0xC0 #define ST7735_PWCTR2 0xC1 #define ST7735_PWCTR3 0xC2 #define ST7735_PWCTR4 0xC3 #define ST7735_PWCTR5 0xC4 #define ST7735_VMCTR1 0xC5 #define ST7735_RDID1 0xDA #define ST7735_RDID2 0xDB #define ST7735_RDID3 0xDC #define ST7735_RDID4 0xDD #define ST7735_PWCTR6 0xFC #define ST7735_GMCTRP1 0xE0 #define ST7735_GMCTRN1 0xE1 private: static constexpr const int V = 128; static constexpr const int H = 160; inline void waitLong() { //vTaskDelay(200 / portTICK_PERIOD_MS); for (int i = 0; i < 0x1FFFFF; ++i) {asm("nop");} // vTaskDelay seems not to block? maybe when display is allocated outside of a function? } inline void waitShort() { //vTaskDelay(20 / portTICK_PERIOD_MS); for (int i = 0; i < 0xFFFF; ++i) {asm("nop");} } void init() { debugMod(NAME, "init()"); select(); sendCommand(ST7735_SWRESET); // 1: Software reset, 0 args deselect(); waitLong(); select(); sendCommand(ST7735_SLPOUT); // 2: Out of sleep mode, 0 args deselect(); waitLong(); select(); sendCommand(ST7735_FRMCTR1); // 3: Frame rate ctrl - normal mode) 3 args: 0xb1 sendData(0x01); sendData(0x2C); sendData(0x2D); // Rate = fosc/(1x2+40) * (LINE+2C+2D) waitShort(); sendCommand(ST7735_FRMCTR2); // 4: Frame rate control - idle mode) 3 args: 0xb2 sendData(0x01); sendData(0x2C); sendData(0x2D); // Rate = fosc/(1x2+40) * (LINE+2C+2D) waitShort(); sendCommand(ST7735_FRMCTR3); // 5: Frame rate ctrl - partial mode) 6 args: 0xb3 sendData(0x01); sendData(0x2C); sendData(0x2D); // Dot inversion mode sendData(0x01); sendData(0x2C); sendData(0x2D); // Line inversion mode waitShort(); sendCommand(ST7735_INVCTR); // 6: Display inversion ctrl) 1 arg) no delay: 0xb4 sendData(0x07); // No inversion sendCommand(ST7735_PWCTR1); // 7: Power control) 3 args) no delay: 0xc0 sendData(0xA2); sendData(0x02); // -4.6V sendData(0x84); // AUTO mode sendCommand(ST7735_PWCTR2); // 8: Power control) 1 arg) no delay: 0xc1 sendData(0xC5); // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD sendCommand(ST7735_PWCTR3); // 9: Power control) 2 args) no delay: 0xc2 sendData(0x0A); // Opamp current small sendData(0x00); // Boost frequency sendCommand(ST7735_PWCTR4); // 10: Power control) 2 args) no delay: sendData(0x8A); // BCLK/2) Opamp current small & Medium low sendData(0x2A); sendCommand(ST7735_PWCTR5); // 11: Power control) 2 args) no delay: sendData(0x8A); sendData(0xEE); sendCommand(ST7735_VMCTR1); // 12: Power control) 1 arg) no delay: sendData(0x0E); sendCommand(ST7735_INVOFF); // 13: Don't invert display) no args) no delay 0x20 sendCommand(ST7735_MADCTL); // 14: Memory access control (directions)) 1 arg: sendData(0xC8); // row addr/col addr); bottom to top refresh waitShort(); sendCommand(ST7735_COLMOD); // 15: set color mode); 1 arg); no delay: sendData(0x05); // 16-bit color deselect(); // required??? adjusts colors or something??? if (1 == 1) { select(); sendCommand(ST7735_GMCTRP1); // 1: Magical unicorn dust, 16 args, no delay: sendData(0x02); sendData(0x1c); sendData(0x07); sendData(0x12); sendData(0x37); sendData(0x32); sendData(0x29); sendData(0x2d); sendData(0x29); sendData(0x25); sendData(0x2B); sendData(0x39); sendData(0x00); sendData(0x01); sendData(0x03); sendData(0x10); sendCommand(ST7735_GMCTRN1); // 2: Sparkles and rainbows, 16 args, no delay: sendData(0x03); sendData(0x1d); sendData(0x07); sendData(0x06); sendData(0x2E); sendData(0x2C); sendData(0x29); sendData(0x2D); sendData(0x2E); sendData(0x2E); sendData(0x37); sendData(0x3F); sendData(0x00); sendData(0x00); sendData(0x02); sendData(0x10); deselect(); } select(); sendCommand(ST7735_NORON); // 3: Normal display on, no args deselect(); waitLong(); select(); sendCommand(ST7735_DISPON); // 4: Main screen turn on, no args deselect(); waitLong(); debugMod(NAME, "init() done"); } void clean(uint16_t color){ select(); uint8_t lo = color & 0xFF; uint8_t hi = color >> 8; sendCommand(ST7735_CASET); // Column addr set sendData(0x00); sendData(0); // XSTART sendData(0x00); sendData(V-1); // XEND sendCommand(ST7735_RASET); // Row addr set sendData(0x00); sendData(0); // YSTART sendData(0x00); sendData(H-1); // YEND sendCommand(ST7735_RAMWR); for(char x=0;x> 8; //sendData(lo); //sendData(hi); //spi::writeWord(color); spi.writeWord(color); }*/ spi.write((const uint8_t*)data, V*H*sizeof(uint16_t)); deselect(); } private: void sendData(uint8_t data) { modeData(); spi.writeByte(data); } void sendCommand(uint8_t cmd) { modeCommand(); spi.writeByte(cmd); } /** switch D/C line low */ inline void modeCommand() { MyGPIO::clear(PIN_DATA_COMMAND); } /** switch D/C line high */ inline void modeData() { MyGPIO::set(PIN_DATA_COMMAND); } /** set CS = low */ inline void select() { MyGPIO::clear(PIN_CS); } /** set CS = high */ inline void deselect() { MyGPIO::set(PIN_CS); } }; #endif