AberLED shield library
Library for the bicolor LED (and TFT screen) shield used in CS12020
TFT_ST7735.cpp
Go to the documentation of this file.
1 /***************************************************
2  Arduino TFT graphics library targetted at the UNO
3  and Mega boards.
4 
5  This library has been derived from the Adafruit_GFX
6  library and the associated driver library. See text
7  at the end of this file.
8 
9  This is a standalone library that contains the
10  hardware driver, the graphics funtions and the
11  proportional fonts.
12 
13  The larger fonts are Run Length Encoded to reduce their
14  size.
15 
16  ****************************************************/
17 
18 #include "TFT_ST7735.h"
19 
20 #include <avr/pgmspace.h>
21 #include <limits.h>
22 #include "pins_arduino.h"
23 #include "wiring_private.h"
24 #include <SPI.h>
25 
26 inline void spiWait17(void) __attribute__((always_inline));
27 inline void spiWait15(void) __attribute__((always_inline));
28 inline void spiWait14(void) __attribute__((always_inline));
29 inline void spiWait12(void) __attribute__((always_inline));
30 inline void spiWrite16(uint16_t data, int16_t count) __attribute__((always_inline));
31 inline void spiWrite16s(uint16_t data) __attribute__((always_inline));
32 inline void spiWrite16R(uint16_t data, int16_t count) __attribute__((always_inline));
33 
34 /***************************************************************************************
35 ** Function name: TFT_ST7735
36 ** Description: Constructor , we must use hardware SPI pins
37 ***************************************************************************************/
38 TFT_ST7735::TFT_ST7735(int16_t w, int16_t h)
39 {
40  _cs = TFT_CS;
41  _dc = TFT_DC;
42  _rst = TFT_RST;
43  _mosi = _sclk = 0;
44 
45  if (_rst > 0) {
46  digitalWrite(_rst, LOW);
47  pinMode(_rst, OUTPUT);
48  }
49 
50  TFT_DC_D;
51  pinMode(_dc, OUTPUT);
52 
53  TFT_CS_H;
54  pinMode(_cs, OUTPUT);
55 
56  _width = w;
57  _height = h;
58  rotation = 0;
59  cursor_y = cursor_x = 0;
60  textfont = 1;
61  textsize = 1;
62  textcolor = 0xFFFF;
63  textbgcolor = 0x0000;
64  padX = 0;
65  textwrap = true;
66  textdatum = 0; // Left text alignment is default
67  fontsloaded = 0;
68 
69  addr_row = 0xFF;
70  addr_col = 0xFF;
71 
72 #ifdef LOAD_GLCD
73  fontsloaded = 0x0002; // Bit 1 set
74 #endif
75 
76 #ifdef LOAD_FONT2
77  fontsloaded |= 0x0004; // Bit 2 set
78 #endif
79 
80 #ifdef LOAD_FONT4
81  fontsloaded |= 0x0010; // Bit 4 set
82 #endif
83 
84 #ifdef LOAD_FONT6
85  fontsloaded |= 0x0040; // Bit 6 set
86 #endif
87 
88 #ifdef LOAD_FONT7
89  fontsloaded |= 0x0080; // Bit 7 set
90 #endif
91 
92 #ifdef LOAD_FONT8
93  fontsloaded |= 0x0100; // Bit 8 set
94 #endif
95 
96 }
97 
98 /***************************************************************************************
99 ** Function name: spiwrite
100 ** Description: Write 8 bits to SPI port
101 ***************************************************************************************/
102 void TFT_ST7735::spiwrite(uint8_t c)
103 {
104  savedSPCR = SPCR;
105  SPCR = mySPCR;
106  SPDR = c;
107  asm volatile( "nop\n\t" ::); // Sync SPIF
108  while (!(SPSR & _BV(SPIF)));
109  SPCR = savedSPCR;
110 }
111 
112 /***************************************************************************************
113 ** Function name: writecommand
114 ** Description: Send an 8 bit command to the TFT
115 ***************************************************************************************/
117 {
118  TFT_DC_C;
119  TFT_CS_L;
120  spiwrite(c);
121  TFT_CS_H;
122 }
123 
124 /***************************************************************************************
125 ** Function name: writedata
126 ** Description: Send a 8 bit data value to the TFT
127 ***************************************************************************************/
128 void TFT_ST7735::writedata(uint8_t c)
129 {
130  TFT_DC_D;
131  TFT_CS_L;
132  spiwrite(c);
133  TFT_CS_H;
134 }
135 
136 /***************************************************************************************
137 ** Function name: writeEnd
138 ** Description: Raise the Chip Select
139 ***************************************************************************************/
141  TFT_CS_H;
142 }
143 
144 /***************************************************************************************
145 ** Function name: backupSPCR
146 ** Description: Save the SPCR register so it can be restored
147 ***************************************************************************************/
149  savedSPCR = SPCR;
150  SPCR = mySPCR;
151 }
152 
153 /***************************************************************************************
154 ** Function name: restoreSPCR
155 ** Description: Restore the origional SPCR value
156 ***************************************************************************************/
158  SPCR = savedSPCR;
159 }
160 
161 /***************************************************************************************
162 ** Function name: spi_begin
163 ** Description: Prepare for SPI communication to TFT
164 ***************************************************************************************/
165 // If the SPI library has transaction support, these functions
166 // establish settings and protect from interference from other
167 // libraries. Otherwise, they simply do nothing.
168 
169 #ifdef SPI_HAS_TRANSACTION
170  #ifdef SUPPORT_TRANSACTIONS
171 
172 static inline void spi_begin(void) __attribute__((always_inline));
173 
174 static inline void spi_begin(void) {
175  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
176 }
177 
178 static inline void spi_end(void) __attribute__((always_inline));
179 
180 static inline void spi_end(void) {
181  SPI.endTransaction();
182 }
183  #else // we do not want to SUPPORT_TRANSACTIONS
184 
185 #define spi_begin()
186 #define spi_end()
187 
188  #endif // SUPPORT_TRANSACTIONS
189 
190 #else
191 #define spi_begin()
192 #define spi_end()
193 #endif
194 
195 /***************************************************************************************
196 ** Function name: begin
197 ** Description: Included for backwards compatibility
198 ***************************************************************************************/
200 {
201  init();
202 }
203 
204 /***************************************************************************************
205 ** Function name: init
206 ** Description: Reset, then initialise the TFT display registers
207 ***************************************************************************************/
208 #define DELAY 0x80
209 
211 {
212  SPI.begin();
213 
214  savedSPCR = SPCR;
215  SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
216  SPI.setBitOrder(MSBFIRST);
217  SPI.setDataMode(SPI_MODE0);
218  mySPCR = SPCR;
219 
220  spi_end();
221 
222  // toggle RST low to reset
223  if (_rst > 0) {
224  digitalWrite(_rst, HIGH);
225  delay(5);
226  digitalWrite(_rst, LOW);
227  delay(20);
228  digitalWrite(_rst, HIGH);
229  delay(150);
230  }
231 
232 
233  // Initialization commands for ST7735 screens
234  static const uint8_t PROGMEM
235  Bcmd[] = { // Initialization commands for 7735B screens
236  18, // 18 commands in list:
237  ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay
238  50, // 50 ms delay
239  ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay
240  255, // 255 = 500 ms delay
241  ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay:
242  0x05, // 16-bit color
243  10, // 10 ms delay
244  ST7735_FRMCTR1, 3+DELAY, // 4: Frame rate control, 3 args + delay:
245  0x00, // fastest refresh
246  0x06, // 6 lines front porch
247  0x03, // 3 lines back porch
248  10, // 10 ms delay
249  ST7735_MADCTL , 1 , // 5: Memory access ctrl (directions), 1 arg:
250  0x08, // Row addr/col addr, bottom to top refresh
251  ST7735_DISSET5, 2 , // 6: Display settings #5, 2 args, no delay:
252  0x15, // 1 clk cycle nonoverlap, 2 cycle gate
253  // rise, 3 cycle osc equalize
254  0x02, // Fix on VTL
255  ST7735_INVCTR , 1 , // 7: Display inversion control, 1 arg:
256  0x0, // Line inversion
257  ST7735_PWCTR1 , 2+DELAY, // 8: Power control, 2 args + delay:
258  0x02, // GVDD = 4.7V
259  0x70, // 1.0uA
260  10, // 10 ms delay
261  ST7735_PWCTR2 , 1 , // 9: Power control, 1 arg, no delay:
262  0x05, // VGH = 14.7V, VGL = -7.35V
263  ST7735_PWCTR3 , 2 , // 10: Power control, 2 args, no delay:
264  0x01, // Opamp current small
265  0x02, // Boost frequency
266  ST7735_VMCTR1 , 2+DELAY, // 11: Power control, 2 args + delay:
267  0x3C, // VCOMH = 4V
268  0x38, // VCOML = -1.1V
269  10, // 10 ms delay
270  ST7735_PWCTR6 , 2 , // 12: Power control, 2 args, no delay:
271  0x11, 0x15,
272  ST7735_GMCTRP1,16 , // 13: Magical unicorn dust, 16 args, no delay:
273  0x09, 0x16, 0x09, 0x20, // (seriously though, not sure what
274  0x21, 0x1B, 0x13, 0x19, // these config values represent)
275  0x17, 0x15, 0x1E, 0x2B,
276  0x04, 0x05, 0x02, 0x0E,
277  ST7735_GMCTRN1,16+DELAY, // 14: Sparkles and rainbows, 16 args + delay:
278  0x0B, 0x14, 0x08, 0x1E, // (ditto)
279  0x22, 0x1D, 0x18, 0x1E,
280  0x1B, 0x1A, 0x24, 0x2B,
281  0x06, 0x06, 0x02, 0x0F,
282  10, // 10 ms delay
283  ST7735_CASET , 4 , // 15: Column addr set, 4 args, no delay:
284  0x00, 0x02, // XSTART = 2
285  0x00, 0x81, // XEND = 129
286  ST7735_RASET , 4 , // 16: Row addr set, 4 args, no delay:
287  0x00, 0x02, // XSTART = 1
288  0x00, 0x81, // XEND = 160
289  ST7735_NORON , DELAY, // 17: Normal display on, no args, w/delay
290  10, // 10 ms delay
291  ST7735_DISPON , DELAY, // 18: Main screen turn on, no args, w/delay
292  255 }, // 255 = 500 ms delay
293 
294  Rcmd1[] = { // Init for 7735R, part 1 (red or green tab)
295  15, // 15 commands in list:
296  ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay
297  150, // 150 ms delay
298  ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, 0 args, w/delay
299  255, // 500 ms delay
300  ST7735_FRMCTR1, 3 , // 3: Frame rate ctrl - normal mode, 3 args:
301  0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
302  ST7735_FRMCTR2, 3 , // 4: Frame rate control - idle mode, 3 args:
303  0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
304  ST7735_FRMCTR3, 6 , // 5: Frame rate ctrl - partial mode, 6 args:
305  0x01, 0x2C, 0x2D, // Dot inversion mode
306  0x01, 0x2C, 0x2D, // Line inversion mode
307  ST7735_INVCTR , 1 , // 6: Display inversion ctrl, 1 arg, no delay:
308  0x07, // No inversion
309  ST7735_PWCTR1 , 3 , // 7: Power control, 3 args, no delay:
310  0xA2,
311  0x02, // -4.6V
312  0x84, // AUTO mode
313  ST7735_PWCTR2 , 1 , // 8: Power control, 1 arg, no delay:
314  0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
315  ST7735_PWCTR3 , 2 , // 9: Power control, 2 args, no delay:
316  0x0A, // Opamp current small
317  0x00, // Boost frequency
318  ST7735_PWCTR4 , 2 , // 10: Power control, 2 args, no delay:
319  0x8A, // BCLK/2, Opamp current small & Medium low
320  0x2A,
321  ST7735_PWCTR5 , 2 , // 11: Power control, 2 args, no delay:
322  0x8A, 0xEE,
323  ST7735_VMCTR1 , 1 , // 12: Power control, 1 arg, no delay:
324  0x0E,
325  ST7735_INVOFF , 0 , // 13: Don't invert display, no args, no delay
326  ST7735_MADCTL , 1 , // 14: Memory access control (directions), 1 arg:
327  0xC8, // row addr/col addr, bottom to top refresh
328  ST7735_COLMOD , 1 , // 15: set color mode, 1 arg, no delay:
329  0x05 }, // 16-bit color
330 
331  Rcmd2green[] = { // Init for 7735R, part 2 (green tab only)
332  2, // 2 commands in list:
333  ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
334  0x00, 0x02, // XSTART = 0
335  0x00, 0x7F+0x02, // XEND = 127
336  ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
337  0x00, 0x01, // XSTART = 0
338  0x00, 0x9F+0x01 }, // XEND = 159
339 
340  Rcmd2red[] = { // Init for 7735R, part 2 (red tab only)
341  2, // 2 commands in list:
342  ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
343  0x00, 0x00, // XSTART = 0
344  0x00, 0x7F, // XEND = 127
345  ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
346  0x00, 0x00, // XSTART = 0
347  0x00, 0x9F }, // XEND = 159
348 
349  Rcmd3[] = { // Init for 7735R, part 3 (red or green tab)
350  4, // 4 commands in list:
351  ST7735_GMCTRP1, 16 , // 1: Magical unicorn dust, 16 args, no delay:
352  0x02, 0x1c, 0x07, 0x12,
353  0x37, 0x32, 0x29, 0x2d,
354  0x29, 0x25, 0x2B, 0x39,
355  0x00, 0x01, 0x03, 0x10,
356  ST7735_GMCTRN1, 16 , // 2: Sparkles and rainbows, 16 args, no delay:
357  0x03, 0x1d, 0x07, 0x06,
358  0x2E, 0x2C, 0x29, 0x2D,
359  0x2E, 0x2E, 0x37, 0x3F,
360  0x00, 0x00, 0x02, 0x10,
361  ST7735_NORON , DELAY, // 3: Normal display on, no args, w/delay
362  10, // 10 ms delay
363  ST7735_DISPON , DELAY, // 4: Main screen turn on, no args w/delay
364  100 }; // 100 ms delay
365 
366 
367  tabcolor = TAB_COLOUR;
368 
369  if (tabcolor == INITB)
370  {
371  commandList(Bcmd);
372  }
373  else
374  {
375  commandList(Rcmd1);
376  if (tabcolor == INITR_GREENTAB)
377  {
378  commandList(Rcmd2green);
379  colstart = 2;
380  rowstart = 1;
381  }
382  else if (tabcolor == INITR_GREENTAB2)
383  {
384  commandList(Rcmd2green);
386  writedata(0xC0);
387  colstart = 2;
388  rowstart = 1;
389  }
390  else if (tabcolor == INITR_REDTAB)
391  {
392  commandList(Rcmd2red);
393  }
394  else if (tabcolor == INITR_BLACKTAB)
395  {
397  writedata(0xC0);
398  }
399  commandList(Rcmd3);
400  }
401 }
402 
403 /***************************************************************************************
404 ** Function name: commandList
405 ** Description: Get initialisation commands from FLASH and send to TFT
406 ***************************************************************************************/
407 void TFT_ST7735::commandList (const uint8_t *addr)
408 {
409  uint8_t numCommands, numArgs;
410  uint8_t ms;
411 
412  spi_begin();
413  numCommands = pgm_read_byte(addr++); // Number of commands to follow
414  while (numCommands--) // For each command...
415  {
416  writecommand(pgm_read_byte(addr++)); // Read, issue command
417  numArgs = pgm_read_byte(addr++); // Number of args to follow
418  ms = numArgs & ST7735_INIT_DELAY; // If hibit set, delay follows args
419  numArgs &= ~ST7735_INIT_DELAY; // Mask out delay bit
420  while (numArgs--) // For each argument...
421  {
422  writedata(pgm_read_byte(addr++)); // Read, issue argument
423  }
424 
425  if (ms)
426  {
427  ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
428  delay( (ms==255 ? 500 : ms) );
429  }
430  }
431  spi_end();
432 }
433 
434 /***************************************************************************************
435 ** Function name: drawCircle
436 ** Description: Draw a circle outline
437 ***************************************************************************************/
438 void TFT_ST7735::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
439 {
440  int16_t f = 1 - r;
441  int16_t ddF_x = 1;
442  int16_t ddF_y = - r - r;
443  int16_t x = 0;
444 
445  drawPixel(x0 + r, y0 , color);
446  drawPixel(x0 - r, y0 , color);
447  drawPixel(x0 , y0 - r, color);
448  drawPixel(x0 , y0 + r, color);
449 
450  while (x < r) {
451  if (f >= 0) {
452  r--;
453  ddF_y += 2;
454  f += ddF_y;
455  }
456  x++;
457  ddF_x += 2;
458  f += ddF_x;
459 
460  drawPixel(x0 + x, y0 + r, color);
461  drawPixel(x0 - x, y0 + r, color);
462  drawPixel(x0 - x, y0 - r, color);
463  drawPixel(x0 + x, y0 - r, color);
464 
465  drawPixel(x0 + r, y0 + x, color);
466  drawPixel(x0 - r, y0 + x, color);
467  drawPixel(x0 - r, y0 - x, color);
468  drawPixel(x0 + r, y0 - x, color);
469  }
470 }
471 
472 /***************************************************************************************
473 ** Function name: drawCircleHelper
474 ** Description: Support function for circle drawing
475 ***************************************************************************************/
476 void TFT_ST7735::drawCircleHelper( int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color)
477 {
478  int16_t f = 1 - r;
479  int16_t ddF_x = 1;
480  int16_t ddF_y = -2 * r;
481  int16_t x = 0;
482 
483  while (x < r) {
484  if (f >= 0) {
485  r--;
486  ddF_y += 2;
487  f += ddF_y;
488  }
489  x++;
490  ddF_x += 2;
491  f += ddF_x;
492  if (cornername & 0x8) {
493  drawPixel(x0 - r, y0 + x, color);
494  drawPixel(x0 - x, y0 + r, color);
495  }
496  if (cornername & 0x4) {
497  drawPixel(x0 + x, y0 + r, color);
498  drawPixel(x0 + r, y0 + x, color);
499  }
500  if (cornername & 0x2) {
501  drawPixel(x0 + r, y0 - x, color);
502  drawPixel(x0 + x, y0 - r, color);
503  }
504  if (cornername & 0x1) {
505  drawPixel(x0 - x, y0 - r, color);
506  drawPixel(x0 - r, y0 - x, color);
507  }
508 
509  }
510 }
511 
512 /***************************************************************************************
513 ** Function name: fillCircle
514 ** Description: draw a filled circle
515 ***************************************************************************************/
516 void TFT_ST7735::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
517 {
518  drawFastVLine(x0, y0 - r, r + r + 1, color);
519  fillCircleHelper(x0, y0, r, 3, 0, color);
520 }
521 
522 /***************************************************************************************
523 ** Function name: fillCircleHelper
524 ** Description: Support function for filled circle drawing
525 ***************************************************************************************/
526 // Used to do circles and roundrects
527 void TFT_ST7735::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color)
528 {
529  int16_t f = 1 - r;
530  int16_t ddF_x = 1;
531  int16_t ddF_y = -r - r;
532  int16_t x = 0;
533 
534  delta++;
535  while (x < r) {
536  if (f >= 0) {
537  r--;
538  ddF_y += 2;
539  f += ddF_y;
540  }
541  x++;
542  ddF_x += 2;
543  f += ddF_x;
544 
545  if (cornername & 0x1) {
546  drawFastVLine(x0 + x, y0 - r, r + r + delta, color);
547  drawFastVLine(x0 + r, y0 - x, x + x + delta, color);
548  }
549  if (cornername & 0x2) {
550  drawFastVLine(x0 - x, y0 - r, r + r + delta, color);
551  drawFastVLine(x0 - r, y0 - x, x + x + delta, color);
552  }
553  }
554 }
555 
556 /***************************************************************************************
557 ** Function name: drawEllipse
558 ** Description: Draw a ellipse outline
559 ***************************************************************************************/
560 void TFT_ST7735::drawEllipse(int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint16_t color)
561 {
562  if (rx<2) return;
563  if (ry<2) return;
564  int16_t x, y;
565  int32_t rx2 = rx * rx;
566  int32_t ry2 = ry * ry;
567  int32_t fx2 = 4 * rx2;
568  int32_t fy2 = 4 * ry2;
569  int32_t s;
570 
571  for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++)
572  {
573  drawPixel(x0 + x, y0 + y, color);
574  drawPixel(x0 - x, y0 + y, color);
575  drawPixel(x0 - x, y0 - y, color);
576  drawPixel(x0 + x, y0 - y, color);
577  if (s >= 0)
578  {
579  s += fx2 * (1 - y);
580  y--;
581  }
582  s += ry2 * ((4 * x) + 6);
583  }
584 
585  for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++)
586  {
587  drawPixel(x0 + x, y0 + y, color);
588  drawPixel(x0 - x, y0 + y, color);
589  drawPixel(x0 - x, y0 - y, color);
590  drawPixel(x0 + x, y0 - y, color);
591  if (s >= 0)
592  {
593  s += fy2 * (1 - x);
594  x--;
595  }
596  s += rx2 * ((4 * y) + 6);
597  }
598 }
599 
600 /***************************************************************************************
601 ** Function name: fillEllipse
602 ** Description: draw a filled ellipse
603 ***************************************************************************************/
604 void TFT_ST7735::fillEllipse(int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint16_t color)
605 {
606  if (rx<2) return;
607  if (ry<2) return;
608  int16_t x, y;
609  int32_t rx2 = rx * rx;
610  int32_t ry2 = ry * ry;
611  int32_t fx2 = 4 * rx2;
612  int32_t fy2 = 4 * ry2;
613  int32_t s;
614 
615  for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++)
616  {
617  drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
618  drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
619 
620  if (s >= 0)
621  {
622  s += fx2 * (1 - y);
623  y--;
624  }
625  s += ry2 * ((4 * x) + 6);
626  }
627 
628  for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++)
629  {
630  drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
631  drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
632 
633  if (s >= 0)
634  {
635  s += fy2 * (1 - x);
636  x--;
637  }
638  s += rx2 * ((4 * y) + 6);
639  }
640 
641 }
642 
643 /***************************************************************************************
644 ** Function name: fillScreen
645 ** Description: Clear the screen to defined colour
646 ***************************************************************************************/
647 void TFT_ST7735::fillScreen(uint16_t color)
648 {
649  fillRect(0, 0, _width, _height, color);
650 }
651 
652 /***************************************************************************************
653 ** Function name: drawRect
654 ** Description: Draw a rectangle outline
655 ***************************************************************************************/
656 // Draw a rectangle
657 void TFT_ST7735::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
658 {
659  drawFastHLine(x, y, w, color);
660  drawFastHLine(x, y + h - 1, w, color);
661  drawFastVLine(x, y, h, color);
662  drawFastVLine(x + w - 1, y, h, color);
663 }
664 
665 /***************************************************************************************
666 ** Function name: drawRoundRect
667 ** Description: Draw a rounded corner rectangle outline
668 ***************************************************************************************/
669 // Draw a rounded rectangle
670 void TFT_ST7735::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
671 {
672  // smarter version
673  drawFastHLine(x + r , y , w - r - r, color); // Top
674  drawFastHLine(x + r , y + h - 1, w - r - r, color); // Bottom
675  drawFastVLine(x , y + r , h - r - r, color); // Left
676  drawFastVLine(x + w - 1, y + r , h - r - r, color); // Right
677  // draw four corners
678  drawCircleHelper(x + r , y + r , r, 1, color);
679  drawCircleHelper(x + r , y + h - r - 1, r, 8, color);
680  drawCircleHelper(x + w - r - 1, y + r , r, 2, color);
681  drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
682 
683 }
684 
685 /***************************************************************************************
686 ** Function name: fillRoundRect
687 ** Description: Draw a rounded corner filled rectangle
688 ***************************************************************************************/
689 // Fill a rounded rectangle
690 void TFT_ST7735::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
691 {
692  // smarter version
693  fillRect(x + r, y, w - r - r, h, color);
694 
695  // draw four corners
696  fillCircleHelper(x + w - r - 1, y + r, r, 1, h - r - r - 1, color);
697  fillCircleHelper(x + r , y + r, r, 2, h - r - r - 1, color);
698 }
699 
700 /***************************************************************************************
701 ** Function name: drawTriangle
702 ** Description: Draw a triangle outline using 3 arbitrary points
703 ***************************************************************************************/
704 // Draw a triangle
705 void TFT_ST7735::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
706 {
707  drawLine(x0, y0, x1, y1, color);
708  drawLine(x1, y1, x2, y2, color);
709  drawLine(x2, y2, x0, y0, color);
710 }
711 
712 /***************************************************************************************
713 ** Function name: fillTriangle
714 ** Description: Draw a filled triangle using 3 arbitrary points
715 ***************************************************************************************/
716 // Fill a triangle - original Adafruit function works well and code footprint is small
717 void TFT_ST7735::fillTriangle ( int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
718 {
719  int16_t a, b, y, last;
720 
721  // Sort coordinates by Y order (y2 >= y1 >= y0)
722  if (y0 > y1) {
723  tftswap(y0, y1); tftswap(x0, x1);
724  }
725  if (y1 > y2) {
726  tftswap(y2, y1); tftswap(x2, x1);
727  }
728  if (y0 > y1) {
729  tftswap(y0, y1); tftswap(x0, x1);
730  }
731 
732  if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
733  a = b = x0;
734  if (x1 < a) a = x1;
735  else if (x1 > b) b = x1;
736  if (x2 < a) a = x2;
737  else if (x2 > b) b = x2;
738  drawFastHLine(a, y0, b - a + 1, color);
739  return;
740  }
741 
742  int16_t
743  dx01 = x1 - x0,
744  dy01 = y1 - y0,
745  dx02 = x2 - x0,
746  dy02 = y2 - y0,
747  dx12 = x2 - x1,
748  dy12 = y2 - y1,
749  sa = 0,
750  sb = 0;
751 
752  // For upper part of triangle, find scanline crossings for segments
753  // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
754  // is included here (and second loop will be skipped, avoiding a /0
755  // error there), otherwise scanline y1 is skipped here and handled
756  // in the second loop...which also avoids a /0 error here if y0=y1
757  // (flat-topped triangle).
758  if (y1 == y2) last = y1; // Include y1 scanline
759  else last = y1 - 1; // Skip it
760 
761  for (y = y0; y <= last; y++) {
762  a = x0 + sa / dy01;
763  b = x0 + sb / dy02;
764  sa += dx01;
765  sb += dx02;
766 
767  if (a > b) tftswap(a, b);
768  drawFastHLine(a, y, b - a + 1, color);
769  }
770 
771  // For lower part of triangle, find scanline crossings for segments
772  // 0-2 and 1-2. This loop is skipped if y1=y2.
773  sa = dx12 * (y - y1);
774  sb = dx02 * (y - y0);
775  for (; y <= y2; y++) {
776  a = x1 + sa / dy12;
777  b = x0 + sb / dy02;
778  sa += dx12;
779  sb += dx02;
780 
781  if (a > b) tftswap(a, b);
782  drawFastHLine(a, y, b - a + 1, color);
783  }
784 }
785 
786 /***************************************************************************************
787 ** Function name: drawBitmap
788 ** Description: Draw an image stored in an array on the TFT
789 ***************************************************************************************/
790 void TFT_ST7735::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
791 {
792 
793  int16_t i, j, byteWidth = (w + 7) / 8;
794 
795  for (j = 0; j < h; j++) {
796  for (i = 0; i < w; i++ ) {
797  if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
798  drawPixel(x + i, y + j, color);
799  }
800  }
801  }
802 }
803 
804 /***************************************************************************************
805 ** Function name: setCursor
806 ** Description: Set the text cursor x,y position
807 ***************************************************************************************/
808 void TFT_ST7735::setCursor(int16_t x, int16_t y)
809 {
810  cursor_x = x;
811  cursor_y = y;
812 }
813 
814 /***************************************************************************************
815 ** Function name: setCursor
816 ** Description: Set the text cursor x,y position and font
817 ***************************************************************************************/
818 void TFT_ST7735::setCursor(int16_t x, int16_t y, uint8_t font)
819 {
820  textfont = font;
821  cursor_x = x;
822  cursor_y = y;
823 }
824 
825 /***************************************************************************************
826 ** Function name: setTextSize
827 ** Description: Set the text size multiplier
828 ***************************************************************************************/
829 void TFT_ST7735::setTextSize(uint8_t s)
830 {
831  if (s>7) s = 7; // Limit the maximum size multiplier so byte variables can be used for rendering
832  textsize = (s > 0) ? s : 1; // Don't allow font size 0
833 }
834 
835 /***************************************************************************************
836 ** Function name: setTextFont
837 ** Description: Set the font for the print stream
838 ***************************************************************************************/
839 void TFT_ST7735::setTextFont(uint8_t f)
840 {
841  textfont = (f > 0) ? f : 1; // Don't allow font 0
842 }
843 
844 /***************************************************************************************
845 ** Function name: setTextColor
846 ** Description: Set the font foreground colour (background is transparent)
847 ***************************************************************************************/
848 void TFT_ST7735::setTextColor(uint16_t c)
849 {
850  // For 'transparent' background, we'll set the bg
851  // to the same as fg instead of using a flag
852  textcolor = textbgcolor = c;
853 }
854 
855 /***************************************************************************************
856 ** Function name: setTextColor
857 ** Description: Set the font foreground and background colour
858 ***************************************************************************************/
859 void TFT_ST7735::setTextColor(uint16_t c, uint16_t b)
860 {
861  textcolor = c;
862  textbgcolor = b;
863 }
864 
865 /***************************************************************************************
866 ** Function name: setTextWrap
867 ** Description: Define if text should wrap at end of line
868 ***************************************************************************************/
869 void TFT_ST7735::setTextWrap(boolean w)
870 {
871  textwrap = w;
872 }
873 
874 /***************************************************************************************
875 ** Function name: setTextDatum
876 ** Description: Set the text position reference datum
877 ***************************************************************************************/
879 {
880  textdatum = d;
881 }
882 
883 /***************************************************************************************
884 ** Function name: setTextPadding
885 ** Description: Define padding width (aids erasing old text and numbers)
886 ***************************************************************************************/
887 void TFT_ST7735::setTextPadding(uint16_t x_width)
888 {
889  padX = x_width;
890 }
891 
892 /***************************************************************************************
893 ** Function name: getRotation
894 ** Description: Return the rotation value (as used by setRotation())
895 ***************************************************************************************/
897 {
898  return rotation;
899 }
900 
901 /***************************************************************************************
902 ** Function name: width
903 ** Description: Return the pixel width of display (per current rotation)
904 ***************************************************************************************/
905 // Return the size of the display (per current rotation)
906 int16_t TFT_ST7735::width(void)
907 {
908  return _width;
909 }
910 
911 /***************************************************************************************
912 ** Function name: height
913 ** Description: Return the pixel height of display (per current rotation)
914 ***************************************************************************************/
915 int16_t TFT_ST7735::height(void)
916 {
917  return _height;
918 }
919 
920 /***************************************************************************************
921 ** Function name: textWidth
922 ** Description: Return the width in pixels of a string in a given font
923 ***************************************************************************************/
924 int16_t TFT_ST7735::textWidth(char *string, int font)
925 {
926  unsigned int str_width = 0;
927  char uniCode;
928  char *widthtable;
929 
930  if (font>1 && font<9)
931  widthtable = (char *)pgm_read_word( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop
932 
933  while (*string)
934  {
935  uniCode = *(string++);
936 #ifdef LOAD_GLCD
937  if (font == 1) str_width += 6;
938  else
939 #endif
940  str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subract 32 from uniCode
941  }
942  return str_width * textsize;
943 }
944 
945 /***************************************************************************************
946 ** Function name: fontsLoaded
947 ** Description: return an encoded 16 bit value showing the fonts loaded
948 ***************************************************************************************/
949 // Returns a value showing which fonts are loaded (bit N set = Font N loaded)
950 
952 {
953  return fontsloaded;
954 }
955 
956 
957 /***************************************************************************************
958 ** Function name: fontHeight
959 ** Description: return the height of a font
960 ***************************************************************************************/
961 int16_t TFT_ST7735::fontHeight(int font)
962 {
963  return pgm_read_byte( &fontdata[font].height ) * textsize;
964 }
965 
966 /***************************************************************************************
967 ** Function name: drawChar
968 ** Description: draw a single character in the Adafruit GLCD font
969 ***************************************************************************************/
970 void TFT_ST7735::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)
971 {
972 #ifdef LOAD_GLCD
973  if ((x >= _width) || // Clip right
974  (y >= _height) || // Clip bottom
975  ((x + 6 * size - 1) < 0) || // Clip left
976  ((y + 8 * size - 1) < 0)) // Clip top
977  return;
978  boolean fillbg = (bg != color);
979 
980 spi_begin();
981 
982 // This is about 5 times faster for textsize=1 with background (at 200us per character)
983  if ((size==1) && fillbg)
984  {
985  byte column[6];
986  byte mask = 0x1;
987  setWindow(x, y, x+5, y+8);
988  for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i);
989  column[5] = 0;
990 
991  for (int8_t j = 0; j < 8; j++) {
992  for (int8_t k = 0; k < 5; k++ ) {
993  if (column[k] & mask) {
994  while (!(SPSR & _BV(SPIF)));
995  SPDR = color >> 8; asm volatile( "nop\n\t" ::); // Sync to SPIF bit
996  while (!(SPSR & _BV(SPIF)));
997  SPDR = color;
998  }
999  else {
1000  while (!(SPSR & _BV(SPIF)));
1001  SPDR = bg >> 8; asm volatile( "nop\n\t" ::);
1002  while (!(SPSR & _BV(SPIF)));
1003  SPDR = bg;
1004  }
1005  }
1006 
1007  mask <<= 1;
1008  while (!(SPSR & _BV(SPIF)));
1009  SPDR = bg >> 8; while (!(SPSR & _BV(SPIF)));
1010  SPDR = bg;
1011  }
1012  while (!(SPSR & _BV(SPIF)));
1013  }
1014  else
1015  {
1016  if (size == 1) // default size
1017  {
1018  for (int8_t i = 0; i < 5; i++ ) {
1019  uint8_t line = pgm_read_byte(font + c*5 + i);
1020  if (line & 0x1) drawPixel(x + i, y, color);
1021  if (line & 0x2) drawPixel(x + i, y + 1, color);
1022  if (line & 0x4) drawPixel(x + i, y + 2, color);
1023  if (line & 0x8) drawPixel(x + i, y + 3, color);
1024  if (line & 0x10) drawPixel(x + i, y + 4, color);
1025  if (line & 0x20) drawPixel(x + i, y + 5, color);
1026  if (line & 0x40) drawPixel(x + i, y + 6, color);
1027  if (line & 0x80) drawPixel(x + i, y + 7, color);
1028  }
1029  }
1030  else { // big size
1031  for (int8_t i = 0; i < 5; i++ ) {
1032  uint8_t line = pgm_read_byte(font + c*5 + i);
1033  for (int8_t j = 0; j < 8; j++) {
1034  if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color);
1035  else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg);
1036  line >>= 1;
1037  }
1038  }
1039  }
1040  }
1041 
1042 spi_end();
1043 
1044 #endif // LOAD_GLCD
1045 }
1046 
1047 /***************************************************************************************
1048 ** Function name: setAddrWindow
1049 ** Description: define an area to receive a stream of pixels
1050 ***************************************************************************************/
1051 // Chip select is high at the end of this function
1052 
1053 void TFT_ST7735::setAddrWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
1054 {
1055  spi_begin();
1056  setWindow(x0, y0, x1, y1);
1057  TFT_CS_H;
1058  while (!(SPSR & _BV(SPIF)));
1059  spi_end();
1060 }
1061 
1062 /***************************************************************************************
1063 ** Function name: setWindow
1064 ** Description: define an area to receive a stream of pixels
1065 ***************************************************************************************/
1066 // Chip select stays low, use setAddrWindow() from sketches
1067 
1068 void TFT_ST7735::setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
1069 {
1070 
1071  addr_row = 0xFF;
1072  addr_col = 0xFF;
1073 
1074  // Column addr set
1075  TFT_DC_C;
1076  TFT_CS_L;
1077 
1078  SPDR = ST7735_CASET;
1079  spiWait15();
1080 
1081  TFT_DC_D;
1082  SPDR = 0; spiWait14();
1083  SPDR = x0+colstart; spiWait17();
1084  SPDR = 0; spiWait14();
1085  SPDR = x1+colstart; spiWait14();
1086 
1087  // Row addr set
1088  TFT_DC_C;
1089  SPDR = ST7735_RASET; spiWait15();
1090 
1091  TFT_DC_D;
1092  SPDR = 0; spiWait14();
1093  SPDR = y0+rowstart; spiWait17();
1094  SPDR = 0; spiWait14();
1095  SPDR = y1+rowstart; spiWait14();
1096 
1097  // write to RAM
1098  TFT_DC_C;
1099  SPDR = ST7735_RAMWR; spiWait14();
1100 
1101  TFT_DC_D;
1102 
1103 }
1104 
1105 /***************************************************************************************
1106 ** Function name: drawPixel
1107 ** Description: push a single pixel at an arbitrary position
1108 ***************************************************************************************/
1109 // Smarter version that takes advantage of often used orthogonal coordinate plots
1110 // where either x or y does not change
1111 void TFT_ST7735::drawPixel(uint16_t x, uint16_t y, uint16_t color)
1112 {
1113  // Faster range checking, possible because x and y are unsigned
1114  if ((x >= _width) || (y >= _height)) return;
1115  spi_begin();
1116 
1117  TFT_DC_C;
1118  TFT_CS_L;
1119 
1120 if (addr_col != x) {
1121  SPDR = ST7735_CASET;
1122  spiWait12();
1123  addr_col = x;
1124  TFT_DC_D;
1125  SPDR = 0; spiWait14();
1126  SPDR = x+colstart; spiWait14(); // spiWait17() if we include the next 2 lines
1127  //SPDR = 0; spiWait14();
1128  //SPDR = x+colstart; spiWait14();
1129 
1130  TFT_DC_C;
1131 }
1132 
1133 if (addr_row != y) {
1134  SPDR = ST7735_RASET;
1135  spiWait12();
1136  addr_row = y;
1137  TFT_DC_D;
1138  SPDR = 0; spiWait14();
1139  SPDR = y+rowstart; spiWait14(); // spiWait17() if we include the next 2 lines
1140  //SPDR = 0; spiWait14();
1141  //SPDR = y+rowstart; spiWait14();
1142 
1143  TFT_DC_C;
1144 }
1145 
1146  SPDR = ST7735_RAMWR; spiWait15();
1147 
1148  TFT_DC_D;
1149 
1150  SPDR = color >> 8; spiWait17();
1151  SPDR = color; spiWait14();
1152 
1153  TFT_CS_H;
1154 
1155  spi_end();
1156 }
1157 
1158 /***************************************************************************************
1159 ** Function name: pushColor
1160 ** Description: push a single pixel
1161 ***************************************************************************************/
1162 void TFT_ST7735::pushColor(uint16_t color)
1163 {
1164  spi_begin();
1165 
1166  TFT_CS_L;
1167 
1168  //uint8_t backupSPCR =SPCR;
1169  //SPCR = mySPCR;
1170 
1171  SPDR = color>>8;
1172  while (!(SPSR & _BV(SPIF)));
1173  SPDR = color;
1174  while (!(SPSR & _BV(SPIF)));
1175 
1176  //SPCR = backupSPCR;
1177 
1178  TFT_CS_H;
1179 
1180  spi_end();
1181 }
1182 
1183 /***************************************************************************************
1184 ** Function name: pushColor
1185 ** Description: push a single colour to "len" pixels
1186 ***************************************************************************************/
1187 void TFT_ST7735::pushColor(uint16_t color, uint16_t len)
1188 {
1189  spi_begin();
1190 
1191  TFT_CS_L;
1192  spiWrite16(color, len);
1193  TFT_CS_H;
1194  while (!(SPSR & _BV(SPIF)));
1195 
1196  spi_end();
1197 }
1198 
1199 /***************************************************************************************
1200 ** Function name: pushColors
1201 ** Description: push an aray of pixels for BMP image drawing
1202 ***************************************************************************************/
1203 // Sends an array of 16-bit color values to the TFT; used
1204 // externally by BMP examples. Assumes that setAddrWindow() has
1205 // previously been called to define the bounds. Max 255 pixels at
1206 // a time (BMP examples read in small chunks due to limited RAM).
1207 
1208 void TFT_ST7735::pushColors(uint16_t *data, uint8_t len)
1209 {
1210  uint16_t color;
1211  spi_begin();
1212 
1213  TFT_CS_L;
1214 
1215  while (len--) {
1216  color = *(data++);
1217  SPDR = color >> 8;
1218  spiWait17(); // Wait 17 clock cycles
1219  SPDR = color;
1220  // Wait 9 clock cycles
1221  asm volatile
1222  (
1223  " rcall 1f \n" // 7
1224  " rjmp 2f \n" // 9
1225  "1: ret \n" //
1226  "2: \n" //
1227  );
1228  }
1229  while (!(SPSR & _BV(SPIF)));
1230 
1231  TFT_CS_H;
1232 
1233  spi_end();
1234 }
1235 
1236 /***************************************************************************************
1237 ** Function name: pushColors
1238 ** Description: push an aray of pixels for 16 bit raw image drawing
1239 ***************************************************************************************/
1240 // Assumed that setAddrWindow() has previously been called
1241 
1242 void TFT_ST7735::pushColors(uint8_t *data, uint16_t len)
1243 {
1244  spi_begin();
1245  len = len<<1;
1246 
1247  TFT_CS_L;
1248  while (len--) {
1249  SPDR = *(data++);
1250  // Wait 11 clock cycles
1251  asm volatile
1252  (
1253  " adiw r24,0 \n" // 2
1254  " rcall 1f \n" // 9
1255  " rjmp 2f \n" // 11
1256  "1: ret \n" //
1257  "2: \n" //
1258  );
1259  }
1260  TFT_CS_H;
1261 
1262  while (!(SPSR & _BV(SPIF)));
1263  spi_end();
1264 }
1265 
1266 /***************************************************************************************
1267 ** Function name: drawLine
1268 ** Description: draw a line between 2 arbitrary points
1269 ***************************************************************************************/
1270 
1271 // Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer to use
1272 // an eficient FastH/V Line draw routine for line segments of 2 pixels or more
1273 // enhanced further using code from Xark and Spellbuilder (116 byte penalty)
1274 
1275 // Select which version, fastest or compact
1276 #ifdef FAST_LINE
1277 
1278 void TFT_ST7735::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
1279 {
1280  spi_begin();
1281 
1282  int8_t steep = abs(y1 - y0) > abs(x1 - x0);
1283 
1284  if (steep) {
1285  tftswap(x0, y0);
1286  tftswap(x1, y1);
1287  }
1288 
1289  if (x0 > x1) {
1290  tftswap(x0, x1);
1291  tftswap(y0, y1);
1292  }
1293 
1294  if (x1 < 0) return;
1295 
1296  int16_t dx, dy;
1297  dx = x1 - x0;
1298  dy = abs(y1 - y0);
1299 
1300  int16_t err = dx / 2;
1301  int8_t ystep = (y0 < y1) ? 1 : (-1);
1302 
1303  if (steep) // y increments every iteration (y0 is x-axis, and x0 is y-axis)
1304  {
1305  if (x1 >= _height) x1 = _height - 1;
1306 
1307  for (; x0 <= x1; x0++) {
1308  if ((x0 >= 0) && (y0 >= 0) && (y0 < _width)) break;
1309  err -= dy;
1310  if (err < 0) {
1311  err += dx;
1312  y0 += ystep;
1313  }
1314  }
1315 
1316  if (x0 > x1) return;
1317 
1318  setWindow(y0, x0, y0, _height);
1319  for (; x0 <= x1; x0++) {
1320  spiWrite16s(color);
1321  err -= dy;
1322  if (err < 0) {
1323  y0 += ystep;
1324  if ((y0 < 0) || (y0 >= _width)) break;
1325  err += dx;
1326  //while (!(SPSR & _BV(SPIF))); // Safe, but can comment out and rely on delay
1327  setWindow(y0, x0+1, y0, _height);
1328  }
1329  }
1330  }
1331  else // x increments every iteration (x0 is x-axis, and y0 is y-axis)
1332  {
1333  if (x1 >= _width) x1 = _width - 1;
1334 
1335  for (; x0 <= x1; x0++) {
1336  if ((x0 >= 0) && (y0 >= 0) && (y0 < _height)) break;
1337  err -= dy;
1338  if (err < 0) {
1339  err += dx;
1340  y0 += ystep;
1341  }
1342  }
1343 
1344  if (x0 > x1) return;
1345 
1346  setWindow(x0, y0, _width, y0);
1347  for (; x0 <= x1; x0++) {
1348  spiWrite16s(color);
1349  err -= dy;
1350  if (err < 0) {
1351  y0 += ystep;
1352  if ((y0 < 0) || (y0 >= _height)) break;
1353  err += dx;
1354  //while (!(SPSR & _BV(SPIF))); // Safe, but can comment out and rely on delay
1355  setWindow(x0+1, y0, _width, y0);
1356  }
1357  }
1358  }
1359  TFT_CS_H;
1360  spi_end();
1361 }
1362 
1363 #else // FAST_LINE not defined so use more compact version
1364 
1365 // Slower but more compact line drawing function
1366 void TFT_ST7735::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
1367 {
1368  int8_t steep = abs(y1 - y0) > abs(x1 - x0);
1369  if (steep) {
1370  tftswap(x0, y0);
1371  tftswap(x1, y1);
1372  }
1373 
1374  if (x0 > x1) {
1375  tftswap(x0, x1);
1376  tftswap(y0, y1);
1377  }
1378 
1379  int16_t dx = x1 - x0, dy = abs(y1 - y0);;
1380 
1381 
1382  int16_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0;
1383  if (y0 < y1) ystep = 1;
1384 
1385  // Split into steep and not steep for FastH/V separation
1386  if (steep) {
1387  for (; x0 <= x1; x0++) {
1388  dlen++;
1389  err -= dy;
1390  if (err < 0) {
1391  err += dx;
1392  if (dlen == 1) drawPixel(y0, xs, color);
1393  else drawFastVLine(y0, xs, dlen, color);
1394  dlen = 0; y0 += ystep; xs = x0 + 1;
1395  }
1396  }
1397  if (dlen) drawFastVLine(y0, xs, dlen, color);
1398  }
1399  else
1400  {
1401  for (; x0 <= x1; x0++) {
1402  dlen++;
1403  err -= dy;
1404  if (err < 0) {
1405  err += dx;
1406  if (dlen == 1) drawPixel(xs, y0, color);
1407  else drawFastHLine(xs, y0, dlen, color);
1408  dlen = 0; y0 += ystep; xs = x0 + 1;
1409  }
1410  }
1411  if (dlen) drawFastHLine(xs, y0, dlen, color);
1412  }
1413 }
1414 
1415 #endif // FAST_LINE option
1416 
1417 /***************************************************************************************
1418 ** Function name: drawFastVLine
1419 ** Description: draw a vertical line
1420 ***************************************************************************************/
1421 void TFT_ST7735::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
1422 {
1423 #ifdef CLIP_CHECK
1424  // Rudimentary clipping
1425  if ((x >= _width) || (y >= _height)) return;
1426  if ((y + h - 1) >= _height) h = _height - y;
1427 #endif
1428 
1429  spi_begin();
1430 
1431  setWindow(x, y, x, _height);
1432 
1433  spiWrite16(color, h);
1434  TFT_CS_H;
1435 
1436  spi_end();
1437 }
1438 
1439 /***************************************************************************************
1440 ** Function name: drawFastHLine
1441 ** Description: draw a horizontal line
1442 ***************************************************************************************/
1443 void TFT_ST7735::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
1444 {
1445 #ifdef CLIP_CHECK
1446  // Rudimentary clipping
1447  if ((x >= _width) || (y >= _height)) return;
1448  if ((x + w - 1) >= _width) w = _width - x;
1449 #endif
1450 
1451  spi_begin();
1452  setWindow(x, y, _width, y);
1453 
1454  spiWrite16(color, w);
1455  TFT_CS_H;
1456 
1457  spi_end();
1458 }
1459 
1460 /***************************************************************************************
1461 ** Function name: fillRect
1462 ** Description: draw a filled rectangle
1463 ***************************************************************************************/
1464 void TFT_ST7735::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
1465 {
1466 #ifdef CLIP_CHECK
1467  // rudimentary clipping (drawChar w/big text requires this)
1468  if ((x > _width) || (y > _height) || (w==0) || (h==0)) return;
1469  if ((x + w - 1) > _width) w = _width - x;
1470  if ((y + h - 1) > _height) h = _height - y;
1471 #endif
1472 
1473  spi_begin();
1474  setWindow(x, y, x + w - 1, y + h - 1);
1475 
1476  if (h > w) tftswap(h, w);
1477 
1478  while (h--) spiWrite16(color, w);
1479  TFT_CS_H;
1480 
1481  spi_end();
1482 }
1483 
1484 /***************************************************************************************
1485 ** Function name: color565
1486 ** Description: convert three 8 bit RGB levels to a 16 bit colour value
1487 ***************************************************************************************/
1488 uint16_t TFT_ST7735::color565(uint8_t r, uint8_t g, uint8_t b)
1489 {
1490  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
1491 }
1492 
1493 /***************************************************************************************
1494 ** Function name: setRotation
1495 ** Description: rotate the screen orientation m = 0-3 or 4-7 for BMP drawing
1496 ***************************************************************************************/
1497 
1498 #define MADCTL_MY 0x80
1499 #define MADCTL_MX 0x40
1500 #define MADCTL_MV 0x20
1501 #define MADCTL_ML 0x10
1502 #define MADCTL_RGB 0x00
1503 #define MADCTL_BGR 0x08
1504 #define MADCTL_MH 0x04
1505 
1507 {
1508  byte spsr = SPSR;// We need this here for some reason...
1509  addr_row = 0xFF;
1510  addr_col = 0xFF;
1511 
1512  rotation = m % 4;
1513  spi_begin();
1515  switch (rotation) {
1516  case 0:
1517  if (tabcolor == INITR_BLACKTAB) {
1519  } else if(tabcolor == INITR_GREENTAB2) {
1521  colstart = 2;
1522  rowstart = 1;
1523  } else {
1525  }
1528  break;
1529  case 1:
1530  if (tabcolor == INITR_BLACKTAB) {
1532  } else if(tabcolor == INITR_GREENTAB2) {
1534  colstart = 1;
1535  rowstart = 2;
1536  } else {
1538  }
1541  break;
1542  case 2:
1543  if (tabcolor == INITR_BLACKTAB) {
1545  } else if(tabcolor == INITR_GREENTAB2) {
1547  colstart = 2;
1548  rowstart = 1;
1549  } else {
1551  }
1554  break;
1555  case 3:
1556  if (tabcolor == INITR_BLACKTAB) {
1558  } else if(tabcolor == INITR_GREENTAB2) {
1560  colstart = 1;
1561  rowstart = 2;
1562  } else {
1564  }
1567  break;
1568 
1569  // These next rotations are for bottum up BMP drawing
1570  /* case 4:
1571  writedata(ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_BGR);
1572  _width = ST7735_TFTWIDTH;
1573  _height = ST7735_TFTHEIGHT;
1574  break;
1575  case 5:
1576  writedata(ST7735_MADCTL_MV | ST7735_MADCTL_MX | ST7735_MADCTL_BGR);
1577  _width = ST7735_TFTHEIGHT;
1578  _height = ST7735_TFTWIDTH;
1579  break;
1580  case 6:
1581  writedata(ST7735_MADCTL_BGR);
1582  _width = ST7735_TFTWIDTH;
1583  _height = ST7735_TFTHEIGHT;
1584  break;
1585  case 7:
1586  writedata(ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_BGR);
1587  _width = ST7735_TFTHEIGHT;
1588  _height = ST7735_TFTWIDTH;
1589  break;
1590  */
1591  }
1592  spi_end();
1593 }
1594 
1595 /***************************************************************************************
1596 ** Function name: invertDisplay
1597 ** Description: invert the display colours i = 1 invert, i = 0 normal
1598 ***************************************************************************************/
1600 {
1601  spi_begin();
1602  // Send the command twice as otherwise it does not always work!
1604  writecommand(i ? ST7735_INVON : ST7735_INVOFF);
1605  spi_end();
1606 }
1607 
1608 /***************************************************************************************
1609 ** Function name: write
1610 ** Description: draw characters piped through serial stream
1611 ***************************************************************************************/
1612 size_t TFT_ST7735::write(uint8_t uniCode)
1613 {
1614  if (uniCode == '\r') return 1;
1615  unsigned int width = 0;
1616  unsigned int height = 0;
1617  //Serial.print((char) uniCode); // Debug line sends all printed TFT text to serial port
1618 
1619 #ifdef LOAD_FONT2
1620  if (textfont == 2)
1621  {
1622  // This is 20us faster than using the fontdata structure (0.443ms per character instead of 0.465ms)
1623  width = pgm_read_byte(widtbl_f16 + uniCode-32);
1624  height = chr_hgt_f16;
1625  // Font 2 is rendered in whole byte widths so we must allow for this
1626  width = (width + 6) / 8; // Width in whole bytes for font 2, should be + 7 but must allow for font width change
1627  width = width * 8; // Width converted back to pixles
1628  }
1629  #ifdef LOAD_RLE
1630  else
1631  #endif
1632 #endif
1633 
1634 
1635 #ifdef LOAD_RLE
1636  {
1637  // Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements
1638  // A tad slower than above but this is not significant and is more convenient for the RLE fonts
1639  // Yes, this code can be needlessly executed when textfont == 1...
1640  width = pgm_read_byte( pgm_read_word( &(fontdata[textfont].widthtbl ) ) + uniCode-32 );
1641  height= pgm_read_byte( &fontdata[textfont].height );
1642  }
1643 #endif
1644 
1645 #ifdef LOAD_GLCD
1646  if (textfont==1)
1647  {
1648  width = 6;
1649  height = 8;
1650  }
1651 #else
1652  if (textfont==1) return 0;
1653 #endif
1654 
1655  height = height * textsize;
1656 
1657  if (uniCode == '\n') {
1658  cursor_y += height;
1659  cursor_x = 0;
1660  }
1661  else
1662  {
1663  if (textwrap && (cursor_x + width * textsize >= _width))
1664  {
1665  cursor_y += height;
1666  cursor_x = 0;
1667  }
1668  cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont);
1669  }
1670  return 1;
1671 }
1672 
1673 /***************************************************************************************
1674 ** Function name: drawChar
1675 ** Description: draw a unicode onto the screen
1676 ***************************************************************************************/
1677 int TFT_ST7735::drawChar(unsigned int uniCode, int x, int y, int font)
1678 {
1679 
1680  if (font==1)
1681  {
1682 #ifdef LOAD_GLCD
1683  drawChar(x, y, uniCode, textcolor, textbgcolor, textsize);
1684  return 6 * textsize;
1685 #else
1686  return 0;
1687 #endif
1688  }
1689 
1690  unsigned int width = 0;
1691  unsigned int height = 0;
1692  unsigned int flash_address = 0; // 16 bit address OK for Arduino if font files <60K
1693  uniCode -= 32;
1694 
1695 #ifdef LOAD_FONT2
1696  if (font == 2)
1697  {
1698  // This is 20us faster than using the fontdata structure (0.413ms per character instead of 0.433ms)
1699  flash_address = pgm_read_word(&chrtbl_f16[uniCode]);
1700  width = pgm_read_byte(widtbl_f16 + uniCode);
1701  height = chr_hgt_f16;
1702  }
1703  #ifdef LOAD_RLE
1704  else
1705  #endif
1706 #endif
1707 
1708 #ifdef LOAD_RLE
1709  {
1710  // This is slower than above but is more convenient for the RLE fonts
1711  flash_address = pgm_read_word( pgm_read_word( &(fontdata[font].chartbl ) ) + uniCode*sizeof(void *) );
1712  width = pgm_read_byte( pgm_read_word( &(fontdata[font].widthtbl ) ) + uniCode );
1713  height= pgm_read_byte( &fontdata[font].height );
1714  }
1715 #endif
1716 
1717  int w = width;
1718  int pX = 0;
1719  int pY = y;
1720  byte line = 0;
1721 
1722  byte tl = textcolor;
1723  byte th = textcolor >> 8;
1724  byte bl = textbgcolor;
1725  byte bh = textbgcolor >> 8;
1726 
1727 #ifdef LOAD_FONT2 // chop out 962 bytes of code if we do not need it
1728  if (font == 2) {
1729  w = w + 6; // Should be + 7 but we need to compensate for width increment
1730  w = w / 8;
1731  if (x + width * textsize >= _width) return width * textsize ;
1732 
1733  if (textcolor == textbgcolor || textsize != 1) {
1734 
1735  for (int i = 0; i < height; i++)
1736  {
1737  if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize, textbgcolor);
1738 
1739  for (int k = 0; k < w; k++)
1740  {
1741  line = pgm_read_byte(flash_address + w * i + k);
1742  if (line) {
1743  if (textsize == 1) {
1744  pX = x + k * 8;
1745  if (line & 0x80) drawPixel(pX, pY, textcolor);
1746  if (line & 0x40) drawPixel(pX + 1, pY, textcolor);
1747  if (line & 0x20) drawPixel(pX + 2, pY, textcolor);
1748  if (line & 0x10) drawPixel(pX + 3, pY, textcolor);
1749  if (line & 0x08) drawPixel(pX + 4, pY, textcolor);
1750  if (line & 0x04) drawPixel(pX + 5, pY, textcolor);
1751  if (line & 0x02) drawPixel(pX + 6, pY, textcolor);
1752  if (line & 0x01) drawPixel(pX + 7, pY, textcolor);
1753  }
1754  else {
1755  pX = x + k * 8 * textsize;
1756  if (line & 0x80) fillRect(pX, pY, textsize, textsize, textcolor);
1757  if (line & 0x40) fillRect(pX + textsize, pY, textsize, textsize, textcolor);
1758  if (line & 0x20) fillRect(pX + 2 * textsize, pY, textsize, textsize, textcolor);
1759  if (line & 0x10) fillRect(pX + 3 * textsize, pY, textsize, textsize, textcolor);
1760  if (line & 0x08) fillRect(pX + 4 * textsize, pY, textsize, textsize, textcolor);
1761  if (line & 0x04) fillRect(pX + 5 * textsize, pY, textsize, textsize, textcolor);
1762  if (line & 0x02) fillRect(pX + 6 * textsize, pY, textsize, textsize, textcolor);
1763  if (line & 0x01) fillRect(pX + 7 * textsize, pY, textsize, textsize, textcolor);
1764  }
1765  }
1766  }
1767  pY += textsize;
1768  }
1769  }
1770  else
1771  // Faster drawing of characters and background using block write
1772  {
1773  spi_begin();
1774  setWindow(x, y, (x + w * 8) - 1, y + height - 1);
1775 
1776  byte mask;
1777  for (int i = 0; i < height; i++)
1778  {
1779  for (int k = 0; k < w; k++)
1780  {
1781  line = pgm_read_byte(flash_address + w * i + k);
1782  pX = x + k * 8;
1783  mask = 0x80;
1784  while (mask) {
1785  if (line & mask) {
1786  while (!(SPSR & _BV(SPIF)));
1787  SPDR = th; asm volatile( "nop\n\t" ::);
1788  while (!(SPSR & _BV(SPIF)));
1789  SPDR = tl;
1790  }
1791  else {
1792  while (!(SPSR & _BV(SPIF)));
1793  SPDR = bh; asm volatile( "nop\n\t" ::);
1794  while (!(SPSR & _BV(SPIF)));
1795  SPDR = bl;
1796  }
1797  mask = mask >> 1;
1798  }
1799  }
1800  pY += textsize;
1801  }
1802  while (!(SPSR & _BV(SPIF)));
1803  writeEnd();
1804  spi_end();
1805  }
1806  }
1807 
1808  #ifdef LOAD_RLE
1809  else
1810  #endif
1811 #endif //FONT2
1812 
1813 #ifdef LOAD_RLE //674 bytes of code
1814  // Font is not 2 and hence is RLE encoded
1815  {
1816  spi_begin();
1817  SPDR = 0; // Dummy write to ensure SPIF flag gets set for first check in while() loop
1818  w *= height; // Now w is total number of pixels in the character
1819  if ((textsize != 1) || (textcolor == textbgcolor)) {
1820  if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor);
1821  int px = 0, py = pY, tpy = pY; // To hold character block start and end column and row values
1822  int pc = 0; // Pixel count
1823  byte np = textsize * textsize; // Number of pixels in a drawn pixel
1824 
1825  byte tnp = 0; // Temporary copy of np for while loop
1826  byte ts = textsize - 1; // Temporary copy of textsize
1827  // 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area
1828  // w is total number of pixels to plot to fill character block
1829  while (pc < w)
1830  {
1831  line = pgm_read_byte(flash_address);
1832  flash_address++; // 20 bytes smaller by incrementing here
1833  if (line & 0x80) {
1834  line &= 0x7F;
1835  line++;
1836  if (ts) {
1837  px = x + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow
1838  py = y + textsize * (pc / width);
1839  }
1840  else {
1841  px = x + pc % width; // Keep these px and py calculations outside the loop as they are slow
1842  py = y + pc / width;
1843  }
1844  while (line--) { // In this case the while(line--) is faster
1845  pc++; // This is faster than putting pc+=line before while() as we use up SPI wait time
1846  while (!(SPSR & _BV(SPIF)));
1847  setWindow(px, py, px + ts, py + ts);
1848 
1849  if (ts) {
1850  tnp = np;
1851  while (tnp--) {
1852  while (!(SPSR & _BV(SPIF)));
1853  SPDR = th;
1854  while (!(SPSR & _BV(SPIF)));
1855  SPDR = tl;
1856  }
1857  }
1858  else {
1859  while (!(SPSR & _BV(SPIF)));
1860  SPDR = th;
1861  while (!(SPSR & _BV(SPIF)));
1862  SPDR = tl;
1863  }
1864  px += textsize;
1865 
1866  if (px >= (x + width * textsize))
1867  {
1868  px = x;
1869  py += textsize;
1870  }
1871  }
1872  }
1873  else {
1874  line++;
1875  pc += line;
1876  }
1877  }
1878  while (!(SPSR & _BV(SPIF)));
1879  writeEnd();
1880  spi_end();
1881  }
1882  else // Text colour != background && textsize = 1
1883  // so use faster drawing of characters and background using block write
1884  {
1885  spi_begin();
1886  setWindow(x, y, x + width - 1, y + height - 1);
1887 
1888  // Maximum font size is equivalent to 180x180 pixels in area
1889  while (w > 0)
1890  {
1891  line = pgm_read_byte(flash_address++); // 8 bytes smaller when incrementing here
1892  if (line & 0x80) {
1893  line &= 0x7F;
1894  line++; w -= line;
1895  spiWrite16(textcolor, line);
1896  }
1897  else {
1898  line++; w -= line;
1899  spiWrite16(textbgcolor, line);
1900  }
1901  }
1902  while (!(SPSR & _BV(SPIF)));
1903  writeEnd();
1904  spi_end();
1905  }
1906  }
1907  // End of RLE font rendering
1908 #endif
1909  return width * textsize; // x +
1910 }
1911 
1912 /***************************************************************************************
1913 ** Function name: drawString
1914 ** Description : draw string with padding if it is defined
1915 ***************************************************************************************/
1916 int TFT_ST7735::drawString(char *string, int poX, int poY, int font)
1917 {
1918  int16_t sumX = 0;
1919  uint8_t padding = 1;
1920  unsigned int cheight = 0;
1921 
1922  if (textdatum || padX)
1923  {
1924  // Find the pixel width of the string in the font
1925  unsigned int cwidth = textWidth(string, font);
1926 
1927  // Get the pixel height of the font
1928  cheight = pgm_read_byte( &fontdata[font].height ) * textsize;
1929 
1930  switch(textdatum) {
1931  case TC_DATUM:
1932  poX -= cwidth/2;
1933  padding = 2;
1934  break;
1935  case TR_DATUM:
1936  poX -= cwidth;
1937  padding = 3;
1938  break;
1939  case ML_DATUM:
1940  poY -= cheight/2;
1941  padding = 1;
1942  break;
1943  case MC_DATUM:
1944  poX -= cwidth/2;
1945  poY -= cheight/2;
1946  padding = 2;
1947  break;
1948  case MR_DATUM:
1949  poX -= cwidth;
1950  poY -= cheight/2;
1951  padding = 3;
1952  break;
1953  case BL_DATUM:
1954  poY -= cheight;
1955  padding = 1;
1956  break;
1957  case BC_DATUM:
1958  poX -= cwidth/2;
1959  poY -= cheight;
1960  padding = 2;
1961  break;
1962  case BR_DATUM:
1963  poX -= cwidth;
1964  poY -= cheight;
1965  padding = 3;
1966  break;
1967  }
1968  // Check coordinates are OK, adjust if not
1969  if (poX < 0) poX = 0;
1970  if (poX+cwidth>_width) poX = _width - cwidth;
1971  if (poY < 0) poY = 0;
1972  if (poY+cheight>_height) poY = _height - cheight;
1973  }
1974 
1975  while (*string) sumX += drawChar(*(string++), poX+sumX, poY, font);
1976 
1977 //#define PADDING_DEBUG
1978 
1979 #ifndef PADDING_DEBUG
1980  if((padX>sumX) && (textcolor!=textbgcolor))
1981  {
1982  int padXc = poX+sumX; // Maximum left side padding
1983  switch(padding) {
1984  case 1:
1985  fillRect(padXc,poY,padX-sumX,cheight, textbgcolor);
1986  break;
1987  case 2:
1988  fillRect(padXc,poY,(padX-sumX)>>1,cheight, textbgcolor);
1989  padXc = (padX-sumX)>>1;
1990  if (padXc>poX) padXc = poX;
1991  fillRect(poX - padXc,poY,(padX-sumX)>>1,cheight, textbgcolor);
1992  break;
1993  case 3:
1994  if (padXc>padX) padXc = padX;
1995  fillRect(poX + sumX - padXc,poY,padXc-sumX,cheight, textbgcolor);
1996  break;
1997  }
1998  }
1999 #else
2000 
2001  // This is debug code to show text (green box) and blanked (white box) areas
2002  // to show that the padding areas are being correctly sized and positioned
2003  if((padX>sumX) && (textcolor!=textbgcolor))
2004  {
2005  int padXc = poX+sumX; // Maximum left side padding
2006  drawRect(poX,poY,sumX,cheight, TFT_GREEN);
2007  switch(padding) {
2008  case 1:
2009  drawRect(padXc,poY,padX-sumX,cheight, TFT_WHITE);
2010  break;
2011  case 2:
2012  drawRect(padXc,poY,(padX-sumX)>>1, cheight, TFT_WHITE);
2013  padXc = (padX-sumX)>>1;
2014  if (padXc>poX) padXc = poX;
2015  drawRect(poX - padXc,poY,(padX-sumX)>>1,cheight, TFT_WHITE);
2016  break;
2017  case 3:
2018  if (padXc>padX) padXc = padX;
2019  drawRect(poX + sumX - padXc,poY,padXc-sumX,cheight, TFT_WHITE);
2020  break;
2021  }
2022  }
2023 #endif
2024 
2025 return sumX;
2026 }
2027 
2028 /***************************************************************************************
2029 ** Function name: drawCentreString
2030 ** Descriptions: draw string centred on dX
2031 ***************************************************************************************/
2032 int TFT_ST7735::drawCentreString(char *string, int dX, int poY, int font)
2033 {
2034  byte tempdatum = textdatum;
2035  int sumX = 0;
2036  textdatum = TC_DATUM;
2037  sumX = drawString(string, dX, poY, font);
2038  textdatum = tempdatum;
2039  return sumX;
2040 }
2041 
2042 /***************************************************************************************
2043 ** Function name: drawRightString
2044 ** Descriptions: draw string right justified to dX
2045 ***************************************************************************************/
2046 int TFT_ST7735::drawRightString(char *string, int dX, int poY, int font)
2047 {
2048  byte tempdatum = textdatum;
2049  int sumX = 0;
2050  textdatum = TR_DATUM;
2051  sumX = drawString(string, dX, poY, font);
2052  textdatum = tempdatum;
2053  return sumX;
2054 }
2055 
2056 /***************************************************************************************
2057 ** Function name: drawNumber
2058 ** Description: draw a long integer
2059 ***************************************************************************************/
2060 int TFT_ST7735::drawNumber(long long_num, int poX, int poY, int font)
2061 {
2062  char str[12];
2063  ltoa(long_num, str, 10);
2064  return drawString(str, poX, poY, font);
2065 }
2066 
2067 /***************************************************************************************
2068 ** Function name: drawFloat
2069 ** Descriptions: drawFloat, prints 7 non zero digits maximum
2070 ***************************************************************************************/
2071 // Adapted to assemble and print a string, this permits alignment relative to a datum
2072 // looks complicated but much more compact and actually faster than using print class
2073 int TFT_ST7735::drawFloat(float floatNumber, int dp, int poX, int poY, int font)
2074 {
2075  char str[14]; // Array to contain decimal string
2076  uint8_t ptr = 0; // Initialise pointer for array
2077  int8_t digits = 1; // Count the digits to avoid array overflow
2078  float rounding = 0.5; // Round up down delta
2079 
2080  if (dp > 7) dp = 7; // Limit the size of decimal portion
2081 
2082  // Adjust the rounding value
2083  for (uint8_t i = 0; i < dp; ++i) rounding /= 10.0;
2084 
2085  if (floatNumber < -rounding) // add sign, avoid adding - sign to 0.0!
2086  {
2087  str[ptr++] = '-'; // Negative number
2088  str[ptr] = 0; // Put a null in the array as a precaution
2089  digits = 0; // Set digits to 0 to compensate so pointer value can be used later
2090  floatNumber = -floatNumber; // Make positive
2091  }
2092 
2093  floatNumber += rounding; // Round up or down
2094 
2095  // For error put ... in string and return (all TFT_ST7735 library fonts contain . character)
2096  if (floatNumber >= 2147483647) {
2097  strcpy(str, "...");
2098  return drawString(str, poX, poY, font);
2099  }
2100  // No chance of overflow from here on
2101 
2102  // Get integer part
2103  unsigned long temp = (unsigned long)floatNumber;
2104 
2105  // Put integer part into array
2106  ltoa(temp, str + ptr, 10);
2107 
2108  // Find out where the null is to get the digit count loaded
2109  while ((uint8_t)str[ptr] != 0) ptr++; // Move the pointer along
2110  digits += ptr; // Count the digits
2111 
2112  str[ptr++] = '.'; // Add decimal point
2113  str[ptr] = '0'; // Add a dummy zero
2114  str[ptr + 1] = 0; // Add a null but don't increment pointer so it can be overwritten
2115 
2116  // Get the decimal portion
2117  floatNumber = floatNumber - temp;
2118 
2119  // Get decimal digits one by one and put in array
2120  // Limit digit count so we don't get a false sense of resolution
2121  uint8_t i = 0;
2122  while ((i < dp) && (digits < 9)) // while (i < dp) for no limit but array size must be increased
2123  {
2124  i++;
2125  floatNumber *= 10; // for the next decimal
2126  temp = floatNumber; // get the decimal
2127  ltoa(temp, str + ptr, 10);
2128  ptr++; digits++; // Increment pointer and digits count
2129  floatNumber -= temp; // Remove that digit
2130  }
2131 
2132  // Finally we can plot the string and return pixel length
2133  return drawString(str, poX, poY, font);
2134 }
2135 
2136 /***************************************************************************************
2137 ** Function name: spiWrite16
2138 ** Descriptions: Delay based assembler loop for fast SPI write
2139 ***************************************************************************************/
2140 inline void spiWrite16(uint16_t data, int16_t count)
2141 {
2142 // We can enter this loop with 0 pixels to draw, so we need to check this
2143 // if(count<1) { Serial.print("#### Less than 1 ####"); Serial.println(count);}
2144 
2145  uint8_t temp;
2146  asm volatile
2147  (
2148  " sbiw %[count],0\n" // test count
2149  //" brmi 2f\n" // if < 0 then done
2150  " breq 2f\n" // if == 0 then done
2151 
2152  "1: out %[spi],%[hi]\n" // write SPI data
2153  " rcall 3f \n" // 7
2154  " rcall 3f \n" // 14
2155  " rjmp 4f \n" // 16
2156  "3: ret \n" //
2157  "4: nop \n" // 17
2158 
2159  " out %[spi],%[lo]\n" // write SPI data
2160 
2161  " adiw r24,0 \n" // 2
2162  " adiw r24,0 \n" // 4
2163  " rcall 5f \n" // 11
2164  " rjmp 6f \n" // 13
2165  "5: ret \n" //
2166  "6: \n"
2167 
2168  " sbiw %[count],1 \n" // 15 decrement count
2169  " brne 1b \n" // 17 if != 0 then loop
2170 
2171  "2:\n"
2172 
2173  : [temp] "=d" (temp), [count] "+w" (count)
2174  : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8))
2175  :
2176  );
2177 }
2178 
2179 /***************************************************************************************
2180 ** Function name: spiWrite16s
2181 ** Descriptions: Write 16 bits, do not wait after last byte sent
2182 ***************************************************************************************/
2183 inline void spiWrite16s(uint16_t data)
2184 {
2185  uint8_t temp;
2186  asm volatile
2187  (
2188  "out %[spi],%[hi]\n" // write SPI data
2189  " rcall 3f \n" // 7
2190  " rcall 3f \n" // 14
2191  " rjmp 4f \n" // 16
2192  "3: ret \n" //
2193  "4: nop \n" // 17
2194 
2195  " out %[spi],%[lo]\n" // write SPI data
2196  " nop \n" // 1
2197 
2198  " adiw r24,0 \n" // 3
2199  " adiw r24,0 \n" // 5
2200 
2201  "5:\n"
2202  : [temp] "=d" (temp)
2203  : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8))
2204  :
2205  );
2206 }
2207 
2208 
2209 /***************************************************************************************
2210 ** Function name: spiWrite16R with hi<>lo reversed (not used)
2211 ** Descriptions: Delay based assembler loop for fast SPI write
2212 ***************************************************************************************/
2213 inline void spiWrite16R(uint16_t data, int16_t count)
2214 {
2215 // We can enter this loop with 0 pixels to draw, so we need to check this
2216 // if(count<1) { Serial.print("#### Less than 1 ####"); Serial.println(count);}
2217 
2218  uint8_t temp;
2219  asm volatile
2220  (
2221  "sbiw %[count],0 \n" // test count
2222  //"brmi 2f \n" // if < 0 then done, we use unsigned though
2223  " breq 2f \n" // if == 0 then done
2224 
2225  "1: out %[spi],%[hi]\n" // write SPI data
2226 
2227  " rcall 3f \n" // 7
2228  " rcall 3f \n" // 14
2229  " rjmp 4f \n" // 16
2230  "3: ret \n" //
2231  "4: nop \n" // 17
2232 
2233  " out %[spi],%[lo]\n" // write SPI data
2234 
2235  " adiw r24,0 \n" // 2
2236  " adiw r24,0 \n" // 4
2237  " rcall 5f \n" // 11
2238  " rjmp 6f \n" // 13
2239  "5: ret \n" //
2240  "6: \n"
2241 
2242  " sbiw %[count],1 \n" // 15 decrement count
2243  " brne 1b \n" // 17 if != 0 then loop
2244 
2245  "2:\n"
2246 
2247  : [temp] "=d" (temp), [count] "+w" (count)
2248  : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)(data>>8)), [hi] "r" ((uint8_t)data)
2249  :
2250  );
2251 }
2252 
2253 /***************************************************************************************
2254 ** Function name: spiWait
2255 ** Descriptions: 17 cycle delay
2256 ***************************************************************************************/
2257 inline void spiWait17(void)
2258 {
2259  asm volatile
2260  (
2261  " rcall 1f \n" // 7
2262  " rcall 1f \n" // 14
2263  " rjmp 2f \n" // 16
2264  "1: ret \n" //
2265  "2: nop \n" // 17
2266  );
2267 }
2268 
2269 /***************************************************************************************
2270 ** Function name: spiWait
2271 ** Descriptions: 15 cycle delay
2272 ***************************************************************************************/
2273 inline void spiWait15(void)
2274 {
2275  asm volatile
2276  (
2277  " adiw r24,0 \n" // 2
2278  " adiw r24,0 \n" // 4
2279  " adiw r24,0 \n" // 6
2280  " rcall 1f \n" // 13
2281  " rjmp 2f \n" // 15
2282  "1: ret \n" //
2283  "2: \n" //
2284  );
2285 }
2286 
2287 /***************************************************************************************
2288 ** Function name: spiWait
2289 ** Descriptions: 14 cycle delay
2290 ***************************************************************************************/
2291 inline void spiWait14(void)
2292 {
2293  asm volatile
2294  (
2295  " nop \n" // 1
2296  " adiw r24,0 \n" // 3
2297  " adiw r24,0 \n" // 5
2298  " rcall 1f \n" // 12
2299  " rjmp 2f \n" // 14
2300  "1: ret \n" //
2301  "2: \n" //
2302  );
2303 }
2304 
2305 /***************************************************************************************
2306 ** Function name: spiWait
2307 ** Descriptions: 12 cycle delay
2308 ***************************************************************************************/
2309 inline void spiWait12(void)
2310 {
2311  asm volatile
2312  (
2313  " nop \n" // 1
2314  " adiw r24,0 \n" // 3
2315  " rcall 1f \n" // 10
2316  " rjmp 2f \n" // 12
2317  "1: ret \n" //
2318  "2: \n" //
2319  );
2320 }
2321 
2322 /***************************************************
2323 
2324  ORIGINAL LIBRARY HEADER
2325 
2326  This is our library for the Adafruit ST7735 Breakout and Shield
2327  ----> http://www.adafruit.com/products/1651
2328 
2329  Check out the links above for our tutorials and wiring diagrams
2330  These displays use SPI to communicate, 4 or 5 pins are required to
2331  interface (RST is optional)
2332  Adafruit invests time and resources providing this open source code,
2333  please support Adafruit and open-source hardware by purchasing
2334  products from Adafruit!
2335 
2336  Written by Limor Fried/Ladyada for Adafruit Industries.
2337  MIT license, all text above must be included in any redistribution
2338 
2339  ****************************************************/
void setTextDatum(uint8_t datum)
Definition: TFT_ST7735.cpp:878
int16_t textWidth(char *string, int font)
Definition: TFT_ST7735.cpp:924
int16_t drawString(char *string, int poX, int poY, int font)
#define ST7735_VMCTR1
Definition: TFT_ST7735.h:147
void setTextSize(uint8_t size)
Definition: TFT_ST7735.cpp:829
#define MADCTL_MV
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
#define TFT_RST
Definition: User_Setup.h:27
#define MR_DATUM
Definition: TFT_ST7735.h:93
void setRotation(uint8_t r)
#define ST7735_CASET
Definition: TFT_ST7735.h:127
int16_t drawRightString(char *string, int dX, int poY, int font)
#define ST7735_TFTWIDTH
Definition: TFT_ST7735.h:110
uint16_t color565(uint8_t r, uint8_t g, uint8_t b)
#define ST7735_FRMCTR2
Definition: TFT_ST7735.h:137
#define DELAY
Definition: TFT_ST7735.cpp:208
int16_t cursor_y
Definition: TFT_ST7735.h:362
int16_t height(void)
Definition: TFT_ST7735.cpp:915
boolean textwrap
Definition: TFT_ST7735.h:374
#define ST7735_INIT_DELAY
Definition: TFT_ST7735.h:105
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t font)
Definition: TFT_ST7735.cpp:970
uint8_t textsize
Definition: TFT_ST7735.h:369
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
uint16_t textcolor
Definition: TFT_ST7735.h:365
#define BL_DATUM
Definition: TFT_ST7735.h:95
#define TFT_CS_H
Definition: TFT_ST7735.h:82
#define INITB
Definition: TFT_ST7735.h:22
void spiWait14(void) __attribute__((always_inline))
void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
Definition: TFT_ST7735.cpp:516
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
Definition: TFT_ST7735.cpp:438
void fillEllipse(int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint16_t color)
Definition: TFT_ST7735.cpp:604
#define ST7735_TFTHEIGHT
Definition: TFT_ST7735.h:111
#define ST7735_FRMCTR3
Definition: TFT_ST7735.h:138
#define ST7735_RASET
Definition: TFT_ST7735.h:128
#define INITR_BLACKTAB
Definition: TFT_ST7735.h:20
void begin(void)
Definition: TFT_ST7735.cpp:199
void spiWrite16s(uint16_t data) __attribute__((always_inline))
#define MADCTL_BGR
int16_t width(void)
Definition: TFT_ST7735.cpp:906
int16_t drawCentreString(char *string, int dX, int poY, int font)
#define ST7735_SLPOUT
Definition: TFT_ST7735.h:119
#define ST7735_INVCTR
Definition: TFT_ST7735.h:139
#define MC_DATUM
Definition: TFT_ST7735.h:91
#define ST7735_NORON
Definition: TFT_ST7735.h:121
const PROGMEM fontinfo fontdata[]
Definition: TFT_ST7735.h:219
uint8_t addr_row
Definition: TFT_ST7735.h:367
#define ST7735_PWCTR1
Definition: TFT_ST7735.h:142
void spiWait12(void) __attribute__((always_inline))
#define ST7735_INVOFF
Definition: TFT_ST7735.h:123
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
Definition: TFT_ST7735.cpp:790
int16_t _height
Definition: TFT_ST7735.h:362
void spiwrite(uint8_t)
Definition: TFT_ST7735.cpp:102
void init(void)
Definition: TFT_ST7735.cpp:210
void writedata(uint8_t d)
Definition: TFT_ST7735.cpp:128
void setCursor(int16_t x, int16_t y)
Definition: TFT_ST7735.cpp:808
int16_t padX
Definition: TFT_ST7735.h:362
void drawEllipse(int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint16_t color)
Definition: TFT_ST7735.cpp:560
virtual size_t write(uint8_t)
#define TC_DATUM
Definition: TFT_ST7735.h:87
void pushColors(uint16_t *data, uint8_t len)
#define spi_begin()
Definition: TFT_ST7735.cpp:191
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
#define ST7735_PWCTR2
Definition: TFT_ST7735.h:143
#define ST7735_GMCTRP1
Definition: TFT_ST7735.h:156
#define ST7735_PWCTR5
Definition: TFT_ST7735.h:146
int16_t drawFloat(float floatNumber, int decimal, int poX, int poY, int font)
void spiWait17(void) __attribute__((always_inline))
uint16_t fontsloaded
Definition: TFT_ST7735.h:365
#define BR_DATUM
Definition: TFT_ST7735.h:97
uint8_t textfont
Definition: TFT_ST7735.h:369
#define TFT_DC_C
Definition: TFT_ST7735.h:81
void backupSPCR(void)
Definition: TFT_ST7735.cpp:148
uint8_t getRotation(void)
Definition: TFT_ST7735.cpp:896
void spiWrite16R(uint16_t data, int16_t count) __attribute__((always_inline))
#define BC_DATUM
Definition: TFT_ST7735.h:96
#define TFT_CS_L
Definition: TFT_ST7735.h:80
void fillScreen(uint16_t color)
Definition: TFT_ST7735.cpp:647
void pushColor(uint16_t color)
#define spi_end()
Definition: TFT_ST7735.cpp:192
#define ST7735_FRMCTR1
Definition: TFT_ST7735.h:136
#define INITR_GREENTAB2
Definition: TFT_ST7735.h:21
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color)
Definition: TFT_ST7735.cpp:527
#define TFT_CS
Definition: User_Setup.h:25
#define ST7735_PWCTR4
Definition: TFT_ST7735.h:145
#define ST7735_PWCTR6
Definition: TFT_ST7735.h:154
#define TAB_COLOUR
Definition: User_Setup.h:10
#define ST7735_COLMOD
Definition: TFT_ST7735.h:133
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color)
Definition: TFT_ST7735.cpp:670
#define TFT_WHITE
Definition: TFT_ST7735.h:184
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
Definition: TFT_ST7735.cpp:705
int16_t fontHeight(int font)
Definition: TFT_ST7735.cpp:961
#define MADCTL_MY
#define INITR_REDTAB
Definition: TFT_ST7735.h:19
void spiWait15(void) __attribute__((always_inline))
int16_t cursor_x
Definition: TFT_ST7735.h:362
#define ST7735_RAMWR
Definition: TFT_ST7735.h:129
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
Definition: TFT_ST7735.cpp:717
void setTextColor(uint16_t color)
Definition: TFT_ST7735.cpp:848
#define TR_DATUM
Definition: TFT_ST7735.h:88
void restoreSPCR(void)
Definition: TFT_ST7735.cpp:157
void setTextPadding(uint16_t x_width)
Definition: TFT_ST7735.cpp:887
void commandList(const uint8_t *addr)
Definition: TFT_ST7735.cpp:407
void writecommand(uint8_t c)
Definition: TFT_ST7735.cpp:116
void invertDisplay(boolean i)
void writeEnd(void)
Definition: TFT_ST7735.cpp:140
#define ST7735_INVON
Definition: TFT_ST7735.h:124
#define INITR_GREENTAB
Definition: TFT_ST7735.h:18
#define TFT_DC
Definition: User_Setup.h:26
uint16_t textbgcolor
Definition: TFT_ST7735.h:365
#define MADCTL_RGB
#define MADCTL_MX
uint8_t textdatum
Definition: TFT_ST7735.h:369
void setTextFont(uint8_t font)
Definition: TFT_ST7735.cpp:839
void setTextWrap(boolean wrap)
Definition: TFT_ST7735.cpp:869
uint8_t rotation
Definition: TFT_ST7735.h:369
uint8_t addr_col
Definition: TFT_ST7735.h:367
#define ST7735_DISSET5
Definition: TFT_ST7735.h:140
#define ST7735_SWRESET
Definition: TFT_ST7735.h:114
void spiWrite16(uint16_t data, int16_t count) __attribute__((always_inline))
#define ST7735_DISPON
Definition: TFT_ST7735.h:126
#define ST7735_GMCTRN1
Definition: TFT_ST7735.h:157
int16_t _width
Definition: TFT_ST7735.h:362
void setAddrWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
#define TFT_DC_D
Definition: TFT_ST7735.h:83
void drawPixel(uint16_t x, uint16_t y, uint16_t color)
void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color)
Definition: TFT_ST7735.cpp:476
uint16_t fontsLoaded(void)
Definition: TFT_ST7735.cpp:951
int16_t drawNumber(long long_num, int poX, int poY, int font)
#define TFT_GREEN
Definition: TFT_ST7735.h:179
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
#define ML_DATUM
Definition: TFT_ST7735.h:89
void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color)
Definition: TFT_ST7735.cpp:690
#define ST7735_PWCTR3
Definition: TFT_ST7735.h:144
void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
Definition: TFT_ST7735.cpp:657
#define ST7735_MADCTL
Definition: TFT_ST7735.h:134