ESP8266 ILI9341 display support code with printf sources, wire-frame viewer and custom fonts  1.0
ESP8266ILI9341DisplayProject
ili9341.c
Go to the documentation of this file.
1 
32 #include "user_config.h"
33 
34 #include <stdint.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <math.h>
38 
39 #include "display/font.h"
40 #include "display/ili9341.h"
42 
43 // TFT master window definition
46 
49 
53 void tft_Cmd(uint8_t cmd)
54 {
55  tft_spi_TX(&cmd, 1, 1);
56 }
57 
62 {
63  tft_spi_TXRX(&data, 1, 0);
64  return(data);
65 }
66 
72 void tft_Cmd_Data_TX(uint8_t cmd, uint8_t * data, int bytes)
73 {
74 // Do not change Command/Data control until SPI bus clear
75  tft_spi_begin();
76 
77  tft_Cmd(cmd);
78 
79 // Read result
80  if (bytes > 0)
81  {
82  tft_spi_TX(data,bytes,0);
83  }
84 
85  tft_spi_end();
86 }
87 
89 
93 
101 int32_t tft_abs_window(window *win, int16_t x, int16_t y, int16_t w, int16_t h)
102 {
103  uint8_t tmp[4];
104 
105  int16_t xl,yl;
106  int32_t bytes;
107 
108  // FIXME do we want to return or use the constrained values ????
109  if(tft_window_clip_args(win,&x,&y,&w,&h) )
110  return(0);
111 
112  // Now We know the result will fit
113  xl = x + w - 1;
114  tmp[0] = x >> 8;
115  tmp[1] = x & 0xff;
116  tmp[2] = xl >> 8;
117  tmp[3] = xl & 0xff;
118  tft_Cmd_Data_TX(0x2A, tmp, 4);
119 
120  yl = y + h - 1;
121  tmp[0] = y >> 8;
122  tmp[1] = y & 0xff;
123  tmp[2] = yl >> 8;
124  tmp[3] = yl & 0xff;
125  tft_Cmd_Data_TX(0x2B, tmp, 4);
126 
127  bytes = w;
128  bytes *= h;
129  return( bytes);
130 }
131 
140 int32_t tft_rel_window(window *win, int16_t x, int16_t y, int16_t w, int16_t h)
141 {
142  // function tft_abs_window clips
143  return( tft_abs_window(win,x+win->x, y+win->y, w,h) );
144 }
145 
148 
149 
151 
165 MEMSPACE
167 {
168  uint32_t result;
169 
170  tft_spi_begin();
171 
172  // Send Undocumented ILI9341 0xd9 as COMMAND
173  tft_Cmd(0xd9);
174 
175  // We do not know what the 0x10 offset implies, undocumented, but is required.
176  // Send ILI9341 parameter as DATA
177  tft_Data(0x10 + parameter);
178 
179  // The real ILI9341 Command whose parameters we want to read
180  // Send ILI9341 command as COMMAND
181  tft_Cmd(command);
182 
183  // Read Result
184  result=tft_Data(0);
185 
186  tft_spi_end();
187 
188 
189 #if ILI9341_DEBUG & 1
190 ets_uart_printf("cmd:%02x, par:%02x, read: %02x\n",
191  0xff & command,
192  0xff & parameter,
193  0xff & result);
194 #endif
195 
196  return (result);
197 }
198 
199 
205 MEMSPACE
207 {
208  uint32_t_bytes id;
209 
210 
211  id.all = 0;
214  id.bytes.b2 = tft_readRegister(0xd3, 1); // Parameter 1
215  id.bytes.b1 = tft_readRegister(0xd3, 2); // Parameter 2
216  id.bytes.b0 = tft_readRegister(0xd3, 3); // Parameter 3
217 
218  return id.all;
219 }
220 
221 
224 
234 void tft_bit_blit(window *win, uint8_t *ptr, int16_t x, int16_t y, int16_t w, int16_t h)
235 {
236 
237  uint16_t color;
238  int xx,yy;
239  int32_t off;
240  int32_t pixels;
241  int wdcount;
242  int ind;
243  uint8_t buf[2*64];
244 
245  // FIXME - do we just want to constrain the values or ignore the request ???
246  if ( tft_window_clip_args(tft,&x,&y,&w,&h) )
247  return;
248 
249  if(!w || !h)
250  return;
251 
252 #if 1
253 // BIT BLIT
254 
255  pixels = tft_rel_window(win, x, y, w, h);
256  if(pixels == 0)
257  return;
258 
259 // FIXME now we should consider clipping the pixel array
260 // Note: Clipping modifies offsets which in turn modifies blit array offsets
261 // We could use tft_drawPixel, and it clips - but that the pixel function is very slow
262 // For now we clip the arguments and use tft_rel_windows which also clips
263 
264 
265  tft_spi_begin();
266 
267  tft_Cmd(0x2c);
268 
269  off = 0;
270  ind = 0;
271  wdcount = 0;
272 
273  for (yy=0; yy < h; ++yy)
274  {
275  for (xx=0;xx < w; ++xx)
276  {
277  if(bittestv(ptr, xx + off))
278  color = win->fg;
279  else
280  color = win->bg;
281 
282  buf[ind++] = color >> 8;
283  buf[ind++] = color & 0xff;
284 
285  if(ind >= sizeof(buf))
286  {
287  tft_spi_TX(buf,ind,0);
288  ind = 0;
289  }
290  }
291  wdcount += xx;
292  if(wdcount > 0x3ff)
293  {
294  optimistic_yield(1000);
295  //ets_wdt_disable();
296  wdcount = 0;
297  }
298  off += w;
299  }
300  if(ind)
301  {
302  tft_spi_TX(buf,ind,0);
303  }
304 
305  tft_spi_end();
306 #else
307  off = 0;
308  for (yy=0; yy < h; ++yy)
309  {
310  for (xx=0;xx < w; ++xx)
311  {
312  if(bittestv(ptr, xx + off))
313  tft_drawPixel(win,x+xx,y+yy,fg);
314  else
315  tft_drawPixel(win,x+xx,y+yy,bg);
316  }
317  off += w;
318  }
319 #endif
320 }
321 
322 // =============================================================
323 // =============================================================
324 
325 
326 
330 
334 void tft_fillWin(window *win, uint16_t color)
335 {
336  // tft_fillRectWH() clips
337  tft_fillRectWH(win, 0,0, win->w, win->h, color);
338 }
339 
346 void tft_flood(window *win, int16_t x, int16_t y, uint16_t border, uint16_t fill)
347 {
348  uint16_t current;
349 
350  if(x < 0 || x >= win->w)
351  return;
352  if(y < 0 || y >= win->h)
353  return;
354 
355  current = tft_readPixel(win,x,y);
356  if(current == border || current == fill)
357  return;
358 
359  tft_drawPixel(win,x,y,fill);
360  tft_flood(win,x+1,y,border,fill);
361  tft_flood(win,x,y+1,border,fill);
362  tft_flood(win,x-1,y,border,fill);
363  tft_flood(win,x,y-1,border,fill);
364 }
365 
366 
367 
369 #define XYSTACK 64
370 static struct {
371  int16_t x[XYSTACK+2];
372  int16_t y[XYSTACK+2];
373  int ind;
374 } xy;
375 
380 int tft_push_xy(int16_t x, int16_t y)
381 {
382  if(xy.ind >= XYSTACK)
383  {
384  printf("xy.ind stack >= %d\n",XYSTACK);
385  return(0);
386  }
387  xy.x[xy.ind] = x;
388  xy.y[xy.ind] = y;
389  xy.ind++;
390  return(1);
391 }
392 
397 int tft_pop_xy(int16_t *x, int16_t *y)
398 {
399  if(xy.ind <= 0)
400  return(0);
401  xy.ind--;
402  *x = xy.x[xy.ind];
403  *y = xy.y[xy.ind];
404  return(1);
405 }
406 
416 int tft_floodline(window *win, int16_t x, int16_t y, uint16_t border, uint16_t fill)
417 {
418  int lineAbove, lineBelow;
419  int16_t xoff;
420  int count = 0;
421 
422  // reset stack
423  xy.ind = 0;
424 
425  if(x < 0 || x >= win->w)
426  {
427  printf("tft_floodline: X out of range\n");
428  return(0);
429  }
430  if(y < 0 || y >= win->h)
431  {
432  printf("tft_floodline: Y out of range\n");
433  return(0);
434  }
435 
436  // test for stack full
437  if(!tft_push_xy(x, y))
438  return(0);
439 
440  // while we have stacked items
441  // FIXME we can bypass readpixel - read any entire line interruped by the color check
442  while(tft_pop_xy((int16_t *)&x, (int16_t *)&y))
443  {
444  if(x < 0 || x >= win->w)
445  {
446  printf("tft_floodline: X out of range\n");
447  return(0);
448  }
449  if(y < 0 || y >= win->h)
450  {
451  printf("tft_floodline: Y out of range\n");
452  return(0);
453  }
454  xoff = x;
455  while(xoff >= 0 && tft_readPixel(win,xoff,y) != border )
456  xoff--;
457  xoff++;
458 
459  lineAbove = lineBelow = 0;
460 
461  while(xoff < win->w && tft_readPixel(win,xoff,y) != border)
462  {
463  tft_drawPixel(win,xoff,y,fill);
464  if(++count >= 1000)
465  {
466  optimistic_yield(1000);
467  count = 0;
468  }
469 
470 
471  if(!lineAbove && y > 0 && tft_readPixel(win,xoff,y-1) != border)
472  {
473  // test for stack full
474  if(!tft_push_xy(xoff, y - 1))
475  return(0);
476  lineAbove = 1;
477  }
478  else if(lineAbove && y > 0 && tft_readPixel(win,xoff,y-1) == border )
479  {
480  lineAbove = 0;
481  }
482  if(!lineBelow && y < (win->h-1) && tft_readPixel(win,xoff,y+1) != border )
483  {
484  // test for stack full
485  if(!tft_push_xy(xoff, y + 1))
486  return(0);
487  lineBelow = 1;
488  }
489  else if(lineBelow && y < (win->h-1) && tft_readPixel(win,xoff,y+1) == border)
490  {
491  lineBelow = 0;
492  }
493  xoff++;
494  }
495  }
496  return(1);
497 }
498 
499 
509 #define MAXVEC 24
510 int tft_FillPolyLine(window *win, int16_t x, int16_t y, int w, uint16_t color)
511 {
512  uint8_t data[3];
513  uint16_t val;
514  int pixels;
515  int ind,state;
516  int inside;
517  int count;
518  int16_t vec[MAXVEC+2];
519 
520 
521  // tft_rel_window() clips
522  pixels = tft_rel_window(win, x,y,w,1);
523  if(!pixels)
524  return(0);
525  if(pixels != w)
526  {
527  printf("FillPoly: w(%d) != pixels(%d)\n", (int) w, pixels);
528  }
529 
530  // scan
531  tft_spi_begin();
532  tft_Cmd(0x2e); // Memory Read
533  tft_Cmd(0); // NOP
534 
535  state = 0;
536  ind = 0;
537  inside = 0;
538  while(pixels > 0)
539  {
540  data[0] = 0;
541  data[1] = 0;
542  data[2] = 0;
543  tft_spi_RX(data, 3,1);
544  val = tft_RGBto565(data[0],data[1],data[2]);
545 
546  switch(state)
547  {
548  case 0:
549  /* match state */
550  if(val == color)
551  {
552  /* go to wait for unmatched state */
553  state = 1;
554  ++inside;
555  }
556  break;
557  case 1:
558  /* wait for unmatched state */
559  /* match to unmatch state */
560  if(val != color)
561  {
562  if(inside & 1)
563  {
564  // Save offset of start of unset transition
565  if(ind < MAXVEC)
566  vec[ind++] = x;
567  }
568  /* go to wait for matched state */
569  state = 2;
570  }
571 
572  break;
573  case 2:
574  /* unmatch to match */
575  /* wait for matched state */
576  if(val == color)
577  {
578  if(inside & 1)
579  {
580  // Save offset of LAST unmatched state
581  if(ind < MAXVEC)
582  vec[ind++] = x-1;
583  }
584  /* go to wait for unmatched state */
585  ++inside;
586  state = 1;
587 
588  }
589  break;
590  }
591  ++x;
592  --pixels;
593  }
594  tft_spi_end();
595 
596  count = ind;
597  if(count >= 2)
598  {
599 #if 1
600  int j;
601  printf("count[%d] @ line %d\n", count, y);
602  for(j=0;j<ind;++j)
603  printf("%d \n", (int)vec[j]);
604  printf("\n");
605 #endif
606  ind = 0;
607  while(count >= 2)
608  {
609  // tft_drawLine ( win , vec[ind], y, vec[ind+1], y, color );
610  tft_drawFastHLine ( win , vec[ind], y, vec[ind+1]-vec[ind]+1, color );
611  count -= 2;
612  ind += 2;
613  }
614  }
615  return(ind);
616 }
617 
627 void tft_fillRectWH(window *win, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
628 {
629  int32_t pixels;
630  int32_t colors;
631  int wdcount;
632  int ind;
633  uint8_t buf[2*64];
634 
635  // tft_rel_window clips
636  pixels = tft_rel_window(win, x,y,w,h);
637  if(!pixels)
638  return;
639 
640  wdcount = 0;
641 
642  if(pixels > 0)
643  {
644  tft_spi_begin();
645 
646  tft_Cmd(0x2c);
647 
648  ind = 0;
649  //We are sending words
650  while(pixels > 0)
651  {
652  colors = pixels;
653  if(colors > sizeof(buf)/2)
654  colors = sizeof(buf)/2;
655 
656  pixels -= colors;
657  wdcount += colors;
658 
659  if(!ind)
660  {
661  while(ind < sizeof(buf) && ind < colors*2)
662  {
663  buf[ind++] = color >> 8;
664  buf[ind++] = color & 0xff;
665  }
666  }
667  tft_spi_TX(buf,colors*2,0);
668  if(wdcount > 0x3ff)
669  {
670  wdcount = 0;
671  optimistic_yield(1000);
672  // ets_wdt_disable();
673  }
674  }
675 
676  tft_spi_end();
677  } // if(pixels > 0)
678 
679 }
680 
690 void tft_fillRectXY(window *win, int16_t x, int16_t y, int16_t xl, int16_t yl, uint16_t color)
691 {
692  uint32_t repeat;
693  int16_t w,h;
694 
695  if(x > xl)
696  SWAP(x,xl);
697  if(y > yl)
698  SWAP(y,yl);
699 
700  w = xl - x + 1;
701  h = yl - y + 1;
702  // tft_fillRectWH() clips
703  tft_fillRectWH(win, x, y, w, h, color);
704 }
705 
709 
717 void tft_drawPixel(window *win, int16_t x, int16_t y, int16_t color)
718 {
719  uint8_t data[2];
720 
721 // Clip pixel
722  if(x < 0 || x >= win->w)
723  return;
724  if(y < 0 || y >= win->h)
725  return;
726 
727  // tft_rel_window() clips
728  if(! tft_rel_window(win, x,y,1,1))
729  return;
730 
731  data[0] = color >>8;
732  data[1] = color;
733  tft_Cmd_Data_TX(0x2c, data, 2);
734 
735 }
736 
745 void tft_writeRect(window *win, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *color)
746 {
747 
748  int32_t pixels;
749  uint16_t pixel;
750  int wdcount;
751  int xx,yy;
752  int ind;
753  uint8_t buf[2*64];
754 
755  if(!w || !h)
756  return;
757 
758 // TODO CLIP window data - depends on blit array offset also
759 // We could use tft_drawPixel, and it clips - but that is slow
760 
761 #if 1
762  // tft_rel_window() clips limits
763  pixels = tft_rel_window(win, x, y, w, h);
764  if(!pixels)
765  return;
766 
767  tft_spi_begin();
768 
769  tft_Cmd(0x2c);
770 
771  ind = 0;
772  wdcount = 0;
773 
774  while(pixels-- > 0)
775  {
776  pixel = *color++;
777  buf[ind++]=pixel >> 8;
778  buf[ind++]=pixel & 0xff;
779  if(ind >= sizeof(buf))
780  {
781  tft_spi_TX(buf,ind,0);
782  wdcount += ind;
783  ind = 0;
784  if(wdcount > 0x3ff)
785  {
786  wdcount = 0;
787  optimistic_yield(1000);
788  //ets_wdt_disable();
789  }
790  }
791  }
792 
793  if(ind)
794  {
795  tft_spi_TX(buf,ind,0);
796  }
797 
798  tft_spi_end();
799 
800 #else
801  wdcount = 0;
802  for (yy=0; yy < h; ++yy)
803  {
804  for (xx=0;xx < w; ++xx)
805  {
806  tft_drawPixel(win, x+xx,y+yy,*ptr++);
807  }
808  wdcount += w;
809  if(wdcount >= 0x3ff)
810  {
811  wdcount = 0;
812  optimistic_yield(1000);
813  // ets_wdt_disable();
814  }
815  }
816 #endif
817 }
818 
819 
832 
835 #define HSPI_PIX ((HSPI_FIFO_SIZE-2)/3)
836 
837 void tft_readRect(window *win, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *color)
838 {
839  int32_t pixels;
840  int wdcount;
841  int rem;
842  uint8_t cmd;
843  uint8_t *ptr;
844  // Command and Pixel buffer
845  uint8_t data[64*3];
846 
847  // tft_rel_window() clips
848  pixels = tft_rel_window(win, x,y,w,h);
849  if(!pixels)
850  return;
851 
852  cmd = 0x2e; // Memory Read
853 
854  wdcount = 0;
855  while(pixels > 0)
856  {
857  tft_spi_begin();
858 
859  tft_Cmd(cmd);
860  tft_Cmd(0); // NOP
861 
862  if(pixels > sizeof(data)/3)
863  rem = sizeof(data)/3;
864  else
865  rem = pixels;
866 
867  pixels -= rem;
868 
869  wdcount += rem;
870 
871  // Send/Receive
872  // Read 3 byte pixel data
873  tft_spi_RX(data, rem*3,1);
874 
875  tft_spi_end();
876 
877  // Now reconvert 3 byte color data into 2 byte color data
878  ptr = data;
879  while(rem--)
880  {
881  // reuse the color buffer
882  // overwrite the 3 byte/pixel with 2 byte/pixle only data
883  *color++ = tft_RGBto565(ptr[0],ptr[1],ptr[2]);
884  ptr += 3;
885  }
886  cmd = 0x3e; // Memory Read Continue
887 
888  if(wdcount >= 0x3ff)
889  {
890  optimistic_yield(1000);
891  // ets_wdt_disable();
892  wdcount = 0;
893  }
894  }
895 }
896 
903 void tft_Vscroll(window *win, int dir)
904 {
905  int i;
906  int yfrom,yto;
907  uint8_t buff[TFT_W*3];
908 
909  // FIXME unsupported
910  // + == normal scroll - start at the top move down
911  // 0 == nothing to do
912  // - == reverse scroll - start at the bottom and move up
913  if(dir <= 0)
914  return;
915 
916  if(dir >= win->h)
917  {
918  // clear area that is vacated
919  tft_fillRectWH(win, 0, 0, win->w, win->h, win->bg);
920  return;
921  }
922  for(i=0; i < win->h;++i)
923  {
924  // source of scroll
925  yfrom= i+dir;
926  // target of scroll
927  yto = i;
928 
929  if(yfrom >= (win->h-1))
930  {
931  // Clear to of window
932  tft_fillRectWH(win, 0, yto, win->w, 1, win->bg);
933  }
934  else
935  {
936  // TOP
937  tft_readRect(win, 0, yfrom, win->w, 1, (uint16_t *) buff);
938  // DOWN
939  tft_writeRect(win, 0, yto, win->w, 1, (uint16_t *)buff);
940  }
941  }
942 }
943 
952 uint16_t tft_readPixel(window *win, int16_t x, int16_t y)
953 {
954  uint8_t data[3];
955  uint16_t color;
956 
957  // set window, also clips
958  if(!tft_rel_window(win, x,y,1,1))
959  return(0);
960 
961  tft_spi_begin();
962 
963  tft_Cmd(0x2e);
964  tft_Cmd(0); // NOP
965  tft_spi_RX(data, 3, 1);
966 
967  tft_spi_end();
968 
969  color = tft_RGBto565(data[0],data[1],data[2]);
970  return(color);
971 }
972 
973 
974 
981 MEMSPACE
983 {
984 
985  uint8_t data;
986  tft->rotation = m & 3; // can't be higher than 3
987  data = MADCTL_BGR;
988  switch (tft->rotation)
989  {
990  case 0:
991  data |= MADCTL_MX;
992  tft->w = TFT_W;
993  tft->x = TFT_XOFF;
994  tft->h = TFT_H;
995  tft->y = TFT_YOFF;
996  break;
997  case 1:
998  data |= MADCTL_MV;
999  tft->w = TFT_H;
1000  tft->x = TFT_YOFF;
1001  tft->h = TFT_W;
1002  tft->y = TFT_XOFF;
1003  break;
1004  case 2:
1005  data |= MADCTL_MY;
1006  tft->w = TFT_W;
1007  tft->x = TFT_XOFF;
1008  tft->h = TFT_H;
1009  tft->y = TFT_YOFF;
1010  break;
1011  case 3:
1012  data = MADCTL_MX | MADCTL_MY | MADCTL_MV;
1013  tft->w = TFT_H;
1014  tft->x = TFT_YOFF;
1015  tft->h = TFT_W;
1016  tft->y = TFT_XOFF;
1017  break;
1018  }
1019 
1020  tft_Cmd_Data_TX(ILI9341_MADCTL, &data, 1);
1021 }
1022 
1026 
1034 {
1035  *r = ((0xf800 & color)>>8);
1036  *g = ((0x7e0 & color)>>3);
1037  *b = (0x1f & color) << 3;
1038 }
1039 
1040 
1044 MEMSPACE
1045 void tft_invertDisplay(int flag)
1046 {
1047  uint8_t cmd = flag ? ILI9341_INVON : ILI9341_INVOFF;
1048 
1049  tft_spi_begin();
1050  tft_Cmd(cmd);
1051  tft_spi_end();
1052 }
1053 
1058 MEMSPACE
1060 {
1061  int clipped = 0;
1062 
1063  // Clip X
1064  if(win->x < tft->x)
1065  {
1066  win->x = tft->x;
1067  clipped++;
1068  }
1069  if(win->x > (tft->x + tft->w - 1))
1070  {
1071  win->x = (tft->x + tft->w - 1);
1072  clipped++;
1073  }
1074 
1075  // CLIP X,Y first
1076  // CLIP Y
1077  if(win->y < tft->y)
1078  {
1079  win->y = tft->y;
1080  clipped++;
1081  }
1082  if(win->y > (tft->y + tft->h - 1))
1083  {
1084  win->y = (tft->y + tft->h - 1);
1085  clipped++;
1086  }
1087 
1088 
1089  // CLIP W,H last
1090  // CLIP W
1091  if( (win->x + win->w - 1 ) > (tft->x + tft->w - 1) )
1092  {
1093  win->w = (tft->x + tft->w ) - win->x;
1094  clipped++;
1095  }
1096 
1097  // CLIP H
1098  if( (win->y + win->h - 1 ) > (tft->y + tft->h - 1) )
1099  {
1100  win->h = (tft->y + tft->h ) - win->y;
1101  clipped++;
1102  }
1103  return(clipped);
1104 }
1105 
1113 MEMSPACE
1114 void tft_clip_xy(window *win, int16_t *X, int16_t *Y)
1115 {
1116 
1117  int16_t X1 = *X;
1118  int16_t Y1 = *Y;
1119 
1120  if(X1 < win->x)
1121  X1 = win->x;
1122  if(X1 > (win->x + win->w - 1))
1123  X1 = (win->x + win->w - 1);
1124 
1125  if(Y1 < win->y)
1126  Y1 = win->y;
1127  if(Y1 > (win->y + win->w - 1))
1128  Y1 = (win->y + win->w - 1);
1129  *X = X1;
1130  *Y = Y1;
1131 }
1132 
1133 
1134 
1144 MEMSPACE
1145 int tft_window_clip_args(window *win, int16_t *x, int16_t *y, int16_t *w, int16_t *h)
1146 {
1147  int clipped = 0;
1148 
1149  // Clip X
1150  if(*x < win->x)
1151  {
1152  *x = win->x;
1153  clipped++;
1154  }
1155  if(*x > (win->x + win->w - 1))
1156  {
1157  *x = (win->x + win->w - 1);
1158  clipped++;
1159  }
1160 
1161  // CLIP Y
1162  if(*y < win->y)
1163  {
1164  *y = win->y;
1165  clipped++;
1166  }
1167  if(*y > (win->y + win->h - 1))
1168  {
1169  *y = (win->y + win->h - 1);
1170  clipped++;
1171  }
1172 
1173  // CLIP W
1174  if( (*x + *w - 1 ) > (win->x + win->w - 1) )
1175  {
1176  *w = (win->x + win->w ) - *x;
1177  clipped++;
1178  }
1179 
1180  // CLIP H
1181  if( (*y + *h - 1 ) > (win->y + win->h - 1) )
1182  {
1183  *h = (win->y + win->h ) - *y;
1184  clipped++;
1185  }
1186  return(clipped);
1187 }
1188 
1197 MEMSPACE
1198 void tft_window_init(window *win, int16_t x, int16_t y, int16_t w, int16_t h)
1199 {
1200  // Do Clipping checks for bogus values
1201 
1202 
1203  (void) tft_window_clip_args(tft,&x,&y,&w,&h);
1204 
1205  win->xpos = 0; // current X position
1206  win->ypos = 0; // current Y position
1207  win->font = 0; // current font size
1208  win->flags = WRAP_H;
1209  win->w = w;
1210  win->x = x;
1211  win->h = h;
1212  win->y = y;
1213  win->rotation = 0;
1214  win->tabstop = w/4;
1215  win->fg = 0xFFFF;
1216  win->bg = 0;
1217 }
1218 
1219 
1221 
1227 MEMSPACE
1229 {
1230  win->fg = fg;
1231  win->bg = bg;
1232 }
1233 
1240 MEMSPACE
1241 void tft_setpos(window *win, int16_t x, int16_t y)
1242 {
1243  win->xpos = x;
1244  win->ypos = y;
1245 }
1246 
1253 MEMSPACE
1254 void tft_set_textpos(window *win, int16_t x, int16_t y)
1255 {
1256  win->xpos = x * font_W(win->font);
1257  win->ypos = y * font_H(win->font);
1258 }
1259 
1260 
1266 MEMSPACE
1267 void tft_set_font(window *win, uint16_t index)
1268 {
1269  if(win->font > font_max())
1270  win->font = font_max();
1271  win->font = index;
1272 }
1273 
1277 MEMSPACE
1279 {
1280  win->flags &= ~FONT_VAR;
1281 }
1282 
1283 
1287 MEMSPACE
1289 {
1290  win->flags |= FONT_VAR;
1291 }
1292 
1297 {
1298  int ret;
1299  _fontc f;
1300  ret = font_attr(win, ' ', &f);
1301  if(ret < 0)
1302  return 0;
1303  return(f.Height);
1304 }
1305 
1306 
1314 void tft_drawFastVLine(window *win,int16_t x, int16_t y,
1315 int16_t h, uint16_t color)
1316 {
1317  // function clips
1318  tft_fillRectWH(win, x,y ,1, h, color);
1319 }
1320 
1321 
1329 void tft_drawFastHLine(window *win, int16_t x, int16_t y,
1330 int16_t w, uint16_t color)
1331 {
1332  // function clips
1333  tft_fillRectWH(win, x,y ,w, 1, color);
1334 }
1335 
1336 
1346 #if 0
1347 void tft_drawLine(window *win, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
1348 {
1349  int npts, i, delx, dely, xi, yi, diff;
1350 
1351  delx = (x1-x0); xi = SIGN(delx); delx = ABS(delx);
1352  dely = (y1-y0); yi = SIGN(dely); dely = ABS(dely);
1353  diff = (delx-dely);
1354  npts = MAX(delx,dely);
1355 
1356  for(i=0;i<=npts;++i)
1357  {
1358  tft_drawPixel(win, x0, y0, color);
1359  if(diff >= 0)
1360  {
1361  diff -= dely; x0 += xi;
1362  if(dely >= delx)
1363  {
1364  diff +=delx; y0 +=yi;
1365  }
1366  }
1367  else
1368  {
1369  diff += delx; y0 += yi;
1370  if(delx >= dely)
1371  {
1372  diff -= dely; x0 += xi;
1373  }
1374  }
1375  }
1376 }
1377 
1378 #else
1379 void tft_drawLine(window *win, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
1390 {
1391 
1392 #define USE_OPTIMIZATION_DRAWLINE
1393 
1394  int16_t dx = ABS(x1 - x0);
1395  int16_t dy = -ABS(y1 - y0);
1396  int8_t sx = (x0 < x1) ? 1 : -1;
1397  int8_t sy = (y0 < y1) ? 1 : -1;
1398  int16_t err = dx + dy;
1399  int16_t e2 = 0;
1400 
1401 #ifdef USE_OPTIMIZATION_DRAWLINE
1402  uint16_t startX = x0;
1403  uint16_t startY = y0;
1404 #endif
1405 
1406  for (;;)
1407  {
1408 #ifdef USE_OPTIMIZATION_DRAWLINE
1409  // Require correction
1410  if ((startX != x0) && (startY != y0)) // draw line and not draw point
1411  {
1412 
1413  tft_fillRectXY(win, startX, startY, x0 - sx, y0 - sy, color);
1414  startX = x0;
1415  startY = y0;
1416  }
1417 #else
1418  tft_drawPixel(win, x0, y0, color);
1419 #endif
1420 
1421  e2 = 2*err;
1422  if (e2 >= dy)
1423  {
1424  if (x0 == x1) break;
1425  err += dy;
1426  x0 += sx;
1427  }
1428  if (e2 <= dx)
1429  {
1430  if (y0 == y1) break;
1431  err += dx;
1432  y0 += sy;
1433  }
1434  }
1435 #ifdef USE_OPTIMIZATION_DRAWLINE
1436  // function clips
1437  tft_fillRectXY(win, startX, startY, x0, y0, color);
1438 #endif
1439 }
1440 #endif
1441 
1474 int tft_Bezier2(window *win, p2_int16_t S, p2_int16_t C, p2_int16_t T, int steps, uint16_t color)
1475 {
1476  float t, tinc, t1,p1,p2,p3;
1477  p2_int16_t Last,Point;
1478  int16_t X,Y;
1479  int ind = 0;
1480  int i;
1481 
1482  Last = S;
1483  t = 0;
1484 
1485  if(steps < 1)
1486  steps = 1;
1487 
1488  // FIXME we should compute a step size based on the start to end point distances
1489  tinc = 1.0 / (float) steps; // steps = 1 will just draw one line
1490 
1491  // Quadratic Bezier http://en.wikipedia.org/wiki/Bézier_curve
1492  // B(t) = (1-t)(1-t)S + 2(1-t)tC + t*tT, 0 <= t <= 1
1493  for (i = 0; i < steps; ++i)
1494  {
1495  t += tinc;
1496 
1497  t1 = (1.0 - t);
1498  p1 = t1 * t1; /* (1.0 - t) (1.0 - t) */
1499  p2 = 2.0 * t1 * t; /* 2(1.0 - t) * t */
1500  p3 = t * t; /* t * t */
1501 
1502  Point.X = (int16_t) (p1 * (float)S.X + p2 * (float)C.X + p3 * (float)T.X);
1503  Point.Y = (int16_t) (p1 * (float)S.Y + p2 * (float)C.Y + p3 * (float)T.Y);
1504  // Do not plot a line until we actually move
1505  if(Last.X == Point.X && Last.Y == Point.Y)
1506  continue;
1507  tft_drawLine(win, Last.X, Last.Y, Point.X, Point.Y, color);
1508  Last = Point;
1509  }
1510  return(ind);
1511 }
1512 
1545 int tft_Bezier3(window *win, p2_int16_t S, p2_int16_t C1, p2_int16_t C2, p2_int16_t T, int steps, uint16_t color)
1546 {
1547  float t, tinc, c0, t1,t2,p1,p2,p3,p4;
1548  p2_int16_t Last,Point;
1549  int16_t X,Y;
1550  int i;
1551  int ind;
1552 
1553  Last = S;
1554 
1555  if(steps < 1)
1556  steps = 1;
1557 
1558  ind = 0;
1559 
1560  t = 0;
1561  // FXIME we should compute a step size based on the start to end point distances
1562  tinc = 1.0 / (float) steps; // steps = 1 will just draw one line
1563 
1564  // Quadratic Bezier http://en.wikipedia.org/wiki/Bézier_curve
1565  // B(t) = (1-t)(1-t)*(1-t)*S + 3*(1-t)(1-t)*t*C1 + 3(1-t)*t*t*C2 + t*t*t*T, 0 <= t <= 1
1566  for (i = 0; i < steps; ++i)
1567  {
1568  t += tinc;
1569  t1 = (1.0 - t);
1570  t2 = t1 * t1; /* (1-t)(1-t) */
1571 
1572  c0 = 3.0 * t1 * t; /* 3(1-t) * t */
1573 
1574  p1 = t2 * t1; /* (1-t)(1-t)(1-t) */
1575  p2 = c0 * t1; /* 3(1-t)(1-t) * t */
1576  p3 = c0 * t; /* 3(1-t) * t * t */
1577  p4 = t * t * t; /* t * t * t */
1578 
1579  Point.X = (int16_t) (p1 * (float)S.X + p2 * (float)C1.X + p3 * (float) C2.X + p4 * (float)T.X);
1580  Point.Y = (int16_t) (p3 * (float)S.Y + p2 * (float)C1.Y + p3 * (float) C2.Y + p4 * (float)T.Y);
1581 
1582  // Do not plot a line until we actually move
1583  if(Last.X == X && Last.Y == Y)
1584  continue;
1585  tft_drawLine(win, Last.X, Last.Y, X, Y, color);
1586  Last = Point;
1587  ++ind;
1588  }
1589  return(ind);
1590 }
1591 
1592 
1596 
1600 MEMSPACE
1602 {
1603  int ret, rem;
1604  _fontc f;
1605  ret = font_attr(win,' ', &f);
1606  if(ret < 0)
1607  return;
1608  rem = (win->w - 1 - win->xpos);
1609  if(rem > 0)
1610  {
1611  // function clips
1612  tft_fillRectWH(win, win->xpos, win->ypos, rem, f.Height, win->bg);
1613  }
1614  win->xpos = win->w; // one past end
1615 }
1616 
1620 MEMSPACE
1622 {
1623  int ret, rem;
1624  _fontc f;
1625  ret = font_attr(win,' ', &f);
1626  if(ret < 0)
1627  return;
1628  rem = (win->w - 1 - win->xpos);
1629  if(rem > 0)
1630  {
1631  // function clips
1632  tft_fillRectWH(win, 0, win->ypos, rem, f.Height, win->bg);
1633  }
1634  win->xpos = 0;
1635 }
1636 
1637 
1638 
1643 void tft_putch(window *win, int c)
1644 {
1645  _fontc f;
1646  int ret;
1647  int width;
1648  int count;
1649  int rem;
1650 
1651  if(c < 0 || c > 0x7e)
1652  return;
1653 
1654  if(c >= ' ')
1655  {
1656  ret = font_attr(win, c, &f);
1657  if(ret < 0)
1658  return;
1659  }
1660  else
1661  {
1662  // use space to get font attributes
1663  ret = font_attr(win,' ', &f);
1664  if(ret < 0)
1665  return;
1666  }
1667 
1668  // Normal visible characters
1669  if(c >= ' ')
1670  {
1671  (void) tft_drawChar(win, c);
1672  return;
1673  }
1674 
1675  // Control characters
1676  if(c == '\n')
1677  {
1678  tft_cleareol(win);
1679  win->xpos = 0;
1680  win->ypos += f.Height;
1681  }
1682  if(c == '\f')
1683  {
1684  tft_fillWin(win,win->bg);
1685  win->xpos = 0;
1686  win->ypos = 0;
1687  }
1688  if(c == '\t')
1689  {
1690  count = win->tabstop - (win->xpos % win->tabstop);// skip size to next tabstop
1691  // Will we overflow ?
1692  if(win->xpos + count > win->w)
1693  {
1694  count = (win->xpos + count) - win->w -1;
1695  tft_cleareol(win);
1696  if(win->flags & WRAP_H)
1697  {
1698  tft_fillRectWH(win, 0, win->ypos, count, f.Height, win->bg);
1699  win->xpos = count;
1700  win->ypos += f.Height;
1701  }
1702  }
1703  else
1704  {
1705  tft_fillRectWH(win, win->xpos, win->ypos, count, f.Height, win->bg);
1706  win->xpos += count;
1707  }
1708  }
1709 }
1710 
1711 
1712 /* tft_printf removes the need for most of the draw string functions */
int16_t w
Definition: ili9341.h:40
int16_t sy(float scale, int16_t yoff, int16_t Y)
MEMSPACE void tft_setRotation(uint8_t m)
Set Display rotation, applies to the master window only Set hardware display rotation and memory fill...
Definition: ili9341.c:982
int tft_get_font_height(window *win)
Get font height.
Definition: ili9341.c:1296
uint16_t tft_readPixel(window *win, int16_t x, int16_t y)
Read one pixel and return color in 1bit 565 RGB format We clip the window to the current view Note: R...
Definition: ili9341.c:952
#define TFT_YOFF
Definition: ili9341.h:86
int int32_t
MEMSPACE void tft_set_textpos(window *win, int16_t x, int16_t y)
Set current window text pointer in characters (per current rotation) - overall font bounding box...
Definition: ili9341.c:1254
#define FONT_VAR
Definition: ili9341.h:78
MEMSPACE uint32_t tft_readRegister(uint8_t command, uint8_t parameter)
====================================
Definition: ili9341.c:166
void tft_drawFastHLine(window *win, int16_t x, int16_t y, int16_t w, uint16_t color)
Fast virtical line drawing.
Definition: ili9341.c:1329
void tft_spi_begin(void)
Obtain SPI bus for TFT display, assert chip select return: void.
Definition: ili9341_hal.c:80
int16_t h
Definition: ili9341.h:41
unsigned short uint16_t
Definition: send.c:18
void tft_bit_blit(window *win, uint8_t *ptr, int16_t x, int16_t y, int16_t w, int16_t h)
BLIT functions
Definition: ili9341.c:234
uint16_t flags
Definition: ili9341.h:43
Master include file for project Includes all project includes and defines here.
uint16_t bg
Definition: ili9341.h:45
void tft_fillRectWH(window *win, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
Partial window Fill with color We clip the window to the current view.
Definition: ili9341.c:627
void tft_Cmd(uint8_t cmd)
Transmit 8 bit command.
Definition: ili9341.c:53
#define MAXVEC
find beginning and end of all non-matching color transitions in a line FIXME: not tested yet ...
Definition: ili9341.c:509
int tft_floodline(window *win, int16_t x, int16_t y, uint16_t border, uint16_t fill)
Flood using line fill method.
Definition: ili9341.c:416
void tft_flood(window *win, int16_t x, int16_t y, uint16_t border, uint16_t fill)
Flood fill.
Definition: ili9341.c:346
MEMSPACE void tft_setTextColor(window *win, uint16_t fg, uint16_t bg)
====================================
Definition: ili9341.c:1228
Cordic_T X
Main Cordic routine - used for basic trig and vector rotations We use fixed point numbers...
Definition: cordic.c:102
#define SWAP(a, b)
Definition: ili9341.h:95
int16_t xpos
Definition: ili9341.h:36
uint8_t rotation
Definition: ili9341.h:46
int16_t y[XYSTACK+2]
Definition: ili9341.c:372
uint8_t tft_Data(uint8_t data)
Transmit 8 bit data amd read 8bit data.
Definition: ili9341.c:61
#define MADCTL_MV
#define MADCTL_MX
#define ILI9341_INVON
void tft_fillRectXY(window *win, int16_t x, int16_t y, int16_t xl, int16_t yl, uint16_t color)
Fill rectangle with color We clip the window to the current view.
Definition: ili9341.c:690
unsigned int uint32_t
Definition: send.c:19
Cordic_T Y
Definition: cordic.c:102
MEMSPACE void tft_set_font(window *win, uint16_t index)
Set current font size (per current rotation)
Definition: ili9341.c:1267
#define ABS(x)
Definition: ili9341.h:96
MEMSPACE int tft_window_clip(window *win)
Clip window structure to TFT limits.
Definition: ili9341.c:1059
int tft_Bezier2(window *win, p2_int16_t S, p2_int16_t C, p2_int16_t T, int steps, uint16_t color)
Draw lines between points along Quadratic Bézier curve Quadratic Bézier with respect to t...
Definition: ili9341.c:1474
int tft_Bezier3(window *win, p2_int16_t S, p2_int16_t C1, p2_int16_t C2, p2_int16_t T, int steps, uint16_t color)
Draw lines between points along Cubic Bézier curve Quadratic Bézier with respect to t...
Definition: ili9341.c:1545
int tft_push_xy(int16_t x, int16_t y)
point push
Definition: ili9341.c:380
#define MADCTL_MY
void tft_writeRect(window *win, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *color)
Write a rectangle pixel array.
Definition: ili9341.c:745
#define WRAP_H
Definition: ili9341.h:79
void optimistic_yield(uint32_t interval_us)
Definition: user_task.c:102
#define MADCTL_BGR
void tft_drawChar(window *win, uint8_t c)
Display a character and optionally wrap the graphic cursor.
Definition: font.c:200
int16_t x[XYSTACK+2]
Definition: ili9341.c:371
#define TFT_XOFF
Definition: ili9341.h:85
MEMSPACE int tft_window_clip_args(window *win, int16_t *x, int16_t *y, int16_t *w, int16_t *h)
clip arguments to window limits Arguments position x,y width w and height h to be clipped ...
Definition: ili9341.c:1145
window * tft
Definition: ili9341.c:45
void ets_uart_printf(char *fmt,...)
#define XYSTACK
X,Y point stack.
Definition: ili9341.c:369
int32_t tft_rel_window(window *win, int16_t x, int16_t y, int16_t w, int16_t h)
Set the ili9341 working window by relative position and size Note: Function clips x...
Definition: ili9341.c:140
#define tft_RGBto565(r, g, b)
Pass 8-bit (each) R,G,B, get back 16-bit packed color ILI9341 defaults to MSB/LSB data so we have to ...
Definition: ili9341.h:93
int32_t tft_abs_window(window *win, int16_t x, int16_t y, int16_t w, int16_t h)
=============================================================
Definition: ili9341.c:101
MEMSPACE void tft_clip_xy(window *win, int16_t *X, int16_t *Y)
Clip X,Y to fix inside specifiied window.
Definition: ili9341.c:1114
window tftwin
Definition: ili9341.c:44
void tft_drawFastVLine(window *win, int16_t x, int16_t y, int16_t h, uint16_t color)
Fast virtical line drawing.
Definition: ili9341.c:1314
signed char int8_t
int font_max()
Definition: font.c:59
int16_t sx(float scale, int16_t xoff, int16_t X)
MEMSPACE void tft_clearline(window *win)
Clear display text line.
Definition: ili9341.c:1621
void tft_spi_TXRX(uint8_t *data, int bytes, uint8_t command)
Transmit and read 8 bit data array.
Definition: ili9341_hal.c:149
int16_t y
Definition: ili9341.h:39
MEMSPACE void tft_font_fixed(window *win)
Definition: ili9341.c:1278
#define ILI9341_INVOFF
void tft_drawPixel(window *win, int16_t x, int16_t y, int16_t color)
Pixel functions
Definition: ili9341.c:717
int bittestv(unsigned char *ptr, int off)
Test bit in byte array.
Definition: flash.c:151
int ind
Definition: ili9341.c:373
2D display point - display coordinates are int16
Definition: ili9341.h:51
uint16_t font
Definition: ili9341.h:42
void tft_drawLine(window *win, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
Draw line From my blit test code testit.c 1984 - 1985 Mike Gore.
Definition: ili9341.c:1389
int16_t ypos
Definition: ili9341.h:37
int16_t X
Definition: ili9341.h:52
int tft_FillPolyLine(window *win, int16_t x, int16_t y, int w, uint16_t color)
Definition: ili9341.c:510
int font_W(int font)
Get font Width used for character to character spacing.
Definition: font.c:80
MEMSPACE void tft_font_var(window *win)
Set current font type to variable.
Definition: ili9341.c:1288
void tft_spi_end(void)
Release SPI bus from TFT display, deassert chip select return: void.
Definition: ili9341_hal.c:87
uint16_t fg
Definition: ili9341.h:44
void tft_565toRGB(uint16_t color, uint8_t *r, uint8_t *g, uint8_t *b)
Color conversions
Definition: ili9341.c:1033
#define MEMSPACE
Definition: cpu.h:25
MEMSPACE void tft_setpos(window *win, int16_t x, int16_t y)
Set current window text pointer in pixels (per current rotation)
Definition: ili9341.c:1241
void tft_Vscroll(window *win, int dir)
Scroll window up by dir lines We start at the top of the window and move down.
Definition: ili9341.c:903
void tft_fillWin(window *win, uint16_t color)
Fill functions
Definition: ili9341.c:334
void tft_readRect(window *win, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *color)
Definition: ili9341.c:837
MEMSPACE int printf(const char *format,...)
int16_t x
Definition: ili9341.h:38
Definition: ili9341.h:34
int8_t Height
Definition: font.h:98
MEMSPACE void tft_cleareol(window *win)
Character and String functions
Definition: ili9341.c:1601
void tft_Cmd_Data_TX(uint8_t cmd, uint8_t *data, int bytes)
Transmit 8 bit command and optionally send data buffer.
Definition: ili9341.c:72
MEMSPACE uint32_t tft_readId(void)
Read ILI9341 device ID should be 9341 This does not work for really high SPI clock speeds Make sure t...
Definition: ili9341.c:206
void tft_spi_TX(uint8_t *data, int bytes, uint8_t command)
Transmit 8 bit data array.
Definition: ili9341_hal.c:134
int16_t Y
Definition: ili9341.h:53
MEMSPACE void tft_invertDisplay(int flag)
Invert the display.
Definition: ili9341.c:1045
ili9341 driver inspired by Adafruit ili9341 code All code in this file has been rewritten by Mike Gor...
int font_attr(window *win, int c, _fontc *f)
Get font attributes for a font.
Definition: font.c:94
uint8_t tabstop
Definition: ili9341.h:47
#define ILI9341_MADCTL
unsigned char uint8_t
Definition: send.c:17
#define TFT_W
Definition: ili9341.h:83
#define TFT_H
Definition: ili9341.h:84
Definition: font.h:89
int font_H(int font)
Get font height used for line to line spacing.
Definition: font.c:70
void tft_spi_RX(uint8_t *data, int bytes, uint8_t command)
read 8 bit data array
Definition: ili9341_hal.c:165
static struct @1 xy
MEMSPACE void tft_window_init(window *win, int16_t x, int16_t y, int16_t w, int16_t h)
Initialize window structure we default values FIXME check x+w, y+h absolute limits against TFT limuts...
Definition: ili9341.c:1198
void tft_putch(window *win, int c)
put character in current winoow
Definition: ili9341.c:1643
int tft_pop_xy(int16_t *x, int16_t *y)
point push
Definition: ili9341.c:397