+/***************************************************
+ This is a first stab at modifying the code below, which
+ originally worked on an Arduino, to work directly with
+ an ESP8266, it is not clever, it is not optimised yet
+ but it works. I've tested in landscape mode using GPIOs
+ 4,5,12 and 15 (you may not need RST at all, I hooked it
+ to ESP reset. I did check to see if you can do away with
+ You need EASYGPIO for this - OR you could decide beforehand
+ the pins you want to use and hard-code the IO which would make
+ it marginally faster. Or you could go HERE
+ https://github.com/MetalPhreak/ESP8266_SPI_Driver
+ and transform this software by using hardware SPI on the ESP.
+ I've not done this yet as I want to get the fonts working.
+ Next step is to put the init code in FLASH but it gets messy
+ (fonts will really need to be in flash) so I thought I'd
+ make this available before I start really hacking it up.
+ 17/09/2015 Peter Scargill - http://tech.scargill.net
+ So in use I added this to my main code
+ #include "QDTech/QDTech.h"
+ Then this code to test... remember to scrap any other init or use
+ of the relevant port bits in your code
+ QD_init(4,5,15,12,0,160,128);
+ QD_setAddrWindow(0,0,160,128);
+ QD_fillScreen(QD_Color565(255,0,0));
+ QD_fillRect(30,30,90,90,QD_Color565(0,255,0));
+ for (int qq=0; qq<160;qq++) QD_drawPixel(qq,qq,QD_Color565(0,0,255));
+ There is referrence below to the stock Adafruit GFX library for fonts
+ - not included that yet as that will need modifying to put the fonts
+/***************************************************
+ This is a modification of the Adafruit SPI LCD library,
+ customised for hardware SPI and the QDTech board
+ using a Samsung S6D02A1 chip.
+ Most changes are made to the initialisation routine but
+ non-Arduino code has been removed too.
+ The initialisation sequence comes from Henning Karlsen's
+ UTFT library: http://henningkarlsen.com
+ Using the hardware SPI pins is highly recommeneded.
+ You will also need the stock "Adafruit_GFX" library.
+ https://github.com/adafruit/Adafruit-GFX-Library
+ 6/2/14 1.1 Fixed RGB colour order error
+/***************************************************
+ This is a library for the Adafruit 1.8" SPI display.
+ This library works with the Adafruit 1.8" TFT Breakout w/SD card
+ ----> http://www.adafruit.com/products/358
+ as well as Adafruit raw 1.8" TFT display
+ ----> http://www.adafruit.com/products/618
+ 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 "QDTech/QDTech.h"
+// Rather than a bazillion writecommand() and writedata() calls, screen
+// initialization commands and arguments are organized in these tables
+// stored in PROGMEM. The table may look bulky, but that's mostly the
+// formatting -- storage-wise this is hundreds of bytes more compact
+// than the equivalent code. Companion function follows.
+static const uint8_t QDTech[] = { // QDTech support only now
+ 0xf0, 2, 0x5a, 0x5a, // Excommand2
+ 0xfc, 2, 0x5a, 0x5a, // Excommand3
+ 0x26, 1, 0x01, // Gamma set
+ 0xfa, 15, 0x02, 0x1f, 0x00, 0x10, 0x22, 0x30, 0x38, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3d, 0x02, 0x01, // Positive gamma control
+ 0xfb, 15, 0x21, 0x00, 0x02, 0x04, 0x07, 0x0a, 0x0b, 0x0c, 0x0c, 0x16, 0x1e, 0x30, 0x3f, 0x01, 0x02, // Negative gamma control
+ 0xfd, 11, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x01, 0x00, 0x1f, 0x1f, // Analog parameter control
+ 0xf4, 15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, // Power control
+ 0xf5, 13, 0x00, 0x70, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x66, 0x06, // VCOM control
+ 0xf6, 11, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, // Source control
+ 0xf2, 17, 0x00, 0x01, 0x03, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x08, 0x08, //Display control
+ 0xf8, 1, 0x11, // Gate control
+ 0xf7, 4, 0xc8, 0x20, 0x00, 0x00, // Interface control
+ 0xf3, 2, 0x00, 0x00, // Power sequence control
+ 0x11, DELAY, 50, // Wake
+ 0xf3, 2+DELAY, 0x00, 0x01, 50, // Power sequence control
+ 0xf3, 2+DELAY, 0x00, 0x03, 50, // Power sequence control
+ 0xf3, 2+DELAY, 0x00, 0x07, 50, // Power sequence control
+ 0xf3, 2+DELAY, 0x00, 0x0f, 50, // Power sequence control
+ 0xf4, 15+DELAY, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, 50, // Power control
+ 0xf3, 2+DELAY, 0x00, 0x1f, 50, // Power sequence control
+ 0xf3, 2+DELAY, 0x00, 0x7f, 50, // Power sequence control
+ 0xf3, 2+DELAY, 0x00, 0xff, 50, // Power sequence control
+ 0xfd, 11, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x01, 0x00, 0x16, 0x16, // Analog parameter control
+ 0xf4, 15, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, // Power control
+ 0x36, 1, 0x08, // Memory access data control
+ 0x35, 1, 0x00, // Tearing effect line on
+ 0x3a, 1+DELAY, 0x05, 150, // Interface pixel control
+ 0x2c, 0 // Memory write
+inline uint16_t QD_swapcolor(uint16_t x) {
+ return (x << 11) | (x & 0x07E0) | (x >> 11);
+// Init when using software SPI. All output pins are configurable.
+void ICACHE_FLASH_ATTR QD_init(uint8_t cs, uint8_t rs, uint8_t sid, uint8_t sclk, uint8_t rst,uint8_t qwidth,uint8_t qheight)
+ QD_commandList(QDTech);
+void QD_spiwrite(uint8_t c) {
+ // Fast SPI bitbang swiped from LPD8806 library
+ for(uint8_t bit = 0x80; bit; bit >>= 1) {
+ if(c & bit) easygpio_outputSet(_sid,1);
+ else easygpio_outputSet(_sid,0);
+ easygpio_outputSet(_sclk,1);
+ easygpio_outputSet(_sclk,0);
+void QD_writecommand(uint8_t c) {
+ easygpio_outputSet(_rs,0);
+ easygpio_outputSet(_cs,0);
+ easygpio_outputSet(_cs,1);
+void QD_writedata(uint8_t c) {
+ easygpio_outputSet(_rs,1);
+ easygpio_outputSet(_cs,0);
+ easygpio_outputSet(_cs,1);
+// Companion code to the above tables. Reads and issues
+// a series of LCD commands stored in PROGMEM byte array.
+void ICACHE_FLASH_ATTR QD_commandList(const uint8_t *addr) {
+ uint8_t numCommands, numArgs;
+ numCommands = *addr++; // Number of commands to follow
+ while(numCommands--) { // For each command...
+ QD_writecommand(*addr++); // Read, issue command
+ numArgs = *addr++; // Number of args to follow
+ ms = numArgs & DELAY; // If hibit set, delay follows args
+ numArgs &= ~DELAY; // Mask out delay bit
+ while(numArgs--) { // For each argument...
+ QD_writedata(*addr++); // Read, issue argument
+ ms = *addr++; // Read post-command delay time (ms)
+ if(ms == 255) ms = 500; // If 255, delay for 500 ms
+// Initialization code for QDTech displays
+void ICACHE_FLASH_ATTR QD_commonInit(const uint8_t *cmdList) {
+ colstart = rowstart = 0; // May be overridden in init func
+ easygpio_pinMode(_rs, EASYGPIO_PULLUP, EASYGPIO_OUTPUT);
+ easygpio_pinMode(_cs, EASYGPIO_PULLUP, EASYGPIO_OUTPUT);
+ easygpio_pinMode(_sclk, EASYGPIO_PULLUP, EASYGPIO_OUTPUT);
+ easygpio_pinMode(_sid, EASYGPIO_PULLUP, EASYGPIO_OUTPUT);
+ easygpio_outputSet(_sclk,0);
+ easygpio_outputSet(_sid,0);
+ // toggle RST low to reset; CS low so it'll listen to us
+ easygpio_outputSet(_cs,0);
+ easygpio_pinMode(_rst, EASYGPIO_PULLUP, EASYGPIO_OUTPUT);
+ easygpio_outputSet(_rst,1);
+ easygpio_outputSet(_rst,0);
+ easygpio_outputSet(_rst,1);
+ if(cmdList) QD_commandList(cmdList);
+void ICACHE_FLASH_ATTR QD_setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1,
+ QD_writecommand(QDTech_CASET); // Column addr set
+ QD_writedata(x0+colstart); // XSTART
+ QD_writedata(x1+colstart); // XEND
+ QD_writecommand(QDTech_RASET); // Row addr set
+ QD_writedata(y0+rowstart); // YSTART
+ QD_writedata(y1+rowstart); // YEND
+ QD_writecommand(QDTech_RAMWR); // write to RAM
+void ICACHE_FLASH_ATTR QD_pushColor(uint16_t color) {
+ easygpio_outputSet(_rs,1);
+ easygpio_outputSet(_cs,0);
+ QD_spiwrite(color >> 8);
+ easygpio_outputSet(_cs,1);
+void QD_drawPixel(int16_t x, int16_t y, uint16_t color) {
+ if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
+ QD_setAddrWindow(x,y,x+1,y+1);
+ easygpio_outputSet(_rs,1);
+ easygpio_outputSet(_cs,0);
+ QD_spiwrite(color >> 8);
+ easygpio_outputSet(_cs,1);
+void ICACHE_FLASH_ATTR QD_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;
+ QD_setAddrWindow(x, y, x, y+h-1);
+ uint8_t hi = color >> 8, lo = color;
+ easygpio_outputSet(_rs,1);
+ easygpio_outputSet(_cs,0);
+ easygpio_outputSet(_cs,1);
+void ICACHE_FLASH_ATTR QD_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;
+ QD_setAddrWindow(x, y, x+w-1, y);
+ uint8_t hi = color >> 8, lo = color;
+ easygpio_outputSet(_rs,1);
+ easygpio_outputSet(_cs,0);
+ easygpio_outputSet(_cs,1);
+void ICACHE_FLASH_ATTR QD_fillScreen(uint16_t color) {
+ QD_fillRect(0, 0, _width, _height, color);
+void ICACHE_FLASH_ATTR QD_fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
+ // 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;
+ QD_setAddrWindow(x, y, x+w-1, y+h-1);
+ uint8_t hi = color >> 8, lo = color;
+ easygpio_outputSet(_rs,1);
+ easygpio_outputSet(_cs,0);
+ easygpio_outputSet(_cs,1);
+// Pass 8-bit (each) R,G,B, get back 16-bit packed color
+uint16_t QD_Color565(uint8_t r, uint8_t g, uint8_t b) {
+ return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
+void ICACHE_FLASH_ATTR QD_setRotation(uint8_t m) {
+// Generally 0 - Portrait 1 - Landscape
+ QD_writecommand(QDTech_MADCTL);
+ rotation = m % 4; // can't be higher than 3
+ QD_writedata(MADCTL_MX | MADCTL_MY | MADCTL_BGR);
+ _width = QDTech_TFTWIDTH;
+ _height = QDTech_TFTHEIGHT;
+ QD_writedata(MADCTL_MY | MADCTL_MV | MADCTL_BGR);
+ _width = QDTech_TFTHEIGHT;
+ _height = QDTech_TFTWIDTH;
+ QD_writedata(MADCTL_BGR);
+ _width = QDTech_TFTWIDTH;
+ _height = QDTech_TFTHEIGHT;
+// writedata(MADCTL_MX | MADCTL_MV | MADCTL_RGB);
+ QD_writedata(MADCTL_MX | MADCTL_MV | MADCTL_BGR);
+ _width = QDTech_TFTHEIGHT;
+ _height = QDTech_TFTWIDTH;
+void ICACHE_FLASH_ATTR QD_invertDisplay(uint8_t i) {
+ QD_writecommand(i ? QDTech_INVON : QDTech_INVOFF);