Adafruit_TFT8.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /*!
  2. * @file Adafruit_TFT8.cpp
  3. *
  4. * @mainpage Adafruit 8-bit Parallel TFT Displays
  5. *
  6. * @section intro_sec Introduction
  7. * This is our library for TFT Displays using an 8-bit parallel interface
  8. * with address windows and 16 bit color.
  9. *
  10. * These displays use ip to 13 pins to communicate:
  11. * - 8 data lines (required)
  12. * - Write strobe (required)
  13. * - Command/data (required)
  14. * - Chip select (optional, can be tied LOW)
  15. * - Read strobe (optional)
  16. * - Reset (optional, can connect to MCU reset)
  17. *
  18. * Adafruit invests time and resources providing this open source code,
  19. * please support Adafruit and open-source hardware by purchasing
  20. * products from Adafruit!
  21. *
  22. * Written by Limor Fried/Ladyada for Adafruit Industries.
  23. * MIT license, all text above must be included in any redistribution
  24. * @section dependencies Dependencies
  25. *
  26. * This library depends on <a href="https://github.com/adafruit/Adafruit_GFX">
  27. * Adafruit_GFX</a> being present on your system. Please make sure you have
  28. * installed the latest version before using this library.
  29. *
  30. * @section author Author
  31. *
  32. * Written by Limor "ladyada" Fried for Adafruit Industries.
  33. *
  34. * @section license License
  35. *
  36. * BSD license, all text here must be included in any redistribution.
  37. *
  38. */
  39. #if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
  40. #include "Adafruit_TFT8.h"
  41. #ifdef PORT_IOBUS
  42. // On SAMD21, redefine digitalPinToPort() to use the slightly-faster
  43. // PORT_IOBUS rather than PORT (not needed on SAMD51).
  44. #undef digitalPinToPort
  45. #define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort]))
  46. #endif
  47. #ifdef USE_PORT_DMA
  48. #include <Adafruit_ZeroDMA.h>
  49. #include <malloc.h> // memalign() function
  50. // DMA transfer-in-progress indicator and callback
  51. static volatile boolean dma_busy = false;
  52. static void dma_callback(Adafruit_ZeroDMA *dma) {
  53. dma_busy = false;
  54. }
  55. #endif // USE_PORT_DMA
  56. #if defined(__AVR__)
  57. #define WR_LOW() *wrPort &= wrPinMaskClr;
  58. #define WR_HIGH() *wrPort |= wrPinMaskSet;
  59. #define DC_LOW() *dcPort &= dcPinMaskClr;
  60. #define DC_HIGH() *dcPort |= dcPinMaskSet;
  61. #define CS_LOW() if(_cs >= 0) *csPort &= csPinMaskClr;
  62. #define CS_HIGH() if(_cs >= 0) *csPort |= csPinMaskSet;
  63. #define RD_LOW() *rdPort &= rdPinMaskClr;
  64. #define RD_HIGH() *rdPort |= rdPinMaskSet;
  65. #define PORT_OUTPUT() *portDir = 0xFF;
  66. #define PORT_INPUT() *portDir = 0x00;
  67. #else
  68. #define WR_LOW() *wrPortClr = wrPinMask;
  69. #define WR_HIGH() *wrPortSet = wrPinMask;
  70. #define DC_LOW() *dcPortClr = dcPinMask;
  71. #define DC_HIGH() *dcPortSet = dcPinMask;
  72. #define CS_LOW() if(_cs >= 0) *csPortClr = csPinMask;
  73. #define CS_HIGH() if(_cs >= 0) *csPortSet = csPinMask;
  74. #define RD_LOW() *rdPortClr = rdPinMask;
  75. #define RD_HIGH() *rdPortSet = rdPinMask;
  76. #define PORT_OUTPUT() *dirSet = 0xFF;
  77. #define PORT_INPUT() *dirClr = 0xFF;
  78. #define PORT_OUTPUT16() *(volatile uint16_t *)dirSet = 0xFFFF;
  79. #define PORT_INPUT16() *(volatile uint16_t *)dirClr = 0xFFFF;
  80. #endif
  81. #define WR_STROBE() { WR_LOW(); WR_HIGH(); }
  82. /*!
  83. @brief Instantiate Adafruit TFT8 display driver.
  84. @param w Display width in pixels.
  85. @param h Display height in pixels.
  86. @param D0 Arduino pin # for data bit 0 (1+ are extrapolated).
  87. The 8 data bits MUST be contiguous and byte-aligned
  88. (word-aligned for 'wide' interface) within the same
  89. PORT register (may not correspond to Arduino pin sequence).
  90. @param WR Arduino pin # for write strobe.
  91. @param DC Arduino pin # for data/command.
  92. @param CS Arduino pin # for chip select (-1 if unused, tie CS low).
  93. @param RST Arduino pin # for reset (-1 if unused, tie to MCU reset).
  94. @param RD Arduino pin # for read strobe (-1 if unused).
  95. @param wide If true, use 16-bit wide interface (not on AVR).
  96. */
  97. Adafruit_TFT8::Adafruit_TFT8(uint16_t w, uint16_t h,
  98. int8_t D0, int8_t WR, int8_t DC, int8_t CS, int8_t RST, int8_t RD,
  99. bool wide) : Adafruit_GFX(w, h),
  100. _d0(D0), _wr(WR), _dc(DC), _cs(CS), _rst(RST), _rd(RD)
  101. {
  102. #if defined(__AVR__)
  103. if(digitalPinToBitMask(D0) != 1) return; // D0 MUST be port bit 0
  104. _d0 = D0; // Save D0 pin to indicate valid alignment
  105. wrPort = (PORTreg_t)portOutputRegister(digitalPinToPort(WR));
  106. wrPinMaskSet = digitalPinToBitMask(WR);
  107. dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(DC));
  108. dcPinMaskSet = digitalPinToBitMask(DC);
  109. if(CS >= 0) {
  110. csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(CS));
  111. csPinMaskSet = digitalPinToBitMask(CS);
  112. } else {
  113. // No chip-select line defined; might be permanently tied to GND.
  114. // Assign a valid GPIO register (though not used for CS), and an
  115. // empty pin bitmask...the nonsense bit-twiddling might be faster
  116. // than checking _cs and possibly branching.
  117. csPort = dcPort;
  118. csPinMaskSet = 0;
  119. }
  120. if(RD >= 0) {
  121. rdPort = (PORTreg_t)portOutputRegister(digitalPinToPort(RD));
  122. rdPinMaskSet = digitalPinToBitMask(RD);
  123. } else {
  124. // No read-strobe line defined; similar to CS case above
  125. rdPort = dcPort;
  126. rdPinMaskSet = 0;
  127. }
  128. wrPinMaskClr = ~wrPinMaskSet;
  129. dcPinMaskClr = ~dcPinMaskSet;
  130. csPinMaskClr = ~csPinMaskSet;
  131. rdPinMaskClr = ~rdPinMaskSet;
  132. writePort = (PORTreg_t)portOutputRegister(digitalPinToPort(D0));
  133. readPort = (PORTreg_t)portInputRegister(digitalPinToPort(D0));
  134. portDir = (PORTreg_t)portModeRegister(digitalPinToPort(D0));
  135. #else
  136. // Confirm D0 bit is byte- or word-aligned in PORT...
  137. if(g_APinDescription[D0].ulPin & (wide ? 15 : 7)) return;
  138. _d0 = D0; // Save D0 pin to indicate valid alignment
  139. _wide = wide;
  140. wrPinMask = digitalPinToBitMask(WR);
  141. wrPortSet = &(PORT->Group[g_APinDescription[WR].ulPort].OUTSET.reg);
  142. wrPortClr = &(PORT->Group[g_APinDescription[WR].ulPort].OUTCLR.reg);
  143. dcPinMask = digitalPinToBitMask(DC);
  144. dcPortSet = &(PORT->Group[g_APinDescription[DC].ulPort].OUTSET.reg);
  145. dcPortClr = &(PORT->Group[g_APinDescription[DC].ulPort].OUTCLR.reg);
  146. if(CS >= 0) { // If chip-select pin is specified...
  147. csPinMask = digitalPinToBitMask(CS);
  148. csPortSet = &(PORT->Group[g_APinDescription[CS].ulPort].OUTSET.reg);
  149. csPortClr = &(PORT->Group[g_APinDescription[CS].ulPort].OUTCLR.reg);
  150. } else {
  151. // No chip-select line defined; might be permanently tied to GND.
  152. // Assign a valid GPIO register (though not used for CS), and an
  153. // empty pin bitmask...the nonsense bit-twiddling might be faster
  154. // than checking _cs and possibly branching.
  155. csPinMask = 0;
  156. csPortSet = dcPortSet;
  157. csPortClr = dcPortClr;
  158. }
  159. if(RD >= 0) { // If read-strobe pin is specified...
  160. rdPinMask = digitalPinToBitMask(RD);
  161. rdPortSet = &(PORT->Group[g_APinDescription[RD].ulPort].OUTSET.reg);
  162. rdPortClr = &(PORT->Group[g_APinDescription[RD].ulPort].OUTCLR.reg);
  163. } else {
  164. rdPinMask = 0;
  165. rdPortSet = dcPortSet;
  166. rdPortClr = dcPortClr;
  167. }
  168. // Get pointers to PORT write/read/dir bytes within 32-bit PORT
  169. uint8_t dBit = g_APinDescription[_d0].ulPin; // d0 bit # in PORT
  170. PortGroup *p = (&(PORT->Group[g_APinDescription[_d0].ulPort]));
  171. uint8_t offset = dBit / 8; // d[7:0] byte # within PORT
  172. if(wide) offset &= ~1; // d[15:8] byte # within PORT
  173. // These are all uint8_t* pointers -- elsewhere they're recast
  174. // as necessary if a 'wide' 16-bit interface is in use.
  175. writePort = (volatile uint8_t *)&(p->OUT.reg) + offset;
  176. readPort = (volatile uint8_t *)&(p->IN.reg) + offset;
  177. dirSet = (volatile uint8_t *)&(p->DIRSET.reg) + offset;
  178. dirClr = (volatile uint8_t *)&(p->DIRCLR.reg) + offset;
  179. #endif
  180. }
  181. /*!
  182. @brief Initialiaze hardware interface.
  183. */
  184. bool Adafruit_TFT8::init(void) {
  185. if(_d0 < 0) return false; // Bad alignment in constructor
  186. // Initialize data pins. We were only passed d0, so scan
  187. // the pin description list looking for the other pins.
  188. // They'll be on the same PORT, and within the next 7 (or 15) bits
  189. // (because we need to write to a contiguous PORT byte or word).
  190. #if defined(__AVR__)
  191. // PORT registers are 8 bits wide, so just need a register match...
  192. for(uint8_t i=0; i<NUM_DIGITAL_PINS; i++) {
  193. if((PORTreg_t)portOutputRegister(digitalPinToPort(i)) == writePort) {
  194. pinMode(i, OUTPUT);
  195. digitalWrite(i, LOW);
  196. }
  197. }
  198. #else
  199. uint8_t portNum = g_APinDescription[_d0].ulPort, // d0 PORT #
  200. dBit = g_APinDescription[_d0].ulPin, // d0 bit # in PORT
  201. lastBit = dBit + (_wide ? 15 : 7);
  202. for(uint8_t i=0; i<PINS_COUNT; i++) {
  203. if((g_APinDescription[i].ulPort == portNum ) &&
  204. (g_APinDescription[i].ulPin >= dBit ) &&
  205. (g_APinDescription[i].ulPin <= (uint32_t)lastBit)) {
  206. pinMode(i, OUTPUT);
  207. digitalWrite(i, LOW);
  208. }
  209. }
  210. #endif
  211. // Initialize control signal pins, all active LOW
  212. pinMode(_wr, OUTPUT);
  213. digitalWrite(_wr, HIGH);
  214. pinMode(_dc, OUTPUT);
  215. digitalWrite(_dc, HIGH);
  216. if(_cs >= 0) {
  217. pinMode(_cs, OUTPUT);
  218. digitalWrite(_cs, HIGH); // Deselect
  219. }
  220. if(_rd >= 0) {
  221. pinMode(_rd, OUTPUT);
  222. digitalWrite(_rd, HIGH);
  223. }
  224. if(_rst >= 0) {
  225. pinMode(_rst, OUTPUT);
  226. digitalWrite(_rst, HIGH);
  227. delay(100);
  228. digitalWrite(_rst, LOW); // Toggle RST low to reset
  229. delay(100);
  230. digitalWrite(_rst, HIGH);
  231. delay(200);
  232. }
  233. return true;
  234. }
  235. /*!
  236. @brief Initiate write (or read!) operation.
  237. */
  238. inline void Adafruit_TFT8::startWrite(void) {
  239. CS_LOW(); // Chip select LOW
  240. }
  241. /*!
  242. @brief End write (or read!) operation.
  243. */
  244. inline void Adafruit_TFT8::endWrite(void) {
  245. CS_HIGH(); // Chip select HIGH
  246. }
  247. /*!
  248. @brief Write one byte to hardware interface.
  249. @param b One byte to send, MSB order
  250. */
  251. void Adafruit_TFT8::write8(uint8_t b) {
  252. #if defined(__AVR__)
  253. *writePort = b;
  254. #else
  255. if(!_wide) {
  256. *writePort = b;
  257. } else {
  258. *(volatile uint16_t *)writePort = b;
  259. }
  260. #endif
  261. WR_STROBE(); // Write strobe LOW, HIGH
  262. }
  263. /*!
  264. @brief Write one word to hardware interface.
  265. @param w One word to send, MSB order
  266. */
  267. void Adafruit_TFT8::write16(uint16_t w) {
  268. #if defined(__AVR__)
  269. *writePort = w >> 8; // MSB
  270. WR_STROBE(); // Write strobe LOW, HIGH
  271. *writePort = w; // LSB
  272. WR_STROBE(); // Write strobe LOW, HIGH
  273. #else
  274. if(!_wide) {
  275. *writePort = w >> 8; // MSB
  276. WR_STROBE(); // Write strobe LOW, HIGH
  277. *writePort = w; // LSB
  278. } else {
  279. *(volatile uint16_t *)writePort = w;
  280. }
  281. WR_STROBE(); // Write strobe LOW, HIGH
  282. #endif
  283. }
  284. /*!
  285. @brief Write a command byte.
  286. @param cmd The 8-bit command to send.
  287. */
  288. void Adafruit_TFT8::writeCommand(uint8_t cmd) {
  289. DC_LOW(); // Data/Command LOW (command mode)
  290. write8(cmd); // Issue value
  291. DC_HIGH(); // Data/Command HIGH (data mode)
  292. }
  293. /*!
  294. @brief Read one byte or word from TFT interface.
  295. @returns One byte or word, native order.
  296. */
  297. uint16_t Adafruit_TFT8::read(void) {
  298. uint16_t r = 0;
  299. if(_rd >= 0) {
  300. #if defined(__AVR__)
  301. PORT_INPUT(); // Set port to INPUT
  302. RD_LOW(); // Read strobe LOW
  303. r = *readPort; // Read value from port
  304. RD_HIGH(); // Read strobe HIGH
  305. PORT_OUTPUT(); // Set port back to OUTPUT
  306. #else
  307. if(!_wide) {
  308. PORT_INPUT(); // Set port to INPUT
  309. RD_LOW(); // Read strobe LOW
  310. r = *readPort; // Read value from port
  311. RD_HIGH(); // Read strobe HIGH
  312. PORT_OUTPUT(); // Set port back to OUTPUT
  313. } else {
  314. PORT_INPUT16(); // Set port to INPUT (16-bit)
  315. RD_LOW(); // Read strobe LOW
  316. r = *(volatile uint16_t *)readPort; // Read value from port
  317. RD_HIGH(); // Read strobe HIGH
  318. PORT_OUTPUT16(); // Set port back to OUTPUT (16-bit)
  319. }
  320. #endif
  321. }
  322. return r;
  323. }
  324. /*!
  325. @brief Draw a single pixel.
  326. @param x X coordinate.
  327. @param y Y coordinate.
  328. @param color 16-bit 5-6-5 pixel color.
  329. */
  330. void Adafruit_TFT8::drawPixel(int16_t x, int16_t y, uint16_t color) {
  331. // Clip first...
  332. if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
  333. // THEN device-select and draw...
  334. startWrite();
  335. setAddrWindow(x, y, 1, 1);
  336. writePixel(color);
  337. endWrite();
  338. }
  339. }
  340. /*!
  341. @brief Converts 8-bit (each) R,G,B color to 16-bit packed 5-6-5 value.
  342. @param red Red level, 0 to 255
  343. @param green Green level, 0 to 255
  344. @param blue Blue level, 0 to 255
  345. @return Unsigned 16-bit decimated color in "5-6-5" format
  346. */
  347. uint16_t Adafruit_TFT8::color565(uint8_t red, uint8_t green, uint8_t blue) {
  348. return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
  349. }
  350. #if 0
  351. /*!
  352. @brief Issue multiple 2-byte colors.
  353. @param colors Array of 16-bit 5-6-5 Colors to draw.
  354. @param len How many pixels to draw.
  355. */
  356. void Adafruit_TFT8::writePixels(uint16_t *colors, uint32_t len) {
  357. SPI_WRITE_PIXELS((uint8_t*)colors , len * 2);
  358. }
  359. /*!
  360. @brief Issue a 2-byte color many times.
  361. @param color The 16-bit 5-6-5 Color to draw.
  362. @param len How many pixels to draw.
  363. */
  364. void Adafruit_TFT8::writeColor(uint16_t color, uint32_t len) {
  365. if(!len) return; // Avoid 0-byte transfers
  366. uint8_t hi = color >> 8, lo = color;
  367. if(hi != lo) {
  368. } else {
  369. len *= 2;
  370. // Issue as bytes
  371. }
  372. }
  373. /**************************************************************************/
  374. /*!
  375. @brief Write a pixel (must have a transaction in progress)
  376. @param x x coordinate
  377. @param y y coordinate
  378. @param color 16-bit 5-6-5 Color to draw with
  379. */
  380. /**************************************************************************/
  381. void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
  382. if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
  383. setAddrWindow(x,y,1,1);
  384. writePixel(color);
  385. }
  386. /**************************************************************************/
  387. /*!
  388. @brief Write a filled rectangle (must have a transaction in progress)
  389. @param x Top left corner x coordinate
  390. @param y Top left corner y coordinate
  391. @param w Width in pixels
  392. @param h Height in pixels
  393. @param color 16-bit 5-6-5 Color to fill with
  394. */
  395. /**************************************************************************/
  396. void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
  397. if((x >= _width) || (y >= _height)) return;
  398. int16_t x2 = x + w - 1, y2 = y + h - 1;
  399. if((x2 < 0) || (y2 < 0)) return;
  400. // Clip left/top
  401. if(x < 0) {
  402. x = 0;
  403. w = x2 + 1;
  404. }
  405. if(y < 0) {
  406. y = 0;
  407. h = y2 + 1;
  408. }
  409. // Clip right/bottom
  410. if(x2 >= _width) w = _width - x;
  411. if(y2 >= _height) h = _height - y;
  412. setAddrWindow(x, y, w, h);
  413. writeColor(color, (int32_t)w * h);
  414. }
  415. /**************************************************************************/
  416. /*!
  417. @brief Write a perfectly vertical line (must have a transaction in progress)
  418. @param x Top-most x coordinate
  419. @param y Top-most y coordinate
  420. @param h Height in pixels
  421. @param color 16-bit 5-6-5 Color to fill with
  422. */
  423. /**************************************************************************/
  424. void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
  425. writeFillRect(x, y, 1, h, color);
  426. }
  427. /**************************************************************************/
  428. /*!
  429. @brief Write a perfectly horizontal line (must have a transaction in progress)
  430. @param x Left-most x coordinate
  431. @param y Left-most y coordinate
  432. @param w Width in pixels
  433. @param color 16-bit 5-6-5 Color to fill with
  434. */
  435. /**************************************************************************/
  436. void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
  437. writeFillRect(x, y, w, 1, color);
  438. }
  439. /**************************************************************************/
  440. /*!
  441. @brief Write a perfectly vertical line - sets up transaction
  442. @param x Top-most x coordinate
  443. @param y Top-most y coordinate
  444. @param h Height in pixels
  445. @param color 16-bit 5-6-5 Color to fill with
  446. */
  447. /**************************************************************************/
  448. void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y,
  449. int16_t h, uint16_t color) {
  450. startWrite();
  451. writeFastVLine(x, y, h, color);
  452. endWrite();
  453. }
  454. /**************************************************************************/
  455. /*!
  456. @brief Write a perfectly horizontal line - sets up transaction
  457. @param x Left-most x coordinate
  458. @param y Left-most y coordinate
  459. @param w Width in pixels
  460. @param color 16-bit 5-6-5 Color to fill with
  461. */
  462. /**************************************************************************/
  463. void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y,
  464. int16_t w, uint16_t color) {
  465. startWrite();
  466. writeFastHLine(x, y, w, color);
  467. endWrite();
  468. }
  469. /**************************************************************************/
  470. /*!
  471. @brief Fill a rectangle completely with one color.
  472. @param x Top left corner x coordinate
  473. @param y Top left corner y coordinate
  474. @param w Width in pixels
  475. @param h Height in pixels
  476. @param color 16-bit 5-6-5 Color to fill with
  477. */
  478. /**************************************************************************/
  479. void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
  480. uint16_t color) {
  481. startWrite();
  482. writeFillRect(x,y,w,h,color);
  483. endWrite();
  484. }
  485. /**************************************************************************/
  486. /*!
  487. @brief Invert the display using built-in hardware command
  488. @param i True if you want to invert, false to make 'normal'
  489. */
  490. /**************************************************************************/
  491. void Adafruit_SPITFT::invertDisplay(boolean i) {
  492. startWrite();
  493. writeCommand(i ? invertOnCommand : invertOffCommand);
  494. endWrite();
  495. }
  496. /**************************************************************************/
  497. /*!
  498. @brief Draw a 16-bit image (RGB 5/6/5) at the specified (x,y) position.
  499. For 16-bit display devices; no color reduction performed.
  500. Adapted from https://github.com/PaulStoffregen/ILI9341_t3
  501. by Marc MERLIN. See examples/pictureEmbed to use this.
  502. 5/6/2017: function name and arguments have changed for compatibility
  503. with current GFX library and to avoid naming problems in prior
  504. implementation. Formerly drawBitmap() with arguments in different order.
  505. @param x Top left corner x coordinate
  506. @param y Top left corner y coordinate
  507. @param pcolors 16-bit array with 16-bit color bitmap
  508. @param w Width of bitmap in pixels
  509. @param h Height of bitmap in pixels
  510. */
  511. /**************************************************************************/
  512. void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y,
  513. uint16_t *pcolors, int16_t w, int16_t h) {
  514. int16_t x2, y2; // Lower-right coord
  515. if(( x >= _width ) || // Off-edge right
  516. ( y >= _height) || // " top
  517. ((x2 = (x+w-1)) < 0 ) || // " left
  518. ((y2 = (y+h-1)) < 0) ) return; // " bottom
  519. int16_t bx1=0, by1=0, // Clipped top-left within bitmap
  520. saveW=w; // Save original bitmap width value
  521. if(x < 0) { // Clip left
  522. w += x;
  523. bx1 = -x;
  524. x = 0;
  525. }
  526. if(y < 0) { // Clip top
  527. h += y;
  528. by1 = -y;
  529. y = 0;
  530. }
  531. if(x2 >= _width ) w = _width - x; // Clip right
  532. if(y2 >= _height) h = _height - y; // Clip bottom
  533. pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
  534. startWrite();
  535. setAddrWindow(x, y, w, h); // Clipped area
  536. while(h--) { // For each (clipped) scanline...
  537. writePixels(pcolors, w); // Push one (clipped) row
  538. pcolors += saveW; // Advance pointer by one full (unclipped) line
  539. }
  540. endWrite();
  541. }
  542. #endif // 0
  543. #endif // !__AVR_ATtiny85__