TinyGPU
Loading...
Searching...
No Matches
DisplayDriverParallel8.h
Go to the documentation of this file.
1#pragma once
2#include <initializer_list>
3#include <stdint.h>
4#include <string.h>
5
6#include "TinyGPU/Drivers/DisplayDriver.h"
7#include "TinyGPU/Emulation.h"
8
9namespace tinygpu {
10
11/**
12 * @brief Common base class for 8-bit parallel ("Intel 8080"-style) TFT
13 * display drivers: 8 data lines (D0-D7), WR (write strobe), RD (read
14 * strobe, unused - this class only writes), RS/DC (command vs. data) and
15 * CS. This is the bus MCUFRIEND-style shields and many 40-pin parallel
16 * TFT breakout boards use, wired straight to 8 GPIOs rather than through
17 * SPI/QSPI - no dedicated bus peripheral is assumed, every data line and
18 * the WR strobe is bit-banged via digitalWrite(), the same portable
19 * approach TinyGPU/Input/TouchDriverArduino.h's TouchDriverBitBang uses
20 * for a resistive touch panel's four GPIO pins. This trades throughput
21 * (one digitalWrite() per bit, per byte) for working unmodified on any
22 * Arduino core - a hardware-accelerated 8080 driver (e.g. ESP32's LCD_CAM/
23 * esp_lcd_panel_io_i80) would be faster but ties the implementation to one
24 * platform's peripheral, the same tradeoff DisplayDriverQSPI.h already
25 * makes explicitly for ESP32-only QSPI.
26 *
27 * The command/parameter protocol on the wire (0x2A/0x2B/0x2C column/row/
28 * RAM-write, 0x36 MADCTL, 0x3A pixel format, ...) is identical to the SPI
29 * wiring of the same controller families (see DisplayDriverSPI.h) - only
30 * how each command/data byte reaches the panel differs, so concrete
31 * drivers here mirror DisplayDriverSPI.h's ILI9341Driver/ST7789Driver/...
32 * init sequences byte-for-byte.
33 */
34template <typename RGB_T = RGB565>
36 public:
37 /// @param d0..d7 the 8 data lines, D0 = least significant bit.
38 /// @param wr write-strobe pin: data is latched by the panel on WR's
39 /// rising edge.
40 /// @param dc data/command ("RS") select pin: LOW selects command, HIGH
41 /// selects data - same polarity/role as DisplayDriverSPI's dc pin.
42 /// @param cs chip-select pin, or -1 if the panel has CS permanently
43 /// tied low (common on single-panel parallel shields).
44 /// @param rd read-strobe pin, or -1 if unused - this class never reads
45 /// from the panel, so it only needs to hold RD in its idle (HIGH,
46 /// inactive) state so the panel doesn't drive the (shared, bidirectional
47 /// on some boards) data bus back.
48 /// @param rst reset pin, or -1 if not wired up (e.g. tied to the MCU's
49 /// own reset).
50 /// @param width/height the panel's addressable resolution, as reported
51 /// by width()/height() - subclasses with a rotation concept (e.g.
52 /// ILI9341Driver8080) override width()/height() themselves instead and
53 /// can ignore these.
54 DisplayDriverParallel8(int8_t d0, int8_t d1, int8_t d2, int8_t d3,
55 int8_t d4, int8_t d5, int8_t d6, int8_t d7,
56 int8_t wr, int8_t dc, int8_t cs = -1,
57 int8_t rd = -1, int8_t rst = -1, size_t xOffset = 0,
58 size_t yOffset = 0, size_t width = 240,
59 size_t height = 320)
60 : d_{d0, d1, d2, d3, d4, d5, d6, d7},
61 wr_(wr),
62 dc_(dc),
63 cs_(cs),
64 rd_(rd),
65 rst_(rst),
69 height_(height) {}
70
71 size_t width() const override { return width_; }
72 size_t height() const override { return height_; }
73
74 bool writeData(ISurface<RGB_T>& surface) override {
75 return writeData(surface, 0, 0);
76 }
77
78 bool writeData(ISurface<RGB_T>& surface, size_t x, size_t y) override {
79 static_assert(sizeof(RGB_T) == 2,
80 "writeData assumes a 16bpp RGB_T (RGB565) stored in "
81 "wire byte order");
82 setAddressWindow(x, y, surface.width(), surface.height());
83 beginTransaction();
84 digitalWrite(dc_, HIGH);
85 const uint8_t* src = surface.data();
86 const size_t n = surface.size();
87 for (size_t i = 0; i < n; ++i) {
88 writeByte(src[i]);
89 }
90 endTransaction();
91 return true;
92 }
93
94 protected:
95 int8_t d_[8];
96 int8_t wr_, dc_, cs_, rd_, rst_;
99
100 void setColumnRowAddress(size_t x, size_t y, size_t w, size_t h) {
101 writeCommand(0x2A);
102 writeData16(x + xOffset_, x + xOffset_ + w - 1);
103 writeCommand(0x2B);
104 writeData16(y + yOffset_, y + yOffset_ + h - 1);
105 }
106
107 bool setAddressWindow(size_t x, size_t y, size_t w, size_t h) override {
108 setColumnRowAddress(x, y, w, h);
109 writeCommand(0x2C); // RAMWR
110 return true;
111 }
112
114 for (int8_t pin : d_) {
115 pinMode(pin, OUTPUT);
116 }
117 pinMode(wr_, OUTPUT);
118 digitalWrite(wr_, HIGH);
119 pinMode(dc_, OUTPUT);
120 if (cs_ >= 0) {
121 pinMode(cs_, OUTPUT);
122 digitalWrite(cs_, HIGH);
123 }
124 if (rd_ >= 0) {
125 pinMode(rd_, OUTPUT);
126 digitalWrite(rd_, HIGH); // idle/inactive - this class never reads
127 }
128 if (rst_ >= 0) {
129 pinMode(rst_, OUTPUT);
130 digitalWrite(rst_, LOW);
131 delay(20);
132 digitalWrite(rst_, HIGH);
133 delay(150);
134 }
135 }
136
137 void writeCommand(uint8_t cmd) {
138 beginTransaction();
139 digitalWrite(dc_, LOW);
140 writeByte(cmd);
141 endTransaction();
142 }
143
144 void writeData16(uint16_t d1, uint16_t d2) {
145 beginTransaction();
146 digitalWrite(dc_, HIGH);
147 writeByte(d1 >> 8);
148 writeByte(d1 & 0xFF);
149 writeByte(d2 >> 8);
150 writeByte(d2 & 0xFF);
151 endTransaction();
152 }
153
154 void writeData8(uint8_t data) {
155 beginTransaction();
156 digitalWrite(dc_, HIGH);
157 writeByte(data);
158 endTransaction();
159 }
160
161 /// Writes each byte as a separate writeData8() call - a convenience for
162 /// sending a command's multi-byte parameter list during init sequences,
163 /// matching DisplayDriverSPI::writeDataN().
164 void writeDataN(std::initializer_list<uint8_t> bytes) {
165 for (uint8_t b : bytes) {
166 writeData8(b);
167 }
168 }
169
170 private:
171 void beginTransaction() {
172 if (cs_ >= 0) digitalWrite(cs_, LOW);
173 }
174
175 void endTransaction() {
176 if (cs_ >= 0) digitalWrite(cs_, HIGH);
177 }
178
179 /// Drives one byte onto D0-D7 and pulses WR - the panel latches the bus
180 /// on WR's rising edge (LOW then HIGH).
181 void writeByte(uint8_t data) {
182 for (uint8_t i = 0; i < 8; ++i) {
183 digitalWrite(d_[i], (data >> i) & 0x01);
184 }
185 digitalWrite(wr_, LOW);
186 digitalWrite(wr_, HIGH);
187 }
188};
189
190/**
191 * @brief Driver for ST7735 8-bit parallel display controller.
192 */
193template <typename RGB_T = RGB565>
195 public:
196 using DisplayDriverParallel8<RGB_T>::setupPinsAndReset;
197 using DisplayDriverParallel8<RGB_T>::writeCommand;
198 using DisplayDriverParallel8<RGB_T>::writeData8;
199
200 ST7735Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4,
201 int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc,
202 int8_t cs = -1, int8_t rd = -1, int8_t rst = -1,
203 size_t width = 128, size_t height = 160)
205 cs, rd, rst, 2, 1, width, height) {}
206
207 bool begin() override {
208 setupPinsAndReset();
209 writeCommand(0x01);
210 delay(150);
211 writeCommand(0x11);
212 delay(120);
213 writeCommand(0x3A);
214 writeData8(0x05);
215 writeCommand(0x29);
216 return true;
217 }
218};
219
220/**
221 * @brief Driver for ST7789 8-bit parallel display controller.
222 */
223template <typename RGB_T = RGB565>
225 public:
226 using DisplayDriverParallel8<RGB_T>::setupPinsAndReset;
227 using DisplayDriverParallel8<RGB_T>::writeCommand;
228 using DisplayDriverParallel8<RGB_T>::writeData8;
229
230 ST7789Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4,
231 int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc,
232 int8_t cs = -1, int8_t rd = -1, int8_t rst = -1,
233 size_t width = 240, size_t height = 320)
235 cs, rd, rst, 0, 0, width, height) {}
236
237 bool begin() override {
238 setupPinsAndReset();
239 writeCommand(0x01);
240 delay(150);
241 writeCommand(0x11);
242 delay(120);
243 writeCommand(0x3A);
244 writeData8(0x55);
245 writeCommand(0x29);
246 return true;
247 }
248};
249
250/**
251 * @brief Driver for ILI9341 8-bit parallel display controller.
252 *
253 * Same power/gamma/MADCTL init sequence as DisplayDriverSPI.h's
254 * ILI9341Driver (see that class's doc comment for provenance) - only the
255 * bus underneath differs.
256 */
257template <typename RGB_T = RGB565>
259 public:
260 using DisplayDriverParallel8<RGB_T>::setupPinsAndReset;
261 using DisplayDriverParallel8<RGB_T>::writeCommand;
262 using DisplayDriverParallel8<RGB_T>::writeData8;
263 using DisplayDriverParallel8<RGB_T>::writeDataN;
264
265 using Rotation = tinygpu::DisplayRotation;
266
267 /// @param nativeWidth/nativeHeight the panel's physical resolution in
268 /// its native (portrait, MV bit clear) orientation - 240x320 is the
269 /// common ILI9341 module size and the default; pass your panel's real
270 /// values if it differs.
271 ILI9341Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4,
272 int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc,
273 int8_t cs = -1, int8_t rd = -1, int8_t rst = -1,
274 Rotation rotation = Rotation::kNone,
275 size_t nativeWidth = 240, size_t nativeHeight = 320)
276 : DisplayDriverParallel8<RGB_T>(d0, d1, d2, d3, d4, d5, d6, d7, wr, dc,
277 cs, rd, rst, 0, 0),
278 rotation_(rotation),
281
282 size_t width() const override {
283 return isLandscapeFamily(rotation_) ? nativeHeight_ : nativeWidth_;
284 }
285 size_t height() const override {
286 return isLandscapeFamily(rotation_) ? nativeWidth_ : nativeHeight_;
287 }
288
289 bool begin() override {
290 setupPinsAndReset();
291
292 writeCommand(0x01); // SWRESET
293 delay(150);
294
295 writeCommand(0xEF);
296 writeDataN({0x03, 0x80, 0x02});
297
298 writeCommand(0xCF);
299 writeDataN({0x00, 0xC1, 0x30});
300
301 writeCommand(0xED);
302 writeDataN({0x64, 0x03, 0x12, 0x81});
303
304 writeCommand(0xE8);
305 writeDataN({0x85, 0x00, 0x78});
306
307 writeCommand(0xCB);
308 writeDataN({0x39, 0x2C, 0x00, 0x34, 0x02});
309
310 writeCommand(0xF7);
311 writeDataN({0x20});
312
313 writeCommand(0xEA);
314 writeDataN({0x00, 0x00});
315
316 writeCommand(0xC0);
317 writeDataN({0x23});
318
319 writeCommand(0xC1);
320 writeDataN({0x10});
321
322 writeCommand(0xC5);
323 writeDataN({0x3E, 0x28});
324
325 writeCommand(0xC7);
326 writeDataN({0x86});
327
328 writeCommand(0x36); // MADCTL
329 writeDataN({madctlForRotation(rotation_)});
330
331 writeCommand(0x3A); // Pixel format: 16bpp
332 writeDataN({0x55});
333
334 writeCommand(0xB1);
335 writeDataN({0x00, 0x13});
336
337 writeCommand(0xB6);
338 writeDataN({0x08, 0x82, 0x27});
339
340 writeCommand(0xF2);
341 writeDataN({0x00});
342
343 writeCommand(0x26);
344 writeDataN({0x01});
345
346 writeCommand(0xE0);
347 writeDataN({0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07,
348 0x10, 0x03, 0x0E, 0x09, 0x00});
349
350 writeCommand(0xE1);
351 writeDataN({0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08,
352 0x0F, 0x0C, 0x31, 0x36, 0x0F});
353
354 writeCommand(0x11); // Sleep out
355 delay(120);
356 writeCommand(0x29); // Display on
357
358 writeCommand(invertColor_ ? 0x21 : 0x20);
359
360 return true;
361 }
362
363 void setRotation(Rotation rotation) override {
364 if (rotation == Rotation::kNone) return;
365 rotation_ = rotation;
366 writeCommand(0x36);
367 writeDataN({madctlForRotation(rotation_)});
368 }
369
370 Rotation rotation() const { return rotation_; }
371
372 /// See DisplayDriverSPI.h's ILI9341Driver::setInvertColor() - same
373 /// panel quirk, same fix, just re-sent over this bus's begin() instead.
374 void setInvertColor(bool invert) {
375 invertColor_ = invert;
376 writeCommand(invert ? 0x21 : 0x20);
377 }
378
379 protected:
380 Rotation rotation_;
382 bool invertColor_ = false;
383
384 static uint8_t madctlForRotation(Rotation rotation) {
385 switch (rotation) {
386 case Rotation::kLandscape:
387 return 0x28;
388 case Rotation::kPortraitFlipped:
389 return 0x88;
390 case Rotation::kLandscapeFlipped:
391 return 0xE8;
392 case Rotation::kNone:
393 case Rotation::kPortrait:
394 default:
395 return 0x48;
396 }
397 }
398};
399
400/**
401 * @brief Driver for HX8357 8-bit parallel display controller.
402 */
403template <typename RGB_T = RGB565>
405 public:
406 using DisplayDriverParallel8<RGB_T>::setupPinsAndReset;
407 using DisplayDriverParallel8<RGB_T>::writeCommand;
408 using DisplayDriverParallel8<RGB_T>::writeData8;
409
410 HX8357Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4,
411 int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc,
412 int8_t cs = -1, int8_t rd = -1, int8_t rst = -1,
413 size_t width = 320, size_t height = 480)
415 cs, rd, rst, 0, 0, width, height) {}
416
417 bool begin() override {
418 setupPinsAndReset();
419 writeCommand(0x01);
420 delay(150);
421 writeCommand(0x11);
422 delay(120);
423 writeCommand(0x3A);
424 writeData8(0x55);
425 writeCommand(0x29);
426 return true;
427 }
428};
429
430/**
431 * @brief Driver for ST7796 8-bit parallel display controller.
432 */
433template <typename RGB_T = RGB565>
435 public:
436 using DisplayDriverParallel8<RGB_T>::setupPinsAndReset;
437 using DisplayDriverParallel8<RGB_T>::writeCommand;
438 using DisplayDriverParallel8<RGB_T>::writeData8;
439
440 ST7796Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4,
441 int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc,
442 int8_t cs = -1, int8_t rd = -1, int8_t rst = -1,
443 size_t width = 320, size_t height = 480)
445 cs, rd, rst, 0, 0, width, height) {}
446
447 bool begin() override {
448 setupPinsAndReset();
449 writeCommand(0x01);
450 delay(150);
451 writeCommand(0x11);
452 delay(120);
453 writeCommand(0x3A);
454 writeData8(0x55);
455 writeCommand(0x36);
456 writeData8(0x48);
457 writeCommand(0x29);
458 return true;
459 }
460};
461
462} // namespace tinygpu
Common base class for 8-bit parallel ("Intel 8080"-style) TFT display drivers: 8 data lines (D0-D7),...
Definition: DisplayDriverParallel8.h:35
int8_t rd_
Definition: DisplayDriverParallel8.h:96
int8_t wr_
Definition: DisplayDriverParallel8.h:96
int8_t dc_
Definition: DisplayDriverParallel8.h:96
size_t xOffset_
Definition: DisplayDriverParallel8.h:97
size_t yOffset_
Definition: DisplayDriverParallel8.h:97
size_t width_
Definition: DisplayDriverParallel8.h:98
void writeDataN(std::initializer_list< uint8_t > bytes)
Definition: DisplayDriverParallel8.h:164
size_t height_
Definition: DisplayDriverParallel8.h:98
int8_t d_[8]
Definition: DisplayDriverParallel8.h:95
size_t height() const override
Definition: DisplayDriverParallel8.h:72
void setColumnRowAddress(size_t x, size_t y, size_t w, size_t h)
Definition: DisplayDriverParallel8.h:100
int8_t cs_
Definition: DisplayDriverParallel8.h:96
int8_t rst_
Definition: DisplayDriverParallel8.h:96
void setupPinsAndReset()
Definition: DisplayDriverParallel8.h:113
void writeCommand(uint8_t cmd)
Definition: DisplayDriverParallel8.h:137
bool writeData(ISurface< RGB_T > &surface, size_t x, size_t y) override
Definition: DisplayDriverParallel8.h:78
size_t width() const override
Definition: DisplayDriverParallel8.h:71
bool setAddressWindow(size_t x, size_t y, size_t w, size_t h) override
Definition: DisplayDriverParallel8.h:107
void writeData8(uint8_t data)
Definition: DisplayDriverParallel8.h:154
DisplayDriverParallel8(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc, int8_t cs=-1, int8_t rd=-1, int8_t rst=-1, size_t xOffset=0, size_t yOffset=0, size_t width=240, size_t height=320)
Definition: DisplayDriverParallel8.h:54
bool writeData(ISurface< RGB_T > &surface) override
Definition: DisplayDriverParallel8.h:74
void writeData16(uint16_t d1, uint16_t d2)
Definition: DisplayDriverParallel8.h:144
Definition: DisplayDriver.h:49
Driver for HX8357 8-bit parallel display controller.
Definition: DisplayDriverParallel8.h:404
HX8357Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc, int8_t cs=-1, int8_t rd=-1, int8_t rst=-1, size_t width=320, size_t height=480)
Definition: DisplayDriverParallel8.h:410
bool begin() override
Definition: DisplayDriverParallel8.h:417
Driver for ILI9341 8-bit parallel display controller.
Definition: DisplayDriverParallel8.h:258
static uint8_t madctlForRotation(Rotation rotation)
Definition: DisplayDriverParallel8.h:384
size_t nativeHeight_
Definition: DisplayDriverParallel8.h:381
size_t nativeWidth_
Definition: DisplayDriverParallel8.h:381
void setInvertColor(bool invert)
Definition: DisplayDriverParallel8.h:374
size_t height() const override
Definition: DisplayDriverParallel8.h:285
size_t width() const override
Definition: DisplayDriverParallel8.h:282
Rotation rotation() const
Definition: DisplayDriverParallel8.h:370
bool invertColor_
Definition: DisplayDriverParallel8.h:382
bool begin() override
Definition: DisplayDriverParallel8.h:289
ILI9341Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc, int8_t cs=-1, int8_t rd=-1, int8_t rst=-1, Rotation rotation=Rotation::kNone, size_t nativeWidth=240, size_t nativeHeight=320)
Definition: DisplayDriverParallel8.h:271
void setRotation(Rotation rotation) override
Definition: DisplayDriverParallel8.h:363
Rotation rotation_
Definition: DisplayDriverParallel8.h:380
RGB color stored in 16-bit RGB565 format, byte-swapped from the conventional bit layout.
Definition: RGB565.h:24
Driver for ST7735 8-bit parallel display controller.
Definition: DisplayDriverParallel8.h:194
ST7735Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc, int8_t cs=-1, int8_t rd=-1, int8_t rst=-1, size_t width=128, size_t height=160)
Definition: DisplayDriverParallel8.h:200
bool begin() override
Definition: DisplayDriverParallel8.h:207
Driver for ST7789 8-bit parallel display controller.
Definition: DisplayDriverParallel8.h:224
ST7789Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc, int8_t cs=-1, int8_t rd=-1, int8_t rst=-1, size_t width=240, size_t height=320)
Definition: DisplayDriverParallel8.h:230
bool begin() override
Definition: DisplayDriverParallel8.h:237
Driver for ST7796 8-bit parallel display controller.
Definition: DisplayDriverParallel8.h:434
ST7796Driver8080(int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t d6, int8_t d7, int8_t wr, int8_t dc, int8_t cs=-1, int8_t rd=-1, int8_t rst=-1, size_t width=320, size_t height=480)
Definition: DisplayDriverParallel8.h:440
bool begin() override
Definition: DisplayDriverParallel8.h:447
Definition: DSIBusESP32.h:19
void delay(unsigned long ms)
Definition: EmulationDesktop.h:52
DisplayRotation
Abstract base class for display drivers.
Definition: DisplayDriver.h:28