// // ST7735S on ESP-WROOM-02 // Sep.7, 2017 // xkozima@tohoku.ac.jp #include "esp_ST7735.h" // pins are for EPS-WROOM-02 #define CS 15 // as a master #define DC 16 // A0 (H:data, L:command) #define MOSI 13 // MISO is not used #define SCK 14 #define swap(a,b) {int t; t=a; a=b; b=t;} unsigned char Dummy[256]; // SPI 初期化 void SPIinit() { pinMode(CS, OUTPUT); digitalWrite(CS, HIGH); pinMode(DC, OUTPUT); digitalWrite(DC, LOW); SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); SPI.setFrequency(15000000ULL); // 15MHz } // SPI からコマンド送信(1バイト) void SPIsendComm1(unsigned char cmdOne) { digitalWrite(CS, LOW); digitalWrite(DC, LOW); SPI.write(cmdOne); digitalWrite(CS, HIGH); } // SPI からコマンド送信(複数バイト) void SPIsendCommN(unsigned char *cmd, int length) { digitalWrite(CS, LOW); digitalWrite(DC, LOW); // command SPI.write(cmd[0]); // parameters (data) digitalWrite(DC, HIGH); for (int i = 1; i < length; i++) { SPI.write(cmd[i]); } digitalWrite(CS, HIGH); } // SPI からデータ送信(複数バイト) void SPIsendDataN(unsigned char *data, int length) { digitalWrite(CS, LOW); digitalWrite(DC, HIGH); SPI.writeBytes(data, length); digitalWrite(CS, HIGH); } // SPI からコマンド送信(複数バイト) void SPIsendCommN2(unsigned char *cmd, int length) { SPIsendComm1(cmd[0]); SPIsendDataN(cmd + 1, length - 1); } // 同じピクセルデータ(color)を複数回送信 #define BLOCK_SIZE_C 128 void LCDsendColorN(int color, int length) { digitalWrite(CS, LOW); digitalWrite(DC, HIGH); unsigned char hi = color >> 8, lo = color & 0xff; unsigned char data[BLOCK_SIZE_C * 2]; for (int i = 0; i < BLOCK_SIZE_C; i++) { data[i * 2] = hi; data[i * 2 + 1] = lo; } int iter = length / BLOCK_SIZE_C; int rest = length % BLOCK_SIZE_C; for (int i = 0; i < iter; i++) { SPI.writeBytes(data, BLOCK_SIZE_C * 2); } SPI.writeBytes(data, rest * 2); digitalWrite(CS, HIGH); } // 初期化 void LCDinit() { // init SPI SPIinit(); delay(20); // init command // RESET: reset (and 120ms) SPIsendComm1(0x01); delay(120); // SLPOUT: sleep out (and 120ms) SPIsendComm1(0x11); delay(120); // framerate (let it be as default) // power (let it be as default) // MADCTL: memory access direction (upsidedown/RGB) unsigned char cmdMA[] = {0x36, 0xc0}; SPIsendCommN(cmdMA, 2); // COLMOD: pixel color format (RGB565) unsigned char cmdCM[] = {0x3a, 0x05}; SPIsendCommN(cmdCM, 2); // CASET: column address (0..128) unsigned char cmdCA[] = {0x2a, 0x00, 0x00, 0x00, 0x7f}; SPIsendCommN(cmdCA, 5); // RASET: row address (0..128) unsigned char cmdRA[] = {0x2b, 0x00, 0x00, 0x00, 0x7f}; SPIsendCommN(cmdRA, 5); // NORON: normal display on SPIsendComm1(0x13); delay(10); // DISPON: display on SPIsendComm1(0x29); delay(100); // clear and display on LCDclear(0); } // 16bit(RGB565) 色情報を 24bit 色情報から生成 int LCDcolor(int r, int g, int b) { return ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); } // LCD BIOS #define COLSTART 2 #define ROWSTART 3 // (1:upright, 3:upsidedown) void LCDsetWindow(int x1, int y1, int x2, int y2) { // set window (CASET, RASET) unsigned char cmdCA[] = {0x2a, 0x00, x1+COLSTART, 0x00, x2+COLSTART}; SPIsendCommN(cmdCA, 5); unsigned char cmdRA[] = {0x2b, 0x00, y1+ROWSTART, 0x00, y2+ROWSTART}; SPIsendCommN(cmdRA, 5); // get ready to send pixel data (RAMWR) SPIsendComm1(0x2c); } // 点を描画 void LCDpoint(int x, int y, int color) { // check if (x & 0xff80 || y & 0xff80) return; // draw LCDsetWindow(x, y, x, y); LCDsendColorN(color, 1); } // 長方形を描画((fill)? 塗りつぶし: 輪郭のみ) void LCDrect(int x, int y, int w, int h, int color, int fill) { // check if (x < 0) x = 0; if (y < 0) y = 0; if (x >= 128) x = 127; if (y >= 128) y = 127; if (x + w > 128) w = 128 - x; if (y + h > 128) h = 128 - y; // draw if (fill) { LCDsetWindow(x, y, x+w-1, y+h-1); LCDsendColorN(color, w*h); } else { LCDline(x, y, x+w-1, y, color); LCDline(x, y, x, y+h-1, color); LCDline(x, y+h-1, x+w-1, y+h-1, color); LCDline(x+w-1, y, x+w-1, y+h-1, color); } } // 線を描画 void LCDline(int x1, int y1, int x2, int y2, int color) { if (x1 == x2) { // fast vline // check if (x1 < 0) x1 = 0; if (x1 >= 128) x1 = 127; if (y1 < 0) y1 = 0; if (y2 >= 128) y2 = 127; // draw if (y1 > y2) swap(y1, y2); LCDsetWindow(x1, y1, x1, y2); LCDsendColorN(color, y2-y1+1); } else if (y1 == y2) { // fast hline // check if (x1 < 0) x1 = 0; if (x1 >= 128) x1 = 127; if (x2 < 0) x2 = 0; if (x2 >= 128) x2 = 127; if (y1 < 0) y1 = 0; if (y1 >= 128) y1 = 127; // draw if (x1 > x2) swap(x1, x2); LCDsetWindow(x1, y1, x2, y1); LCDsendColorN(color, x2-x1+1); } else { // slanted line // draw if (abs(y2 - y1) > abs(x2 - x1)) { swap(x1, y1); swap(x2, y2); } if (x1 > x2) { swap(x1, x2); swap(y1, y2); } int dx = x2 - x1; int dy = abs(y2 - y1); int err = dx / 2; int ystep = (y1 < y2)? 1: -1; int y = y1; for (int x = x1; x <= x2; x++) { if (abs(y2 - y1) > abs(x2 - x1)) { LCDpoint(y, x, color); } else { LCDpoint(x, y, color); } err -= dy; if (err < 0) { y += ystep; err += dx; } } } } // 円を描画((fill)? 塗りつぶし: 輪郭のみ) void LCDcircle(int x, int y, int r, int color, int fill) { if (r <= 0) return; int xx = r, yy = 0, err = 1 - xx; // iteration while (yy <= xx) { // draw it! if (fill) { LCDline(x + xx, y + yy, x - xx, y + yy, color); LCDline(x + yy, y + xx, x - yy, y + xx, color); LCDline(x - xx, y - yy, x + xx, y - yy, color); LCDline(x - yy, y - xx, x + yy, y - xx, color); } else { LCDpoint(x + xx, y + yy, color); LCDpoint(x + yy, y + xx, color); LCDpoint(x - xx, y + yy, color); LCDpoint(x - yy, y + xx, color); LCDpoint(x - xx, y - yy, color); LCDpoint(x - yy, y - xx, color); LCDpoint(x + xx, y - yy, color); LCDpoint(x + yy, y - xx, color); } // walk yy++; if (err <= 0) { err += 1 + 2 * yy; } else { xx--; err += 2 * (yy - xx) + 1; } } } // 楕円を描画(rx/ry: 半径,(fill)? 塗りつぶし: 輪郭のみ) void LCDellipse(int x, int y, int a, int b, int color, int fill) { // cf. http://enchantia.com/graphapp/doc/tech/ellipses.html int xx = 0, yy = b; long a2 = (long)a*a, b2 = (long)b*b; long crit1 = -(a2/4 + a%2 + b2); long crit2 = -(b2/4 + b%2 + a2); long crit3 = -(b2/4 + b%2); long t = -a2*yy; long dxt = 2*b2*xx, dyt = -2*a2*yy; long d2xt = 2*b2, d2yt = 2*a2; // walk and draw while (yy >= 0 && xx <= a) { // draw if (fill) { if (a2*yy <= b2*xx) { LCDline(x-xx, y+yy, x+xx, y+yy, color); LCDline(x-xx, y-yy, x+xx, y-yy, color); } else { LCDline(x+xx, y-yy, x+xx, y+yy, color); LCDline(x-xx, y-yy, x-xx, y+yy, color); } } else { LCDpoint(x+xx, y+yy, color); LCDpoint(x-xx, y-yy, color); LCDpoint(x+xx, y-yy, color); LCDpoint(x-xx, y+yy, color); } // walk if (t + b2*xx <= crit1 || t + a2*yy <= crit3) { xx++, dxt += d2xt, t += dxt; } else if (t - a2*yy > crit2) { yy--, dyt += d2yt, t += dyt; } else { xx++, dxt += d2xt, t += dxt; yy--, dyt += d2yt, t += dyt; } } } // 画面クリア(0: 黒,0xffff: 白, etc.) void LCDclear(int color) { LCDrect(0, 0, 128, 128, color, 1); } // 画像を描画(16bit(RGB565) or 24bit) void LCDimage(int x, int y, int w, int h, int *image16) { // setup the region to fill LCDsetWindow(x, y, x+w-1, y+h-1); // send data SPIsendDataN((unsigned char *) image16, w*h*2); } void LCDimage(int x, int y, int w, int h, const int *image16) { LCDimage(x, y, w, h, (int *) image16); } void LCDimage(int x, int y, int w, int h, unsigned char *image24) { // setup the region to fill LCDsetWindow(x, y, x+w-1, y+h-1); // send data for (int j = 0; j < h; j++) { unsigned char line[256]; for (int i = 0; i < w; i++) { unsigned char r, g, b; b = *image24++; g = *image24++; r = *image24++; int color = LCDcolor(r, g, b); line[i*2] = color >> 8; line[i*2+1] = color & 0xff; } SPIsendDataN(line, w*2); } } void LCDimage(int x, int y, int w, int h, const unsigned char *image24) { LCDimage(x, y, w, h, (unsigned char *) image24); } // ASCII 文字列を描画 void LCDtext(int x, int y, char *string, int color) { int len = strlen(string); for (int i = 0; i < len; i++) { int xx = x + i * 6; unsigned char code = string[i]; if (code < 0x20 || code >= 0x80) continue; //unsigned char *font = font6x8 + ((code - 0x20) * 6); for (int fx = 0; fx < 6; fx++) { if (xx + fx > 127) break; unsigned char line = (unsigned char) *(font6x8 + ((code - 0x20) * 6) + fx); //unsigned char line = *(font + fx); for (int fy = 0, bit = 0x01; fy < 8; fy++, bit <<= 1) { if (line & bit) LCDpoint(xx + fx, y + fy, color); } } } } // ASCII 文字列を描画(背景色も指定) void LCDtext(int x, int y, char *string, int colorF, int colorB) { // clear the background int w = strlen(string) * 6; if (x + w > 127) w = 127 - x; LCDrect(x, y, w, 8, colorB, 1); // overwrite the text LCDtext(x, y, string, colorF); }