PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

1835 linhas
51KB

  1. // https://github.com/PaulStoffregen/ILI9341_t3
  2. // http://forum.pjrc.com/threads/26305-Highly-optimized-ILI9341-(320x240-TFT-color-display)-library
  3. /***************************************************
  4. This is our library for the Adafruit ILI9341 Breakout and Shield
  5. ----> http://www.adafruit.com/products/1651
  6. Check out the links above for our tutorials and wiring diagrams
  7. These displays use SPI to communicate, 4 or 5 pins are required to
  8. interface (RST is optional)
  9. Adafruit invests time and resources providing this open source code,
  10. please support Adafruit and open-source hardware by purchasing
  11. products from Adafruit!
  12. Written by Limor Fried/Ladyada for Adafruit Industries.
  13. MIT license, all text above must be included in any redistribution
  14. ****************************************************/
  15. // <SoftEgg>
  16. //Additional graphics routines by Tim Trzepacz, SoftEgg LLC added December 2015
  17. //(And then accidentally deleted and rewritten March 2016. Oops!)
  18. //Gradient support
  19. //----------------
  20. // fillRectVGradient - fills area with vertical gradient
  21. // fillRectHGradient - fills area with horizontal gradient
  22. // fillScreenVGradient - fills screen with vertical gradient
  23. // fillScreenHGradient - fills screen with horizontal gradient
  24. //Additional Color Support
  25. //------------------------
  26. // color565toRGB - converts 565 format 16 bit color to RGB
  27. // color565toRGB14 - converts 16 bit 565 format color to 14 bit RGB (2 bits clear for math and sign)
  28. // RGB14tocolor565 - converts 14 bit RGB back to 16 bit 565 format color
  29. //Low Memory Bitmap Support
  30. //-------------------------
  31. // writeRect8BPP - write 8 bit per pixel paletted bitmap
  32. // writeRect4BPP - write 4 bit per pixel paletted bitmap
  33. // writeRect2BPP - write 2 bit per pixel paletted bitmap
  34. // writeRect1BPP - write 1 bit per pixel paletted bitmap
  35. //TODO: transparent bitmap writing routines for sprites
  36. //String Pixel Length support
  37. //---------------------------
  38. // strPixelLen - gets pixel length of given ASCII string
  39. // <\SoftEgg>
  40. #include "ILI9341_t3.h"
  41. #include <SPI.h>
  42. // Teensy 3.1 can only generate 30 MHz SPI when running at 120 MHz (overclock)
  43. // At all other speeds, SPI.beginTransaction() will use the fastest available clock
  44. #define WIDTH ILI9341_TFTWIDTH
  45. #define HEIGHT ILI9341_TFTHEIGHT
  46. // Constructor when using hardware SPI. Faster, but must use SPI pins
  47. // specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
  48. ILI9341_t3::ILI9341_t3(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso)
  49. {
  50. _cs = cs;
  51. _dc = dc;
  52. _rst = rst;
  53. _mosi = mosi;
  54. _sclk = sclk;
  55. _miso = miso;
  56. _width = WIDTH;
  57. _height = HEIGHT;
  58. rotation = 0;
  59. cursor_y = cursor_x = 0;
  60. textsize = 1;
  61. textcolor = textbgcolor = 0xFFFF;
  62. wrap = true;
  63. font = NULL;
  64. // Added to see how much impact actually using non hardware CS pin might be
  65. _cspinmask = 0;
  66. _csport = NULL;
  67. }
  68. void ILI9341_t3::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
  69. {
  70. beginSPITransaction(_clock);
  71. setAddr(x0, y0, x1, y1);
  72. writecommand_last(ILI9341_RAMWR); // write to RAM
  73. endSPITransaction();
  74. }
  75. void ILI9341_t3::pushColor(uint16_t color)
  76. {
  77. beginSPITransaction(_clock);
  78. writedata16_last(color);
  79. endSPITransaction();
  80. }
  81. void ILI9341_t3::drawPixel(int16_t x, int16_t y, uint16_t color) {
  82. if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
  83. beginSPITransaction(_clock);
  84. setAddr(x, y, x, y);
  85. writecommand_cont(ILI9341_RAMWR);
  86. writedata16_last(color);
  87. endSPITransaction();
  88. }
  89. void ILI9341_t3::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
  90. {
  91. // Rudimentary clipping
  92. if((x >= _width) || (x < 0) || (y >= _height)) return;
  93. if(y < 0) { h += y; y = 0; }
  94. if((y+h-1) >= _height) h = _height-y;
  95. beginSPITransaction(_clock);
  96. setAddr(x, y, x, y+h-1);
  97. writecommand_cont(ILI9341_RAMWR);
  98. while (h-- > 1) {
  99. writedata16_cont(color);
  100. }
  101. writedata16_last(color);
  102. endSPITransaction();
  103. }
  104. void ILI9341_t3::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
  105. {
  106. // Rudimentary clipping
  107. if((x >= _width) || (y >= _height) || (y < 0)) return;
  108. if(x < 0) { w += x; x = 0; }
  109. if((x+w-1) >= _width) w = _width-x;
  110. beginSPITransaction(_clock);
  111. setAddr(x, y, x+w-1, y);
  112. writecommand_cont(ILI9341_RAMWR);
  113. while (w-- > 1) {
  114. writedata16_cont(color);
  115. }
  116. writedata16_last(color);
  117. endSPITransaction();
  118. }
  119. void ILI9341_t3::fillScreen(uint16_t color)
  120. {
  121. fillRect(0, 0, _width, _height, color);
  122. }
  123. // fill a rectangle
  124. void ILI9341_t3::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
  125. {
  126. // rudimentary clipping (drawChar w/big text requires this)
  127. if((x >= _width) || (y >= _height)) return;
  128. if(x < 0) { w += x; x = 0; }
  129. if(y < 0) { h += y; y = 0; }
  130. if((x + w - 1) >= _width) w = _width - x;
  131. if((y + h - 1) >= _height) h = _height - y;
  132. // TODO: this can result in a very long transaction time
  133. // should break this into multiple transactions, even though
  134. // it'll cost more overhead, so we don't stall other SPI libs
  135. beginSPITransaction(_clock);
  136. setAddr(x, y, x+w-1, y+h-1);
  137. writecommand_cont(ILI9341_RAMWR);
  138. for(y=h; y>0; y--) {
  139. for(x=w; x>1; x--) {
  140. writedata16_cont(color);
  141. }
  142. writedata16_last(color);
  143. if (y > 1 && (y & 1)) {
  144. endSPITransaction();
  145. beginSPITransaction(_clock);
  146. }
  147. }
  148. endSPITransaction();
  149. }
  150. // fillRectVGradient - fills area with vertical gradient
  151. void ILI9341_t3::fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color1, uint16_t color2)
  152. {
  153. // rudimentary clipping (drawChar w/big text requires this)
  154. if((x >= _width) || (y >= _height)) return;
  155. if((x + w - 1) >= _width) w = _width - x;
  156. if((y + h - 1) >= _height) h = _height - y;
  157. int16_t r1, g1, b1, r2, g2, b2, dr, dg, db, r, g, b;
  158. color565toRGB14(color1,r1,g1,b1);
  159. color565toRGB14(color2,r2,g2,b2);
  160. dr=(r2-r1)/h; dg=(g2-g1)/h; db=(b2-b1)/h;
  161. r=r1;g=g1;b=b1;
  162. // TODO: this can result in a very long transaction time
  163. // should break this into multiple transactions, even though
  164. // it'll cost more overhead, so we don't stall other SPI libs
  165. beginSPITransaction(_clock);
  166. setAddr(x, y, x+w-1, y+h-1);
  167. writecommand_cont(ILI9341_RAMWR);
  168. for(y=h; y>0; y--) {
  169. uint16_t color = RGB14tocolor565(r,g,b);
  170. for(x=w; x>1; x--) {
  171. writedata16_cont(color);
  172. }
  173. writedata16_last(color);
  174. if (y > 1 && (y & 1)) {
  175. endSPITransaction();
  176. beginSPITransaction(_clock);
  177. }
  178. r+=dr;g+=dg; b+=db;
  179. }
  180. endSPITransaction();
  181. }
  182. // fillRectHGradient - fills area with horizontal gradient
  183. void ILI9341_t3::fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color1, uint16_t color2)
  184. {
  185. // rudimentary clipping (drawChar w/big text requires this)
  186. if((x >= _width) || (y >= _height)) return;
  187. if((x + w - 1) >= _width) w = _width - x;
  188. if((y + h - 1) >= _height) h = _height - y;
  189. int16_t r1, g1, b1, r2, g2, b2, dr, dg, db, r, g, b;
  190. color565toRGB14(color1,r1,g1,b1);
  191. color565toRGB14(color2,r2,g2,b2);
  192. dr=(r2-r1)/h; dg=(g2-g1)/h; db=(b2-b1)/h;
  193. r=r1;g=g1;b=b1;
  194. // TODO: this can result in a very long transaction time
  195. // should break this into multiple transactions, even though
  196. // it'll cost more overhead, so we don't stall other SPI libs
  197. beginSPITransaction(_clock);
  198. setAddr(x, y, x+w-1, y+h-1);
  199. writecommand_cont(ILI9341_RAMWR);
  200. for(y=h; y>0; y--) {
  201. uint16_t color;
  202. for(x=w; x>1; x--) {
  203. color = RGB14tocolor565(r,g,b);
  204. writedata16_cont(color);
  205. r+=dr;g+=dg; b+=db;
  206. }
  207. color = RGB14tocolor565(r,g,b);
  208. writedata16_last(color);
  209. if (y > 1 && (y & 1)) {
  210. endSPITransaction();
  211. beginSPITransaction(_clock);
  212. }
  213. r=r1;g=g1;b=b1;
  214. }
  215. endSPITransaction();
  216. }
  217. // fillScreenVGradient - fills screen with vertical gradient
  218. void ILI9341_t3::fillScreenVGradient(uint16_t color1, uint16_t color2)
  219. {
  220. fillRectVGradient(0,0,_width,_height,color1,color2);
  221. }
  222. // fillScreenHGradient - fills screen with horizontal gradient
  223. void ILI9341_t3::fillScreenHGradient(uint16_t color1, uint16_t color2)
  224. {
  225. fillRectHGradient(0,0,_width,_height,color1,color2);
  226. }
  227. #define MADCTL_MY 0x80
  228. #define MADCTL_MX 0x40
  229. #define MADCTL_MV 0x20
  230. #define MADCTL_ML 0x10
  231. #define MADCTL_RGB 0x00
  232. #define MADCTL_BGR 0x08
  233. #define MADCTL_MH 0x04
  234. void ILI9341_t3::setRotation(uint8_t m)
  235. {
  236. rotation = m % 4; // can't be higher than 3
  237. beginSPITransaction(_clock);
  238. writecommand_cont(ILI9341_MADCTL);
  239. switch (rotation) {
  240. case 0:
  241. writedata8_last(MADCTL_MX | MADCTL_BGR);
  242. _width = ILI9341_TFTWIDTH;
  243. _height = ILI9341_TFTHEIGHT;
  244. break;
  245. case 1:
  246. writedata8_last(MADCTL_MV | MADCTL_BGR);
  247. _width = ILI9341_TFTHEIGHT;
  248. _height = ILI9341_TFTWIDTH;
  249. break;
  250. case 2:
  251. writedata8_last(MADCTL_MY | MADCTL_BGR);
  252. _width = ILI9341_TFTWIDTH;
  253. _height = ILI9341_TFTHEIGHT;
  254. break;
  255. case 3:
  256. writedata8_last(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
  257. _width = ILI9341_TFTHEIGHT;
  258. _height = ILI9341_TFTWIDTH;
  259. break;
  260. }
  261. endSPITransaction();
  262. cursor_x = 0;
  263. cursor_y = 0;
  264. }
  265. void ILI9341_t3::setScroll(uint16_t offset)
  266. {
  267. beginSPITransaction(_clock);
  268. writecommand_cont(ILI9341_VSCRSADD);
  269. writedata16_last(offset);
  270. endSPITransaction();
  271. }
  272. void ILI9341_t3::invertDisplay(boolean i)
  273. {
  274. beginSPITransaction(_clock);
  275. writecommand_last(i ? ILI9341_INVON : ILI9341_INVOFF);
  276. endSPITransaction();
  277. }
  278. /*
  279. uint8_t ILI9341_t3::readdata(void)
  280. {
  281. uint8_t r;
  282. // Try to work directly with SPI registers...
  283. // First wait until output queue is empty
  284. uint16_t wTimeout = 0xffff;
  285. while (((KINETISK_SPI0.SR) & (15 << 12)) && (--wTimeout)) ; // wait until empty
  286. // KINETISK_SPI0.MCR |= SPI_MCR_CLR_RXF; // discard any received data
  287. // KINETISK_SPI0.SR = SPI_SR_TCF;
  288. // Transfer a 0 out...
  289. writedata8_cont(0);
  290. // Now wait until completed.
  291. wTimeout = 0xffff;
  292. while (((KINETISK_SPI0.SR) & (15 << 12)) && (--wTimeout)) ; // wait until empty
  293. r = KINETISK_SPI0.POPR; // get the received byte... should check for it first...
  294. return r;
  295. }
  296. */
  297. uint8_t ILI9341_t3::readcommand8(uint8_t c, uint8_t index)
  298. {
  299. // Bail if not valid miso
  300. if (_miso == 0xff) return 0;
  301. #ifdef KINETISK
  302. uint16_t wTimeout = 0xffff;
  303. uint8_t r=0;
  304. beginSPITransaction(_clock);
  305. while (((KINETISK_SPI0.SR) & (15 << 12)) && (--wTimeout)) ; // wait until empty
  306. // Make sure the last frame has been sent...
  307. KINETISK_SPI0.SR = SPI_SR_TCF; // dlear it out;
  308. wTimeout = 0xffff;
  309. while (!((KINETISK_SPI0.SR) & SPI_SR_TCF) && (--wTimeout)) ; // wait until it says the last frame completed
  310. // clear out any current received bytes
  311. wTimeout = 0x10; // should not go more than 4...
  312. while ((((KINETISK_SPI0.SR) >> 4) & 0xf) && (--wTimeout)) {
  313. r = KINETISK_SPI0.POPR;
  314. }
  315. //writecommand(0xD9); // sekret command
  316. KINETISK_SPI0.PUSHR = 0xD9 | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
  317. // while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
  318. // writedata(0x10 + index);
  319. KINETISK_SPI0.PUSHR = (0x10 + index) | (pcs_data << 16) | SPI_PUSHR_CTAS(0);
  320. // while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
  321. // writecommand(c);
  322. KINETISK_SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
  323. // while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
  324. // readdata
  325. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0);
  326. // while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
  327. // Now wait until completed.
  328. wTimeout = 0xffff;
  329. while (((KINETISK_SPI0.SR) & (15 << 12)) && (--wTimeout)) ; // wait until empty
  330. // Make sure the last frame has been sent...
  331. KINETISK_SPI0.SR = SPI_SR_TCF; // dlear it out;
  332. wTimeout = 0xffff;
  333. while (!((KINETISK_SPI0.SR) & SPI_SR_TCF) && (--wTimeout)) ; // wait until it says the last frame completed
  334. wTimeout = 0x10; // should not go more than 4...
  335. // lets get all of the values on the FIFO
  336. while ((((KINETISK_SPI0.SR) >> 4) & 0xf) && (--wTimeout)) {
  337. r = KINETISK_SPI0.POPR;
  338. }
  339. endSPITransaction();
  340. return r; // get the received byte... should check for it first...
  341. #elif defined(__IMXRT1062__) // Teensy 4.x
  342. uint8_t r=0;
  343. //digitalWriteFast(2, HIGH); // oscilloscope trigger for testing
  344. //delayMicroseconds(10);
  345. //digitalWriteFast(2, LOW);
  346. beginSPITransaction(ILI9341_SPICLOCK_READ);
  347. if (_dcport) {
  348. // DC pin is controlled by GPIO
  349. DIRECT_WRITE_LOW(_dcport, _dcpinmask);
  350. IMXRT_LPSPI4_S.SR = LPSPI_SR_TCF | LPSPI_SR_FCF | LPSPI_SR_WCF;
  351. IMXRT_LPSPI4_S.TCR = LPSPI_TCR_FRAMESZ(7) | LPSPI_TCR_RXMSK | LPSPI_TCR_CONT;
  352. IMXRT_LPSPI4_S.TDR = 0xD9;
  353. while (!(IMXRT_LPSPI4_S.SR & LPSPI_SR_WCF)) ; // wait until word complete
  354. DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
  355. IMXRT_LPSPI4_S.SR = LPSPI_SR_TCF | LPSPI_SR_FCF | LPSPI_SR_WCF;
  356. IMXRT_LPSPI4_S.TDR = 0x10 + index;
  357. while (!(IMXRT_LPSPI4_S.SR & LPSPI_SR_WCF)) ; // wait until word complete
  358. DIRECT_WRITE_LOW(_dcport, _dcpinmask);
  359. IMXRT_LPSPI4_S.SR = LPSPI_SR_TCF | LPSPI_SR_FCF | LPSPI_SR_WCF;
  360. IMXRT_LPSPI4_S.TDR = c;
  361. while (!(IMXRT_LPSPI4_S.SR & LPSPI_SR_WCF)) ; // wait until word complete
  362. DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
  363. IMXRT_LPSPI4_S.SR = LPSPI_SR_TCF | LPSPI_SR_FCF | LPSPI_SR_WCF;
  364. IMXRT_LPSPI4_S.TCR = LPSPI_TCR_FRAMESZ(7);
  365. IMXRT_LPSPI4_S.TDR = 0x10 + index;
  366. while (!(IMXRT_LPSPI4_S.SR & LPSPI_SR_WCF)) ; // wait until word complete
  367. while (((IMXRT_LPSPI4_S.FSR >> 16) & 0x1F) == 0) ; // wait until rx fifo not empty
  368. r = IMXRT_LPSPI4_S.RDR;
  369. } else {
  370. // DC pin is controlled by SPI CS hardware
  371. }
  372. endSPITransaction();
  373. return r; // get the received byte... should check for it first...
  374. #else
  375. beginSPITransaction(_clock);
  376. writecommand_cont(0xD9);
  377. writedata8_cont(0x10 + index);
  378. writecommand_cont(c);
  379. writedata8_cont(0);
  380. uint8_t r = waitTransmitCompleteReturnLast();
  381. endSPITransaction();
  382. return r;
  383. #endif
  384. }
  385. uint16_t ILI9341_t3::readScanLine()
  386. {
  387. #ifdef KINETISK
  388. return 0; // TODO...
  389. #elif defined(__IMXRT1062__)
  390. uint16_t line=0;
  391. //digitalWriteFast(2, HIGH); // oscilloscope trigger for testing
  392. //delayMicroseconds(10);
  393. //digitalWriteFast(2, LOW);
  394. beginSPITransaction(ILI9341_SPICLOCK_READ);
  395. if (_dcport) {
  396. // DC pin is controlled by GPIO
  397. DIRECT_WRITE_LOW(_dcport, _dcpinmask);
  398. IMXRT_LPSPI4_S.SR = LPSPI_SR_TCF | LPSPI_SR_FCF | LPSPI_SR_WCF;
  399. IMXRT_LPSPI4_S.TCR = LPSPI_TCR_FRAMESZ(7) | LPSPI_TCR_RXMSK | LPSPI_TCR_CONT;
  400. IMXRT_LPSPI4_S.TDR = 0x45;
  401. while (!(IMXRT_LPSPI4_S.SR & LPSPI_SR_WCF)) ; // wait until word complete
  402. DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
  403. IMXRT_LPSPI4_S.TDR = 0;
  404. IMXRT_LPSPI4_S.TCR = LPSPI_TCR_FRAMESZ(15);
  405. IMXRT_LPSPI4_S.TDR = 0;
  406. while (!(IMXRT_LPSPI4_S.SR & LPSPI_SR_WCF)) ; // wait until word complete
  407. while (((IMXRT_LPSPI4_S.FSR >> 16) & 0x1F) == 0) ; // wait until rx fifo not empty
  408. line = IMXRT_LPSPI4_S.RDR >> 7;
  409. //if (IMXRT_LPSPI4_S.FSR != 0) Serial.println("ERROR: junk remains in FIFO!!!");
  410. } else {
  411. // DC pin is controlled by SPI CS hardware
  412. // TODO...
  413. }
  414. endSPITransaction();
  415. return line;
  416. #else
  417. return 0;
  418. #endif
  419. }
  420. // Read Pixel at x,y and get back 16-bit packed color
  421. uint16_t ILI9341_t3::readPixel(int16_t x, int16_t y)
  422. {
  423. if (_miso == 0xff) return 0xffff; // bail if not valid miso
  424. #ifdef KINETISK
  425. uint8_t dummy __attribute__((unused));
  426. uint8_t r,g,b;
  427. beginSPITransaction(ILI9341_SPICLOCK_READ);
  428. setAddr(x, y, x, y);
  429. writecommand_cont(ILI9341_RAMRD); // read from RAM
  430. waitTransmitComplete();
  431. // Push 4 bytes over SPI
  432. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0)| SPI_PUSHR_CONT;
  433. waitFifoEmpty(); // wait for both queues to be empty.
  434. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0)| SPI_PUSHR_CONT;
  435. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0)| SPI_PUSHR_CONT;
  436. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0)| SPI_PUSHR_EOQ;
  437. // Wait for End of Queue
  438. while ((KINETISK_SPI0.SR & SPI_SR_EOQF) == 0) ;
  439. KINETISK_SPI0.SR = SPI_SR_EOQF; // make sure it is clear
  440. // Read Pixel Data
  441. dummy = KINETISK_SPI0.POPR; // Read a DUMMY byte of GRAM
  442. r = KINETISK_SPI0.POPR; // Read a RED byte of GRAM
  443. g = KINETISK_SPI0.POPR; // Read a GREEN byte of GRAM
  444. b = KINETISK_SPI0.POPR; // Read a BLUE byte of GRAM
  445. endSPITransaction();
  446. return color565(r,g,b);
  447. #else
  448. // Kinetisk
  449. uint16_t colors = 0;
  450. readRect(x, y, 1, 1, &colors);
  451. return colors;
  452. #endif
  453. }
  454. // Now lets see if we can read in multiple pixels
  455. #ifdef KINETISK
  456. void ILI9341_t3::readRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *pcolors)
  457. {
  458. if (_miso == 0xff) return; // bail if not valid miso
  459. uint8_t dummy __attribute__((unused));
  460. uint8_t r,g,b;
  461. uint16_t c = w * h;
  462. beginSPITransaction(ILI9341_SPICLOCK_READ);
  463. setAddr(x, y, x+w-1, y+h-1);
  464. writecommand_cont(ILI9341_RAMRD); // read from RAM
  465. waitTransmitComplete();
  466. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0)| SPI_PUSHR_CONT | SPI_PUSHR_EOQ;
  467. while ((KINETISK_SPI0.SR & SPI_SR_EOQF) == 0) ;
  468. KINETISK_SPI0.SR = SPI_SR_EOQF; // make sure it is clear
  469. while ((KINETISK_SPI0.SR & 0xf0)) {
  470. dummy = KINETISK_SPI0.POPR; // Read a DUMMY byte but only once
  471. }
  472. c *= 3; // number of bytes we will transmit to the display
  473. while (c--) {
  474. if (c) {
  475. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0)| SPI_PUSHR_CONT;
  476. } else {
  477. KINETISK_SPI0.PUSHR = 0 | (pcs_data << 16) | SPI_PUSHR_CTAS(0)| SPI_PUSHR_EOQ;
  478. }
  479. // If last byte wait until all have come in...
  480. if (c == 0) {
  481. while ((KINETISK_SPI0.SR & SPI_SR_EOQF) == 0) ;
  482. KINETISK_SPI0.SR = SPI_SR_EOQF; // make sure it is clear
  483. }
  484. if ((KINETISK_SPI0.SR & 0xf0) >= 0x30) { // do we have at least 3 bytes in queue if so extract...
  485. r = KINETISK_SPI0.POPR; // Read a RED byte of GRAM
  486. g = KINETISK_SPI0.POPR; // Read a GREEN byte of GRAM
  487. b = KINETISK_SPI0.POPR; // Read a BLUE byte of GRAM
  488. *pcolors++ = color565(r,g,b);
  489. }
  490. // like waitFiroNotFull but does not pop our return queue
  491. while ((KINETISK_SPI0.SR & (15 << 12)) > (3 << 12)) ;
  492. }
  493. endSPITransaction();
  494. }
  495. #elif defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
  496. void ILI9341_t3::readRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *pcolors)
  497. {
  498. if (_miso == 0xff) return; // bail if not valid miso
  499. uint8_t rgb[3]; // RGB bytes received from the display
  500. uint8_t rgbIdx = 0;
  501. uint32_t txCount = w * h * 3; // number of bytes we will transmit to the display
  502. uint32_t rxCount = txCount; // number of bytes we will receive back from the display
  503. beginSPITransaction(ILI9341_SPICLOCK_READ);
  504. setAddr(x, y, x+w-1, y+h-1);
  505. writecommand_cont(ILI9341_RAMRD); // read from RAM
  506. // transmit a DUMMY byte before the color bytes
  507. writedata8_last(0); // BUGBUG:: maybe fix this as this will wait until the byte fully transfers through.
  508. while (txCount || rxCount) {
  509. // transmit another byte if possible
  510. if (txCount && (IMXRT_LPSPI4_S.SR & LPSPI_SR_TDF)) {
  511. txCount--;
  512. if (txCount) {
  513. IMXRT_LPSPI4_S.TDR = 0;
  514. } else {
  515. maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(7)); // remove the CONTINUE...
  516. while ((IMXRT_LPSPI4_S.SR & LPSPI_SR_TDF) == 0) ; // wait if queue was full
  517. IMXRT_LPSPI4_S.TDR = 0;
  518. }
  519. }
  520. // receive another byte if possible, and either skip it or store the color
  521. if (rxCount && !(IMXRT_LPSPI4_S.RSR & LPSPI_RSR_RXEMPTY)) {
  522. rgb[rgbIdx] = IMXRT_LPSPI4_S.RDR;
  523. rxCount--;
  524. rgbIdx++;
  525. if (rgbIdx == 3) {
  526. rgbIdx = 0;
  527. *pcolors++ = color565(rgb[0], rgb[1], rgb[2]);
  528. }
  529. }
  530. }
  531. // We should have received everything so should be done
  532. endSPITransaction();
  533. }
  534. #endif
  535. // Now lets see if we can writemultiple pixels
  536. void ILI9341_t3::writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors)
  537. {
  538. beginSPITransaction(_clock);
  539. setAddr(x, y, x+w-1, y+h-1);
  540. writecommand_cont(ILI9341_RAMWR);
  541. for(y=h; y>0; y--) {
  542. for(x=w; x>1; x--) {
  543. writedata16_cont(*pcolors++);
  544. }
  545. writedata16_last(*pcolors++);
  546. }
  547. endSPITransaction();
  548. }
  549. // writeRect8BPP - write 8 bit per pixel paletted bitmap
  550. // bitmap data in array at pixels, one byte per pixel
  551. // color palette data in array at palette
  552. void ILI9341_t3::writeRect8BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette )
  553. {
  554. beginSPITransaction(_clock);
  555. setAddr(x, y, x+w-1, y+h-1);
  556. writecommand_cont(ILI9341_RAMWR);
  557. for(y=h; y>0; y--) {
  558. for(x=w; x>1; x--) {
  559. writedata16_cont(palette[*pixels++]);
  560. }
  561. writedata16_last(palette[*pixels++]);
  562. }
  563. endSPITransaction();
  564. }
  565. // writeRect4BPP - write 4 bit per pixel paletted bitmap
  566. // bitmap data in array at pixels, 4 bits per pixel
  567. // color palette data in array at palette
  568. // width must be at least 2 pixels
  569. void ILI9341_t3::writeRect4BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette )
  570. {
  571. beginSPITransaction(_clock);
  572. setAddr(x, y, x+w-1, y+h-1);
  573. writecommand_cont(ILI9341_RAMWR);
  574. for(y=h; y>0; y--) {
  575. for(x=w; x>2; x-=2) {
  576. writedata16_cont(palette[((*pixels)>>4)&0xF]);
  577. writedata16_cont(palette[(*pixels++)&0xF]);
  578. }
  579. writedata16_cont(palette[((*pixels)>>4)&0xF]);
  580. writedata16_last(palette[(*pixels++)&0xF]);
  581. }
  582. endSPITransaction();
  583. }
  584. // writeRect2BPP - write 2 bit per pixel paletted bitmap
  585. // bitmap data in array at pixels, 4 bits per pixel
  586. // color palette data in array at palette
  587. // width must be at least 4 pixels
  588. void ILI9341_t3::writeRect2BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette )
  589. {
  590. beginSPITransaction(_clock);
  591. setAddr(x, y, x+w-1, y+h-1);
  592. writecommand_cont(ILI9341_RAMWR);
  593. for(y=h; y>0; y--) {
  594. for(x=w; x>4; x-=4) {
  595. //unrolled loop might be faster?
  596. writedata16_cont(palette[((*pixels)>>6)&0x3]);
  597. writedata16_cont(palette[((*pixels)>>4)&0x3]);
  598. writedata16_cont(palette[((*pixels)>>2)&0x3]);
  599. writedata16_cont(palette[(*pixels++)&0x3]);
  600. }
  601. writedata16_cont(palette[((*pixels)>>6)&0x3]);
  602. writedata16_cont(palette[((*pixels)>>4)&0x3]);
  603. writedata16_cont(palette[((*pixels)>>2)&0x3]);
  604. writedata16_last(palette[(*pixels++)&0x3]);
  605. }
  606. endSPITransaction();
  607. }
  608. // writeRect1BPP - write 1 bit per pixel paletted bitmap
  609. // bitmap data in array at pixels, 4 bits per pixel
  610. // color palette data in array at palette
  611. // width must be at least 8 pixels
  612. void ILI9341_t3::writeRect1BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette )
  613. {
  614. beginSPITransaction(_clock);
  615. setAddr(x, y, x+w-1, y+h-1);
  616. writecommand_cont(ILI9341_RAMWR);
  617. for(y=h; y>0; y--) {
  618. for(x=w; x>8; x-=8) {
  619. //unrolled loop might be faster?
  620. writedata16_cont(palette[((*pixels)>>7)&0x1]);
  621. writedata16_cont(palette[((*pixels)>>6)&0x1]);
  622. writedata16_cont(palette[((*pixels)>>5)&0x1]);
  623. writedata16_cont(palette[((*pixels)>>4)&0x1]);
  624. writedata16_cont(palette[((*pixels)>>3)&0x1]);
  625. writedata16_cont(palette[((*pixels)>>2)&0x1]);
  626. writedata16_cont(palette[((*pixels)>>1)&0x1]);
  627. writedata16_cont(palette[(*pixels++)&0x1]);
  628. }
  629. writedata16_cont(palette[((*pixels)>>7)&0x1]);
  630. writedata16_cont(palette[((*pixels)>>6)&0x1]);
  631. writedata16_cont(palette[((*pixels)>>5)&0x1]);
  632. writedata16_cont(palette[((*pixels)>>4)&0x1]);
  633. writedata16_cont(palette[((*pixels)>>3)&0x1]);
  634. writedata16_cont(palette[((*pixels)>>2)&0x1]);
  635. writedata16_cont(palette[((*pixels)>>1)&0x1]);
  636. writedata16_last(palette[(*pixels++)&0x1]);
  637. }
  638. endSPITransaction();
  639. }
  640. static const uint8_t init_commands[] = {
  641. 4, 0xEF, 0x03, 0x80, 0x02,
  642. 4, 0xCF, 0x00, 0XC1, 0X30,
  643. 5, 0xED, 0x64, 0x03, 0X12, 0X81,
  644. 4, 0xE8, 0x85, 0x00, 0x78,
  645. 6, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
  646. 2, 0xF7, 0x20,
  647. 3, 0xEA, 0x00, 0x00,
  648. 2, ILI9341_PWCTR1, 0x23, // Power control
  649. 2, ILI9341_PWCTR2, 0x10, // Power control
  650. 3, ILI9341_VMCTR1, 0x3e, 0x28, // VCM control
  651. 2, ILI9341_VMCTR2, 0x86, // VCM control2
  652. 2, ILI9341_MADCTL, 0x48, // Memory Access Control
  653. 2, ILI9341_PIXFMT, 0x55,
  654. 3, ILI9341_FRMCTR1, 0x00, 0x18,
  655. 4, ILI9341_DFUNCTR, 0x08, 0x82, 0x27, // Display Function Control
  656. 2, 0xF2, 0x00, // Gamma Function Disable
  657. 2, ILI9341_GAMMASET, 0x01, // Gamma curve selected
  658. 16, ILI9341_GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08,
  659. 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma
  660. 16, ILI9341_GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07,
  661. 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma
  662. 3, 0xb1, 0x00, 0x10, // FrameRate Control 119Hz
  663. 0
  664. };
  665. void ILI9341_t3::begin(void)
  666. {
  667. // verify SPI pins are valid;
  668. #ifdef KINETISK
  669. #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
  670. // Allow to work with mimimum of MOSI and SCK
  671. if ((_mosi == 255 || _mosi == 11 || _mosi == 7 || _mosi == 28) && (_sclk == 255 || _sclk == 13 || _sclk == 14 || _sclk == 27))
  672. #else
  673. if ((_mosi == 255 || _mosi == 11 || _mosi == 7) && (_sclk == 255 || _sclk == 13 || _sclk == 14))
  674. #endif
  675. {
  676. if (_mosi != 255) SPI.setMOSI(_mosi);
  677. if (_sclk != 255) SPI.setSCK(_sclk);
  678. // Now see if valid MISO
  679. #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
  680. if (_miso == 12 || _miso == 8 || _miso == 39)
  681. #else
  682. if (_miso == 12 || _miso == 8)
  683. #endif
  684. {
  685. SPI.setMISO(_miso);
  686. } else {
  687. _miso = 0xff; // set miso to 255 as flag it is bad
  688. }
  689. } else {
  690. return; // not valid pins...
  691. }
  692. SPI.begin();
  693. if (SPI.pinIsChipSelect(_cs, _dc)) {
  694. pcs_data = SPI.setCS(_cs);
  695. pcs_command = pcs_data | SPI.setCS(_dc);
  696. } else {
  697. // See if at least DC is on chipselect pin, if so try to limp along...
  698. if (SPI.pinIsChipSelect(_dc)) {
  699. pcs_data = 0;
  700. pcs_command = pcs_data | SPI.setCS(_dc);
  701. pinMode(_cs, OUTPUT);
  702. _csport = portOutputRegister(digitalPinToPort(_cs));
  703. _cspinmask = digitalPinToBitMask(_cs);
  704. } else {
  705. pcs_data = 0;
  706. }
  707. }
  708. #elif defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
  709. _pending_rx_count = 0;
  710. SPI.begin();
  711. _csport = portOutputRegister(_cs);
  712. _cspinmask = digitalPinToBitMask(_cs);
  713. pinMode(_cs, OUTPUT);
  714. DIRECT_WRITE_HIGH(_csport, _cspinmask);
  715. _spi_tcr_current = IMXRT_LPSPI4_S.TCR; // get the current TCR value
  716. // TODO: Need to setup DC to actually work.
  717. if (SPI.pinIsChipSelect(_dc)) {
  718. uint8_t dc_cs_index = SPI.setCS(_dc);
  719. _dcport = 0;
  720. _dcpinmask = 0;
  721. dc_cs_index--; // convert to 0 based
  722. _tcr_dc_assert = LPSPI_TCR_PCS(dc_cs_index);
  723. _tcr_dc_not_assert = LPSPI_TCR_PCS(3);
  724. } else {
  725. //Serial.println("ILI9341_t3n: Error not DC is not valid hardware CS pin");
  726. _dcport = portOutputRegister(_dc);
  727. _dcpinmask = digitalPinToBitMask(_dc);
  728. pinMode(_dc, OUTPUT);
  729. DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
  730. _tcr_dc_assert = LPSPI_TCR_PCS(0);
  731. _tcr_dc_not_assert = LPSPI_TCR_PCS(1);
  732. }
  733. maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(7));
  734. #endif
  735. // toggle RST low to reset
  736. if (_rst < 255) {
  737. pinMode(_rst, OUTPUT);
  738. digitalWrite(_rst, HIGH);
  739. delay(5);
  740. digitalWrite(_rst, LOW);
  741. delay(20);
  742. digitalWrite(_rst, HIGH);
  743. delay(150);
  744. }
  745. /*
  746. uint8_t x = readcommand8(ILI9341_RDMODE);
  747. Serial.print("\nDisplay Power Mode: 0x"); Serial.println(x, HEX);
  748. x = readcommand8(ILI9341_RDMADCTL);
  749. Serial.print("\nMADCTL Mode: 0x"); Serial.println(x, HEX);
  750. x = readcommand8(ILI9341_RDPIXFMT);
  751. Serial.print("\nPixel Format: 0x"); Serial.println(x, HEX);
  752. x = readcommand8(ILI9341_RDIMGFMT);
  753. Serial.print("\nImage Format: 0x"); Serial.println(x, HEX);
  754. x = readcommand8(ILI9341_RDSELFDIAG);
  755. Serial.print("\nSelf Diagnostic: 0x"); Serial.println(x, HEX);
  756. */
  757. beginSPITransaction(_clock);
  758. const uint8_t *addr = init_commands;
  759. while (1) {
  760. uint8_t count = *addr++;
  761. if (count-- == 0) break;
  762. writecommand_cont(*addr++);
  763. while (count-- > 0) {
  764. writedata8_cont(*addr++);
  765. }
  766. }
  767. writecommand_last(ILI9341_SLPOUT); // Exit Sleep
  768. endSPITransaction();
  769. delay(120);
  770. beginSPITransaction(_clock);
  771. writecommand_last(ILI9341_DISPON); // Display on
  772. endSPITransaction();
  773. }
  774. /*
  775. This is the core graphics library for all our displays, providing a common
  776. set of graphics primitives (points, lines, circles, etc.). It needs to be
  777. paired with a hardware-specific library for each display device we carry
  778. (to handle the lower-level functions).
  779. Adafruit invests time and resources providing this open source code, please
  780. support Adafruit & open-source hardware by purchasing products from Adafruit!
  781. Copyright (c) 2013 Adafruit Industries. All rights reserved.
  782. Redistribution and use in source and binary forms, with or without
  783. modification, are permitted provided that the following conditions are met:
  784. - Redistributions of source code must retain the above copyright notice,
  785. this list of conditions and the following disclaimer.
  786. - Redistributions in binary form must reproduce the above copyright notice,
  787. this list of conditions and the following disclaimer in the documentation
  788. and/or other materials provided with the distribution.
  789. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  790. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  791. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  792. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  793. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  794. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  795. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  796. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  797. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  798. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  799. POSSIBILITY OF SUCH DAMAGE.
  800. */
  801. //#include "glcdfont.c"
  802. extern "C" const unsigned char glcdfont[];
  803. // Draw a circle outline
  804. void ILI9341_t3::drawCircle(int16_t x0, int16_t y0, int16_t r,
  805. uint16_t color) {
  806. int16_t f = 1 - r;
  807. int16_t ddF_x = 1;
  808. int16_t ddF_y = -2 * r;
  809. int16_t x = 0;
  810. int16_t y = r;
  811. drawPixel(x0 , y0+r, color);
  812. drawPixel(x0 , y0-r, color);
  813. drawPixel(x0+r, y0 , color);
  814. drawPixel(x0-r, y0 , color);
  815. while (x<y) {
  816. if (f >= 0) {
  817. y--;
  818. ddF_y += 2;
  819. f += ddF_y;
  820. }
  821. x++;
  822. ddF_x += 2;
  823. f += ddF_x;
  824. drawPixel(x0 + x, y0 + y, color);
  825. drawPixel(x0 - x, y0 + y, color);
  826. drawPixel(x0 + x, y0 - y, color);
  827. drawPixel(x0 - x, y0 - y, color);
  828. drawPixel(x0 + y, y0 + x, color);
  829. drawPixel(x0 - y, y0 + x, color);
  830. drawPixel(x0 + y, y0 - x, color);
  831. drawPixel(x0 - y, y0 - x, color);
  832. }
  833. }
  834. void ILI9341_t3::drawCircleHelper( int16_t x0, int16_t y0,
  835. int16_t r, uint8_t cornername, uint16_t color) {
  836. int16_t f = 1 - r;
  837. int16_t ddF_x = 1;
  838. int16_t ddF_y = -2 * r;
  839. int16_t x = 0;
  840. int16_t y = r;
  841. int xold;
  842. xold = x;
  843. while (x<y) {
  844. if (f >= 0) {
  845. y--;
  846. ddF_y += 2;
  847. f += ddF_y;
  848. }
  849. x++;
  850. ddF_x += 2;
  851. f += ddF_x;
  852. if (f >= 0 || x == y) { // time to draw the new line segment
  853. if (cornername & 0x4) {
  854. drawFastHLine(x0 + xold+1, y0 + y, x-xold, color);
  855. drawFastVLine(x0 + y, y0 + xold+1, x-xold, color);
  856. }
  857. if (cornername & 0x2) {
  858. drawFastHLine(x0 + xold+1, y0 - y, x-xold, color);
  859. drawFastVLine(x0 + y, y0 - x, x-xold, color);
  860. }
  861. if (cornername & 0x8) {
  862. drawFastVLine(x0 - y, y0 + xold+1, x-xold, color);
  863. drawFastHLine(x0 - x, y0 + y, x-xold, color);
  864. }
  865. if (cornername & 0x1) {
  866. drawFastVLine(x0 - y, y0 - x, x-xold, color);
  867. drawFastHLine(x0 - x, y0 - y, x-xold, color);
  868. }
  869. xold = x;
  870. } // draw new line segment
  871. }
  872. }
  873. void ILI9341_t3::fillCircle(int16_t x0, int16_t y0, int16_t r,
  874. uint16_t color) {
  875. drawFastVLine(x0, y0-r, 2*r+1, color);
  876. fillCircleHelper(x0, y0, r, 3, 0, color);
  877. }
  878. // Used to do circles and roundrects
  879. void ILI9341_t3::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
  880. uint8_t cornername, int16_t delta, uint16_t color) {
  881. int16_t f = 1 - r;
  882. int16_t ddF_x = 1;
  883. int16_t ddF_y = -2 * r;
  884. int16_t x = 0;
  885. int16_t y = r;
  886. while (x<y) {
  887. if (f >= 0) {
  888. y--;
  889. ddF_y += 2;
  890. f += ddF_y;
  891. }
  892. x++;
  893. ddF_x += 2;
  894. f += ddF_x;
  895. if (cornername & 0x1) {
  896. drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
  897. drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
  898. }
  899. if (cornername & 0x2) {
  900. drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
  901. drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
  902. }
  903. }
  904. }
  905. // Bresenham's algorithm - thx wikpedia
  906. void ILI9341_t3::drawLine(int16_t x0, int16_t y0,
  907. int16_t x1, int16_t y1, uint16_t color)
  908. {
  909. if (y0 == y1) {
  910. if (x1 > x0) {
  911. drawFastHLine(x0, y0, x1 - x0 + 1, color);
  912. } else if (x1 < x0) {
  913. drawFastHLine(x1, y0, x0 - x1 + 1, color);
  914. } else {
  915. drawPixel(x0, y0, color);
  916. }
  917. return;
  918. } else if (x0 == x1) {
  919. if (y1 > y0) {
  920. drawFastVLine(x0, y0, y1 - y0 + 1, color);
  921. } else {
  922. drawFastVLine(x0, y1, y0 - y1 + 1, color);
  923. }
  924. return;
  925. }
  926. bool steep = abs(y1 - y0) > abs(x1 - x0);
  927. if (steep) {
  928. swap(x0, y0);
  929. swap(x1, y1);
  930. }
  931. if (x0 > x1) {
  932. swap(x0, x1);
  933. swap(y0, y1);
  934. }
  935. int16_t dx, dy;
  936. dx = x1 - x0;
  937. dy = abs(y1 - y0);
  938. int16_t err = dx / 2;
  939. int16_t ystep;
  940. if (y0 < y1) {
  941. ystep = 1;
  942. } else {
  943. ystep = -1;
  944. }
  945. beginSPITransaction(_clock);
  946. int16_t xbegin = x0;
  947. if (steep) {
  948. for (; x0<=x1; x0++) {
  949. err -= dy;
  950. if (err < 0) {
  951. int16_t len = x0 - xbegin;
  952. if (len) {
  953. VLine(y0, xbegin, len + 1, color);
  954. } else {
  955. Pixel(y0, x0, color);
  956. }
  957. xbegin = x0 + 1;
  958. y0 += ystep;
  959. err += dx;
  960. }
  961. }
  962. if (x0 > xbegin + 1) {
  963. VLine(y0, xbegin, x0 - xbegin, color);
  964. }
  965. } else {
  966. for (; x0<=x1; x0++) {
  967. err -= dy;
  968. if (err < 0) {
  969. int16_t len = x0 - xbegin;
  970. if (len) {
  971. HLine(xbegin, y0, len + 1, color);
  972. } else {
  973. Pixel(x0, y0, color);
  974. }
  975. xbegin = x0 + 1;
  976. y0 += ystep;
  977. err += dx;
  978. }
  979. }
  980. if (x0 > xbegin + 1) {
  981. HLine(xbegin, y0, x0 - xbegin, color);
  982. }
  983. }
  984. writecommand_last(ILI9341_NOP);
  985. endSPITransaction();
  986. }
  987. // Draw a rectangle
  988. void ILI9341_t3::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
  989. {
  990. beginSPITransaction(_clock);
  991. HLine(x, y, w, color);
  992. HLine(x, y+h-1, w, color);
  993. VLine(x, y, h, color);
  994. VLine(x+w-1, y, h, color);
  995. writecommand_last(ILI9341_NOP);
  996. endSPITransaction();
  997. }
  998. // Draw a rounded rectangle
  999. void ILI9341_t3::drawRoundRect(int16_t x, int16_t y, int16_t w,
  1000. int16_t h, int16_t r, uint16_t color) {
  1001. // smarter version
  1002. drawFastHLine(x+r , y , w-2*r, color); // Top
  1003. drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom
  1004. drawFastVLine(x , y+r , h-2*r, color); // Left
  1005. drawFastVLine(x+w-1, y+r , h-2*r, color); // Right
  1006. // draw four corners
  1007. drawCircleHelper(x+r , y+r , r, 1, color);
  1008. drawCircleHelper(x+w-r-1, y+r , r, 2, color);
  1009. drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
  1010. drawCircleHelper(x+r , y+h-r-1, r, 8, color);
  1011. }
  1012. // Fill a rounded rectangle
  1013. void ILI9341_t3::fillRoundRect(int16_t x, int16_t y, int16_t w,
  1014. int16_t h, int16_t r, uint16_t color) {
  1015. // smarter version
  1016. fillRect(x+r, y, w-2*r, h, color);
  1017. // draw four corners
  1018. fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
  1019. fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color);
  1020. }
  1021. // Draw a triangle
  1022. void ILI9341_t3::drawTriangle(int16_t x0, int16_t y0,
  1023. int16_t x1, int16_t y1,
  1024. int16_t x2, int16_t y2, uint16_t color) {
  1025. drawLine(x0, y0, x1, y1, color);
  1026. drawLine(x1, y1, x2, y2, color);
  1027. drawLine(x2, y2, x0, y0, color);
  1028. }
  1029. // Fill a triangle
  1030. void ILI9341_t3::fillTriangle ( int16_t x0, int16_t y0,
  1031. int16_t x1, int16_t y1,
  1032. int16_t x2, int16_t y2, uint16_t color) {
  1033. int16_t a, b, y, last;
  1034. // Sort coordinates by Y order (y2 >= y1 >= y0)
  1035. if (y0 > y1) {
  1036. swap(y0, y1); swap(x0, x1);
  1037. }
  1038. if (y1 > y2) {
  1039. swap(y2, y1); swap(x2, x1);
  1040. }
  1041. if (y0 > y1) {
  1042. swap(y0, y1); swap(x0, x1);
  1043. }
  1044. if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
  1045. a = b = x0;
  1046. if(x1 < a) a = x1;
  1047. else if(x1 > b) b = x1;
  1048. if(x2 < a) a = x2;
  1049. else if(x2 > b) b = x2;
  1050. drawFastHLine(a, y0, b-a+1, color);
  1051. return;
  1052. }
  1053. int32_t
  1054. dx01 = x1 - x0,
  1055. dy01 = y1 - y0,
  1056. dx02 = x2 - x0,
  1057. dy02 = y2 - y0,
  1058. dx12 = x2 - x1,
  1059. dy12 = y2 - y1,
  1060. sa = 0,
  1061. sb = 0;
  1062. // For upper part of triangle, find scanline crossings for segments
  1063. // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
  1064. // is included here (and second loop will be skipped, avoiding a /0
  1065. // error there), otherwise scanline y1 is skipped here and handled
  1066. // in the second loop...which also avoids a /0 error here if y0=y1
  1067. // (flat-topped triangle).
  1068. if(y1 == y2) last = y1; // Include y1 scanline
  1069. else last = y1-1; // Skip it
  1070. for(y=y0; y<=last; y++) {
  1071. a = x0 + sa / dy01;
  1072. b = x0 + sb / dy02;
  1073. sa += dx01;
  1074. sb += dx02;
  1075. /* longhand:
  1076. a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
  1077. b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
  1078. */
  1079. if(a > b) swap(a,b);
  1080. drawFastHLine(a, y, b-a+1, color);
  1081. }
  1082. // For lower part of triangle, find scanline crossings for segments
  1083. // 0-2 and 1-2. This loop is skipped if y1=y2.
  1084. sa = dx12 * (y - y1);
  1085. sb = dx02 * (y - y0);
  1086. for(; y<=y2; y++) {
  1087. a = x1 + sa / dy12;
  1088. b = x0 + sb / dy02;
  1089. sa += dx12;
  1090. sb += dx02;
  1091. /* longhand:
  1092. a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
  1093. b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
  1094. */
  1095. if(a > b) swap(a,b);
  1096. drawFastHLine(a, y, b-a+1, color);
  1097. }
  1098. }
  1099. void ILI9341_t3::drawBitmap(int16_t x, int16_t y,
  1100. const uint8_t *bitmap, int16_t w, int16_t h,
  1101. uint16_t color) {
  1102. int16_t i, j, byteWidth = (w + 7) / 8;
  1103. for(j=0; j<h; j++) {
  1104. for(i=0; i<w; i++ ) {
  1105. if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
  1106. drawPixel(x+i, y+j, color);
  1107. }
  1108. }
  1109. }
  1110. }
  1111. size_t ILI9341_t3::write(uint8_t c)
  1112. {
  1113. if (font) {
  1114. if (c == '\n') {
  1115. cursor_y += font->line_space; // Fix linefeed. Added by T.T., SoftEgg
  1116. cursor_x = 0;
  1117. } else {
  1118. drawFontChar(c);
  1119. }
  1120. } else {
  1121. if (c == '\n') {
  1122. cursor_y += textsize*8;
  1123. cursor_x = 0;
  1124. } else if (c == '\r') {
  1125. // skip em
  1126. } else {
  1127. drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
  1128. cursor_x += textsize*6;
  1129. if (wrap && (cursor_x > (_width - textsize*6))) {
  1130. cursor_y += textsize*8;
  1131. cursor_x = 0;
  1132. }
  1133. }
  1134. }
  1135. return 1;
  1136. }
  1137. // Draw a character
  1138. void ILI9341_t3::drawChar(int16_t x, int16_t y, unsigned char c,
  1139. uint16_t fgcolor, uint16_t bgcolor, uint8_t size)
  1140. {
  1141. if((x >= _width) || // Clip right
  1142. (y >= _height) || // Clip bottom
  1143. ((x + 6 * size - 1) < 0) || // Clip left TODO: is this correct?
  1144. ((y + 8 * size - 1) < 0)) // Clip top TODO: is this correct?
  1145. return;
  1146. if (fgcolor == bgcolor) {
  1147. int16_t xoff, yoff, count;
  1148. uint8_t mask = 0x1;
  1149. uint8_t *s = (uint8_t *)&glcdfont[c * 5];
  1150. for (yoff=0; yoff < 8; yoff++) {
  1151. xoff = 0;
  1152. while (xoff < 5) {
  1153. while (xoff < 5 && !(s[xoff] & mask))
  1154. xoff++; // skip transparent bg
  1155. count = 0;
  1156. while (xoff < 5 && s[xoff] & mask) { // fg
  1157. count++;
  1158. xoff++;
  1159. }
  1160. if (count) {
  1161. if (size == 1)
  1162. drawFastHLine(x+xoff-count, y + yoff, count, fgcolor);
  1163. else
  1164. fillRect(x + (xoff-count) * size, y + yoff * size, count * size, size, fgcolor);
  1165. }
  1166. } // while xoff
  1167. mask = mask << 1;
  1168. } // for y
  1169. } else {
  1170. // This solid background approach is about 5 time faster
  1171. beginSPITransaction(_clock);
  1172. setAddr(x, y, x + 6 * size - 1, y + 8 * size - 1);
  1173. writecommand_cont(ILI9341_RAMWR);
  1174. uint8_t xr, yr;
  1175. uint8_t mask = 0x01;
  1176. uint16_t color;
  1177. for (y=0; y < 8; y++) {
  1178. for (yr=0; yr < size; yr++) {
  1179. for (x=0; x < 5; x++) {
  1180. color = (glcdfont[c * 5 + x] & mask) ? fgcolor : bgcolor;
  1181. for (xr=0; xr < size; xr++) {
  1182. writedata16_cont(color);
  1183. }
  1184. }
  1185. for (xr=0; xr < size; xr++) {
  1186. writedata16_cont(bgcolor);
  1187. }
  1188. }
  1189. mask = mask << 1;
  1190. }
  1191. writecommand_last(ILI9341_NOP);
  1192. endSPITransaction();
  1193. }
  1194. }
  1195. static inline uint32_t fetchbit(const uint8_t *p, uint32_t index)
  1196. {
  1197. return (p[index >> 3] & (0x80 >> (index & 7)));
  1198. }
  1199. static uint32_t fetchbits_unsigned(const uint8_t *p, uint32_t index, uint32_t required)
  1200. {
  1201. uint32_t val;
  1202. uint8_t *s = (uint8_t *)&p[index>>3];
  1203. #ifdef UNALIGNED_IS_SAFE
  1204. val = *(uint32_t *)s; // read 4 bytes - unaligned is ok
  1205. val = __builtin_bswap32(val); // change to big-endian order
  1206. #else
  1207. val = s[0] << 24;
  1208. val |= (s[1] << 16);
  1209. val |= (s[2] << 8);
  1210. val |= s[3];
  1211. #endif
  1212. val <<= (index & 7); // shift out used bits
  1213. if (32 - (index & 7) < required) { // need to get more bits
  1214. val |= (s[4] >> (8 - (index & 7)));
  1215. }
  1216. val >>= (32-required); // right align the bits
  1217. return val;
  1218. }
  1219. static uint32_t fetchbits_signed(const uint8_t *p, uint32_t index, uint32_t required)
  1220. {
  1221. uint32_t val = fetchbits_unsigned(p, index, required);
  1222. if (val & (1 << (required - 1))) {
  1223. return (int32_t)val - (1 << required);
  1224. }
  1225. return (int32_t)val;
  1226. }
  1227. // Measure the dimensions for a single character
  1228. void ILI9341_t3::measureChar(unsigned char c, uint16_t* w, uint16_t* h) {
  1229. // Treat non-breaking space as normal space
  1230. if (c == 0xa0) {
  1231. c = ' ';
  1232. }
  1233. // Is current font a T3 font or the default Adafruit-GFX font?
  1234. if (font) {
  1235. // ILI9341_T3 font
  1236. *h = font->cap_height;
  1237. *w = 0;
  1238. uint32_t bitoffset;
  1239. const uint8_t *data;
  1240. if (c >= font->index1_first && c <= font->index1_last) {
  1241. bitoffset = c - font->index1_first;
  1242. bitoffset *= font->bits_index;
  1243. }
  1244. else if (c >= font->index2_first && c <= font->index2_last) {
  1245. bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
  1246. bitoffset *= font->bits_index;
  1247. }
  1248. else if (font->unicode) {
  1249. return; // TODO: implement sparse unicode
  1250. }
  1251. else {
  1252. return;
  1253. }
  1254. data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
  1255. uint32_t encoding = fetchbits_unsigned(data, 0, 3);
  1256. if (encoding != 0) return;
  1257. //uint32_t width =
  1258. fetchbits_unsigned(data, 3, font->bits_width);
  1259. bitoffset = font->bits_width + 3;
  1260. //uint32_t height =
  1261. fetchbits_unsigned(data, bitoffset, font->bits_height);
  1262. bitoffset += font->bits_height;
  1263. //int32_t xoffset =
  1264. fetchbits_signed(data, bitoffset, font->bits_xoffset);
  1265. bitoffset += font->bits_xoffset;
  1266. //int32_t yoffset =
  1267. fetchbits_signed(data, bitoffset, font->bits_yoffset);
  1268. bitoffset += font->bits_yoffset;
  1269. uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
  1270. *w = delta;
  1271. }
  1272. else {
  1273. // Adafruit-GFX default font has fixed 6x8 dimensions
  1274. *w = 6 * textsize;
  1275. *h = 8 * textsize;
  1276. }
  1277. }
  1278. void ILI9341_t3::drawFontChar(unsigned int c)
  1279. {
  1280. uint32_t bitoffset;
  1281. const uint8_t *data;
  1282. //Serial.printf("drawFontChar %d\n", c);
  1283. if (c >= font->index1_first && c <= font->index1_last) {
  1284. bitoffset = c - font->index1_first;
  1285. bitoffset *= font->bits_index;
  1286. } else if (c >= font->index2_first && c <= font->index2_last) {
  1287. bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
  1288. bitoffset *= font->bits_index;
  1289. } else if (font->unicode) {
  1290. return; // TODO: implement sparse unicode
  1291. } else {
  1292. return;
  1293. }
  1294. //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
  1295. data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
  1296. uint32_t encoding = fetchbits_unsigned(data, 0, 3);
  1297. if (encoding != 0) return;
  1298. uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
  1299. bitoffset = font->bits_width + 3;
  1300. uint32_t height = fetchbits_unsigned(data, bitoffset, font->bits_height);
  1301. bitoffset += font->bits_height;
  1302. //Serial.printf(" size = %d,%d\n", width, height);
  1303. int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
  1304. bitoffset += font->bits_xoffset;
  1305. int32_t yoffset = fetchbits_signed(data, bitoffset, font->bits_yoffset);
  1306. bitoffset += font->bits_yoffset;
  1307. //Serial.printf(" offset = %d,%d\n", xoffset, yoffset);
  1308. uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
  1309. bitoffset += font->bits_delta;
  1310. //Serial.printf(" delta = %d\n", delta);
  1311. //Serial.printf(" cursor = %d,%d\n", cursor_x, cursor_y);
  1312. // horizontally, we draw every pixel, or none at all
  1313. if (cursor_x < 0) cursor_x = 0;
  1314. int32_t origin_x = cursor_x + xoffset;
  1315. if (origin_x < 0) {
  1316. cursor_x -= xoffset;
  1317. origin_x = 0;
  1318. }
  1319. if (origin_x + (int)width > _width) {
  1320. if (!wrap) return;
  1321. origin_x = 0;
  1322. if (xoffset >= 0) {
  1323. cursor_x = 0;
  1324. } else {
  1325. cursor_x = -xoffset;
  1326. }
  1327. cursor_y += font->line_space;
  1328. }
  1329. if (cursor_y >= _height) return;
  1330. cursor_x += delta;
  1331. // vertically, the top and/or bottom can be clipped
  1332. int32_t origin_y = cursor_y + font->cap_height - height - yoffset;
  1333. //Serial.printf(" origin = %d,%d\n", origin_x, origin_y);
  1334. // TODO: compute top skip and number of lines
  1335. int32_t linecount = height;
  1336. //uint32_t loopcount = 0;
  1337. uint32_t y = origin_y;
  1338. while (linecount) {
  1339. //Serial.printf(" linecount = %d\n", linecount);
  1340. uint32_t b = fetchbit(data, bitoffset++);
  1341. if (b == 0) {
  1342. //Serial.println(" single line");
  1343. uint32_t x = 0;
  1344. do {
  1345. uint32_t xsize = width - x;
  1346. if (xsize > 32) xsize = 32;
  1347. uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
  1348. drawFontBits(bits, xsize, origin_x + x, y, 1);
  1349. bitoffset += xsize;
  1350. x += xsize;
  1351. } while (x < width);
  1352. y++;
  1353. linecount--;
  1354. } else {
  1355. uint32_t n = fetchbits_unsigned(data, bitoffset, 3) + 2;
  1356. bitoffset += 3;
  1357. uint32_t x = 0;
  1358. do {
  1359. uint32_t xsize = width - x;
  1360. if (xsize > 32) xsize = 32;
  1361. //Serial.printf(" multi line %d\n", n);
  1362. uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
  1363. drawFontBits(bits, xsize, origin_x + x, y, n);
  1364. bitoffset += xsize;
  1365. x += xsize;
  1366. } while (x < width);
  1367. y += n;
  1368. linecount -= n;
  1369. }
  1370. //if (++loopcount > 100) {
  1371. //Serial.println(" abort draw loop");
  1372. //break;
  1373. //}
  1374. }
  1375. }
  1376. //strPixelLen - gets pixel length of given ASCII string
  1377. int16_t ILI9341_t3::strPixelLen(char * str)
  1378. {
  1379. // Serial.printf("strPixelLen %s\n", str);
  1380. if (!str) return(0);
  1381. uint16_t len=0, maxlen=0;
  1382. while (*str)
  1383. {
  1384. if (*str=='\n')
  1385. {
  1386. if ( len > maxlen )
  1387. {
  1388. maxlen=len;
  1389. len=0;
  1390. }
  1391. }
  1392. else
  1393. {
  1394. if (!font)
  1395. {
  1396. len+=textsize*6;
  1397. }
  1398. else
  1399. {
  1400. uint32_t bitoffset;
  1401. const uint8_t *data;
  1402. uint16_t c = *str;
  1403. // Serial.printf("char %c(%d)\n", c,c);
  1404. if (c >= font->index1_first && c <= font->index1_last) {
  1405. bitoffset = c - font->index1_first;
  1406. bitoffset *= font->bits_index;
  1407. } else if (c >= font->index2_first && c <= font->index2_last) {
  1408. bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
  1409. bitoffset *= font->bits_index;
  1410. } else if (font->unicode) {
  1411. continue;
  1412. } else {
  1413. continue;
  1414. }
  1415. //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
  1416. data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
  1417. uint32_t encoding = fetchbits_unsigned(data, 0, 3);
  1418. if (encoding != 0) continue;
  1419. // uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
  1420. // Serial.printf(" width = %d\n", width);
  1421. bitoffset = font->bits_width + 3;
  1422. bitoffset += font->bits_height;
  1423. // int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
  1424. // Serial.printf(" xoffset = %d\n", xoffset);
  1425. bitoffset += font->bits_xoffset;
  1426. bitoffset += font->bits_yoffset;
  1427. uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
  1428. bitoffset += font->bits_delta;
  1429. // Serial.printf(" delta = %d\n", delta);
  1430. len += delta;//+width-xoffset;
  1431. // Serial.printf(" len = %d\n", len);
  1432. if ( len > maxlen )
  1433. {
  1434. maxlen=len;
  1435. // Serial.printf(" maxlen = %d\n", maxlen);
  1436. }
  1437. }
  1438. }
  1439. str++;
  1440. }
  1441. // Serial.printf("Return maxlen = %d\n", maxlen);
  1442. return( maxlen );
  1443. }
  1444. void ILI9341_t3::drawFontBits(uint32_t bits, uint32_t numbits, uint32_t x, uint32_t y, uint32_t repeat)
  1445. {
  1446. if (bits == 0) return;
  1447. beginSPITransaction(_clock);
  1448. uint32_t w;
  1449. bits <<= (32-numbits); // left align bits
  1450. do {
  1451. w = __builtin_clz(bits); // skip over zeros
  1452. if (w > numbits) w = numbits;
  1453. numbits -= w;
  1454. x += w;
  1455. bits <<= w;
  1456. bits = ~bits; // invert to count 1s as 0s
  1457. w = __builtin_clz(bits);
  1458. if (w > numbits) w = numbits;
  1459. numbits -= w;
  1460. bits <<= w;
  1461. bits = ~bits; // invert back to original polarity
  1462. if (w > 0) {
  1463. x += w;
  1464. setAddr(x-w, y, x-1, y+repeat-1); // write a block of pixels w x repeat sized
  1465. writecommand_cont(ILI9341_RAMWR); // write to RAM
  1466. w *= repeat;
  1467. while (w-- > 1) { // draw line
  1468. writedata16_cont(textcolor);
  1469. }
  1470. writedata16_last(textcolor);
  1471. }
  1472. } while (numbits > 0);
  1473. endSPITransaction();
  1474. }
  1475. void ILI9341_t3::setCursor(int16_t x, int16_t y) {
  1476. if (x < 0) x = 0;
  1477. else if (x >= _width) x = _width - 1;
  1478. cursor_x = x;
  1479. if (y < 0) y = 0;
  1480. else if (y >= _height) y = _height - 1;
  1481. cursor_y = y;
  1482. }
  1483. void ILI9341_t3::getCursor(int16_t *x, int16_t *y) {
  1484. *x = cursor_x;
  1485. *y = cursor_y;
  1486. }
  1487. void ILI9341_t3::setTextSize(uint8_t s) {
  1488. textsize = (s > 0) ? s : 1;
  1489. }
  1490. uint8_t ILI9341_t3::getTextSize() {
  1491. return textsize;
  1492. }
  1493. void ILI9341_t3::setTextColor(uint16_t c) {
  1494. // For 'transparent' background, we'll set the bg
  1495. // to the same as fg instead of using a flag
  1496. textcolor = textbgcolor = c;
  1497. }
  1498. void ILI9341_t3::setTextColor(uint16_t c, uint16_t b) {
  1499. textcolor = c;
  1500. textbgcolor = b;
  1501. }
  1502. void ILI9341_t3::setTextWrap(boolean w) {
  1503. wrap = w;
  1504. }
  1505. boolean ILI9341_t3::getTextWrap()
  1506. {
  1507. return wrap;
  1508. }
  1509. // Return the width of a text string
  1510. // - num = max characters to process, or 0 for entire string (null-terminated)
  1511. uint16_t ILI9341_t3::measureTextWidth(const char* text, int num) {
  1512. uint16_t maxH = 0;
  1513. uint16_t currH = 0;
  1514. uint16_t n = num;
  1515. if (n == 0) {
  1516. n = strlen(text);
  1517. };
  1518. for (int i = 0; i < n; i++) {
  1519. if (text[i] == '\n') {
  1520. // For multi-line strings, retain max width
  1521. if (currH > maxH)
  1522. maxH = currH;
  1523. currH = 0;
  1524. }
  1525. else {
  1526. uint16_t h, w;
  1527. measureChar(text[i], &w, &h);
  1528. currH += w;
  1529. }
  1530. }
  1531. uint16_t h = maxH > currH ? maxH : currH;
  1532. return h;
  1533. }
  1534. // Return the height of a text string
  1535. // - num = max characters to process, or 0 for entire string (null-terminated)
  1536. uint16_t ILI9341_t3::measureTextHeight(const char* text, int num) {
  1537. int lines = 1;
  1538. uint16_t n = num;
  1539. if (n == 0) {
  1540. n = strlen(text);
  1541. };
  1542. for (int i = 0; i < n; i++) {
  1543. if (text[i] == '\n') {
  1544. lines++;
  1545. }
  1546. }
  1547. return ((lines - 1) * fontLineSpace() + fontCapHeight());
  1548. }
  1549. uint8_t ILI9341_t3::getRotation(void) {
  1550. return rotation;
  1551. }
  1552. void ILI9341_t3::sleep(bool enable) {
  1553. beginSPITransaction(_clock);
  1554. if (enable) {
  1555. writecommand_cont(ILI9341_DISPOFF);
  1556. writecommand_last(ILI9341_SLPIN);
  1557. endSPITransaction();
  1558. } else {
  1559. writecommand_cont(ILI9341_DISPON);
  1560. writecommand_last(ILI9341_SLPOUT);
  1561. endSPITransaction();
  1562. delay(5);
  1563. }
  1564. }
  1565. void Adafruit_GFX_Button::initButton(ILI9341_t3 *gfx,
  1566. int16_t x, int16_t y, uint8_t w, uint8_t h,
  1567. uint16_t outline, uint16_t fill, uint16_t textcolor,
  1568. const char *label, uint8_t textsize)
  1569. {
  1570. _x = x;
  1571. _y = y;
  1572. _w = w;
  1573. _h = h;
  1574. _outlinecolor = outline;
  1575. _fillcolor = fill;
  1576. _textcolor = textcolor;
  1577. _textsize = textsize;
  1578. _gfx = gfx;
  1579. strncpy(_label, label, 9);
  1580. _label[9] = 0;
  1581. }
  1582. void Adafruit_GFX_Button::drawButton(bool inverted)
  1583. {
  1584. uint16_t fill, outline, text;
  1585. if (! inverted) {
  1586. fill = _fillcolor;
  1587. outline = _outlinecolor;
  1588. text = _textcolor;
  1589. } else {
  1590. fill = _textcolor;
  1591. outline = _outlinecolor;
  1592. text = _fillcolor;
  1593. }
  1594. _gfx->fillRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, fill);
  1595. _gfx->drawRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, outline);
  1596. _gfx->setCursor(_x - strlen(_label)*3*_textsize, _y-4*_textsize);
  1597. _gfx->setTextColor(text);
  1598. _gfx->setTextSize(_textsize);
  1599. _gfx->print(_label);
  1600. }
  1601. bool Adafruit_GFX_Button::contains(int16_t x, int16_t y)
  1602. {
  1603. if ((x < (_x - _w/2)) || (x > (_x + _w/2))) return false;
  1604. if ((y < (_y - _h/2)) || (y > (_y + _h/2))) return false;
  1605. return true;
  1606. }