GxEPD2_it60.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. // Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
  2. // Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines!
  3. //
  4. // GxEPD2_it60 class is based on Demo Example from Waveshare for Raspberry PI https://github.com/waveshare/IT8951/archive/master.zip
  5. // Controller: IT8951 : https://www.waveshare.com/w/upload/1/18/IT8951_D_V0.2.4.3_20170728.pdf
  6. //
  7. // The GxEPD2_it60 driver class supports the Waveshare e-Paper IT8951 Driver HAT connected with SPI for the ED060SCT 6" e-paper panel (parallel IF)
  8. // https://www.waveshare.com/product/mini-pc/raspberry-pi/hats/6inch-e-paper-hat.htm
  9. // This Driver HAT requires 5V power supply but works with 3.3V data lines; requires both MOSI and MISO SPI lines.
  10. //
  11. // Author: Jean-Marc Zingg
  12. //
  13. // Version: see library.properties
  14. //
  15. // Library: https://github.com/ZinggJM/GxEPD2
  16. #include "GxEPD2_it60.h"
  17. #define VCOM 1500 //e.g. -1.53 = 1530 = 0x5FA
  18. //Built in I80 Command Code
  19. #define IT8951_TCON_SYS_RUN 0x0001
  20. #define IT8951_TCON_STANDBY 0x0002
  21. #define IT8951_TCON_SLEEP 0x0003
  22. #define IT8951_TCON_REG_RD 0x0010
  23. #define IT8951_TCON_REG_WR 0x0011
  24. #define IT8951_TCON_LD_IMG 0x0020
  25. #define IT8951_TCON_LD_IMG_AREA 0x0021
  26. #define IT8951_TCON_LD_IMG_END 0x0022
  27. //I80 User defined command code
  28. #define USDEF_I80_CMD_DPY_AREA 0x0034
  29. #define USDEF_I80_CMD_GET_DEV_INFO 0x0302
  30. #define USDEF_I80_CMD_DPY_BUF_AREA 0x0037
  31. #define USDEF_I80_CMD_VCOM 0x0039
  32. //Rotate mode
  33. #define IT8951_ROTATE_0 0
  34. #define IT8951_ROTATE_90 1
  35. #define IT8951_ROTATE_180 2
  36. #define IT8951_ROTATE_270 3
  37. //Pixel mode , BPP - Bit per Pixel
  38. #define IT8951_2BPP 0
  39. #define IT8951_3BPP 1
  40. #define IT8951_4BPP 2
  41. #define IT8951_8BPP 3
  42. //Endian Type
  43. #define IT8951_LDIMG_L_ENDIAN 0
  44. #define IT8951_LDIMG_B_ENDIAN 1
  45. #define SYS_REG_BASE 0x0000
  46. #define I80CPCR (SYS_REG_BASE + 0x04)
  47. #define MCSR_BASE_ADDR 0x0200
  48. #define LISAR (MCSR_BASE_ADDR + 0x0008)
  49. GxEPD2_it60::GxEPD2_it60(int8_t cs, int8_t dc, int8_t rst, int8_t busy) :
  50. GxEPD2_EPD(cs, dc, rst, busy, LOW, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
  51. _spi_settings(24000000, MSBFIRST, SPI_MODE0),
  52. _spi_settings_for_read(1000000, MSBFIRST, SPI_MODE0)
  53. {
  54. }
  55. void GxEPD2_it60::init(uint32_t serial_diag_bitrate)
  56. {
  57. init(serial_diag_bitrate, true, 20, false);
  58. }
  59. void GxEPD2_it60::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode)
  60. {
  61. GxEPD2_EPD::init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
  62. // we need a long reset pulse
  63. if (_rst >= 0)
  64. {
  65. digitalWrite(_rst, LOW);
  66. delay(200);
  67. digitalWrite(_rst, HIGH);
  68. delay(200);
  69. _waitWhileBusy("init reset_to_ready", reset_to_ready_time);
  70. }
  71. _writeCommand16(USDEF_I80_CMD_GET_DEV_INFO);
  72. _waitWhileBusy("GetIT8951SystemInfo", power_on_time);
  73. _readData16((uint16_t*)&IT8951DevInfo, sizeof(IT8951DevInfo) / 2);
  74. if (_diag_enabled)
  75. {
  76. //Show Device information of IT8951
  77. printf("Panel(W,H) = (%d,%d)\r\n",
  78. IT8951DevInfo.usPanelW, IT8951DevInfo.usPanelH );
  79. printf("Image Buffer Address = %X\r\n",
  80. IT8951DevInfo.usImgBufAddrL | (IT8951DevInfo.usImgBufAddrH << 16));
  81. //Show Firmware and LUT Version
  82. printf("FW Version = %s\r\n", (uint8_t*)IT8951DevInfo.usFWVersion);
  83. printf("LUT Version = %s\r\n", (uint8_t*)IT8951DevInfo.usLUTVersion);
  84. }
  85. //Set to Enable I80 Packed mode
  86. _IT8951WriteReg(I80CPCR, 0x0001);
  87. if (VCOM != _IT8951GetVCOM())
  88. {
  89. _IT8951SetVCOM(VCOM);
  90. printf("VCOM = -%.02fV\n", (float)_IT8951GetVCOM() / 1000);
  91. }
  92. printf("VCOM = -%.02fV\n", (float)_IT8951GetVCOM() / 1000);
  93. }
  94. void GxEPD2_it60::clearScreen(uint8_t value)
  95. {
  96. _initial_write = false; // initial full screen buffer clean done
  97. if (_initial_refresh) _Init_Full();
  98. else _Init_Part();
  99. _initial_refresh = false;
  100. _setPartialRamArea(0, 0, WIDTH, HEIGHT);
  101. SPI.beginTransaction(_spi_settings);
  102. if (_cs >= 0) digitalWrite(_cs, LOW);
  103. _transfer16(0x0000); // preamble for write data
  104. _waitWhileBusy2("clearScreen preamble", default_wait_time);
  105. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT); i++)
  106. {
  107. SPI.transfer(value);
  108. #if defined(ESP8266) || defined(ESP32)
  109. if (0 == i % 10000) yield();
  110. #endif
  111. }
  112. if (_cs >= 0) digitalWrite(_cs, HIGH);
  113. SPI.endTransaction();
  114. _writeCommand16(IT8951_TCON_LD_IMG_END);
  115. _waitWhileBusy2("clearScreen load end", default_wait_time);
  116. _refresh(0, 0, WIDTH, HEIGHT, false);
  117. }
  118. void GxEPD2_it60::writeScreenBuffer(uint8_t value)
  119. {
  120. if (_initial_refresh) clearScreen(value);
  121. else _writeScreenBuffer(value);
  122. }
  123. void GxEPD2_it60::_writeScreenBuffer(uint8_t value)
  124. {
  125. _initial_write = false; // initial full screen buffer clean done
  126. if (!_using_partial_mode) _Init_Part();
  127. _setPartialRamArea(0, 0, WIDTH, HEIGHT);
  128. SPI.beginTransaction(_spi_settings);
  129. if (_cs >= 0) digitalWrite(_cs, LOW);
  130. _transfer16(0x0000); // preamble for write data
  131. _waitWhileBusy2("clearScreen preamble", default_wait_time);
  132. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT); i++)
  133. {
  134. SPI.transfer(value);
  135. #if defined(ESP8266) || defined(ESP32)
  136. if (0 == i % 10000) yield();
  137. #endif
  138. }
  139. if (_cs >= 0) digitalWrite(_cs, HIGH);
  140. SPI.endTransaction();
  141. _writeCommand16(IT8951_TCON_LD_IMG_END);
  142. _waitWhileBusy2("_writeScreenBuffer load end", default_wait_time);
  143. }
  144. void GxEPD2_it60::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  145. {
  146. if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
  147. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  148. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  149. x -= x % 8; // byte boundary
  150. w = wb * 8; // byte boundary
  151. int16_t x1 = x < 0 ? 0 : x; // limit
  152. int16_t y1 = y < 0 ? 0 : y; // limit
  153. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  154. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  155. int16_t dx = x1 - x;
  156. int16_t dy = y1 - y;
  157. w1 -= dx;
  158. h1 -= dy;
  159. if ((w1 <= 0) || (h1 <= 0)) return;
  160. if (!_using_partial_mode) _Init_Part();
  161. _setPartialRamArea(x1, y1, w1, h1);
  162. SPI.beginTransaction(_spi_settings);
  163. if (_cs >= 0) digitalWrite(_cs, LOW);
  164. _transfer16(0x0000); // preamble for write data
  165. _waitWhileBusy2("writeImage preamble", default_wait_time);
  166. for (int16_t i = 0; i < h1; i++)
  167. {
  168. for (int16_t j = 0; j < w1 / 8; j++)
  169. {
  170. uint8_t data;
  171. // use wb, h of bitmap for index!
  172. uint32_t idx = mirror_y ? uint32_t(j + dx / 8) + uint32_t((h - 1 - (i + dy))) * uint32_t(wb) : uint32_t(j + dx / 8) + uint32_t(i + dy) * uint32_t(wb);
  173. if (pgm)
  174. {
  175. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  176. data = pgm_read_byte(&bitmap[idx]);
  177. #else
  178. data = bitmap[idx];
  179. #endif
  180. }
  181. else
  182. {
  183. data = bitmap[idx];
  184. }
  185. if (invert) data = ~data;
  186. _send8pixel(~data);
  187. }
  188. #if defined(ESP8266) || defined(ESP32)
  189. yield();
  190. #endif
  191. }
  192. if (_cs >= 0) digitalWrite(_cs, HIGH);
  193. SPI.endTransaction();
  194. _writeCommand16(IT8951_TCON_LD_IMG_END);
  195. _waitWhileBusy2("writeImage load end", default_wait_time);
  196. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  197. }
  198. void GxEPD2_it60::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  199. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  200. {
  201. if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
  202. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  203. if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
  204. if ((x_part < 0) || (x_part >= w_bitmap)) return;
  205. if ((y_part < 0) || (y_part >= h_bitmap)) return;
  206. int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
  207. x_part -= x_part % 8; // byte boundary
  208. w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
  209. h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
  210. x -= x % 8; // byte boundary
  211. w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
  212. int16_t x1 = x < 0 ? 0 : x; // limit
  213. int16_t y1 = y < 0 ? 0 : y; // limit
  214. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  215. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  216. int16_t dx = x1 - x;
  217. int16_t dy = y1 - y;
  218. w1 -= dx;
  219. h1 -= dy;
  220. if ((w1 <= 0) || (h1 <= 0)) return;
  221. if (!_using_partial_mode) _Init_Part();
  222. _setPartialRamArea(x1, y1, w1, h1);
  223. SPI.beginTransaction(_spi_settings);
  224. if (_cs >= 0) digitalWrite(_cs, LOW);
  225. _transfer16(0x0000); // preamble for write data
  226. _waitWhileBusy2("writeImage preamble", default_wait_time);
  227. for (int16_t i = 0; i < h1; i++)
  228. {
  229. for (int16_t j = 0; j < w1 / 8; j++)
  230. {
  231. uint8_t data;
  232. // use wb_bitmap, h_bitmap of bitmap for index!
  233. uint32_t idx = mirror_y ? x_part / 8 + (j + dx / 8) + uint32_t((h_bitmap - 1 - (y_part + i + dy))) * uint32_t(wb_bitmap) : x_part / 8 + j + dx / 8 + uint32_t(y_part + i + dy) * uint32_t(wb_bitmap);
  234. if (pgm)
  235. {
  236. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  237. data = pgm_read_byte(&bitmap[idx]);
  238. #else
  239. data = bitmap[idx];
  240. #endif
  241. }
  242. else
  243. {
  244. data = bitmap[idx];
  245. }
  246. if (invert) data = ~data;
  247. _send8pixel(~data);
  248. }
  249. }
  250. if (_cs >= 0) digitalWrite(_cs, HIGH);
  251. SPI.endTransaction();
  252. _writeCommand16(IT8951_TCON_LD_IMG_END);
  253. _waitWhileBusy2("writeImage load end", default_wait_time);
  254. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  255. }
  256. void GxEPD2_it60::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  257. {
  258. if (black)
  259. {
  260. writeImage(black, x, y, w, h, invert, mirror_y, pgm);
  261. }
  262. }
  263. void GxEPD2_it60::writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  264. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  265. {
  266. if (black)
  267. {
  268. writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  269. }
  270. }
  271. void GxEPD2_it60::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  272. {
  273. if (data1)
  274. {
  275. if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
  276. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  277. int16_t x1 = x < 0 ? 0 : x; // limit
  278. int16_t y1 = y < 0 ? 0 : y; // limit
  279. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  280. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  281. int16_t dx = x1 - x;
  282. int16_t dy = y1 - y;
  283. w1 -= dx;
  284. h1 -= dy;
  285. if ((w1 <= 0) || (h1 <= 0)) return;
  286. if (!_using_partial_mode) _Init_Part();
  287. _setPartialRamArea(x1, y1, w1, h1);
  288. SPI.beginTransaction(_spi_settings);
  289. if (_cs >= 0) digitalWrite(_cs, LOW);
  290. _transfer16(0x0000); // preamble for write data
  291. _waitWhileBusy2("writeNative preamble", default_wait_time);
  292. for (int16_t i = 0; i < h1; i++)
  293. {
  294. for (int16_t j = 0; j < w1; j++)
  295. {
  296. uint8_t data;
  297. // use w, h of bitmap for index!
  298. uint32_t idx = mirror_y ? uint32_t(j + dx) + uint32_t((h - 1 - (i + dy))) * uint32_t(w) : uint32_t(j + dx) + uint32_t(i + dy) * uint32_t(w);
  299. if (pgm)
  300. {
  301. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  302. data = pgm_read_byte(&data1[idx]);
  303. #else
  304. data = data1[idx];
  305. #endif
  306. }
  307. else
  308. {
  309. data = data1[idx];
  310. }
  311. if (invert) data = ~data;
  312. SPI.transfer(data);
  313. }
  314. #if defined(ESP8266) || defined(ESP32)
  315. yield();
  316. #endif
  317. }
  318. if (_cs >= 0) digitalWrite(_cs, HIGH);
  319. SPI.endTransaction();
  320. _writeCommand16(IT8951_TCON_LD_IMG_END);
  321. _waitWhileBusy2("writeNative load end", default_wait_time);
  322. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  323. }
  324. }
  325. void GxEPD2_it60::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  326. {
  327. writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
  328. _refresh(x, y, w, h, true);
  329. }
  330. void GxEPD2_it60::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  331. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  332. {
  333. writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  334. _refresh(x, y, w, h, true);
  335. }
  336. void GxEPD2_it60::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  337. {
  338. writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
  339. _refresh(x, y, w, h, true);
  340. }
  341. void GxEPD2_it60::drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  342. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  343. {
  344. writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  345. _refresh(x, y, w, h, true);
  346. }
  347. void GxEPD2_it60::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  348. {
  349. writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
  350. _refresh(x, y, w, h, false);
  351. }
  352. void GxEPD2_it60::refresh(bool partial_update_mode)
  353. {
  354. _refresh(0, 0, WIDTH, HEIGHT, partial_update_mode);
  355. }
  356. void GxEPD2_it60::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
  357. {
  358. _refresh(x, y, w, h, true);
  359. }
  360. void GxEPD2_it60::_refresh(int16_t x, int16_t y, int16_t w, int16_t h, bool partial_update_mode)
  361. {
  362. //x -= x % 8; // byte boundary
  363. //w -= x % 8; // byte boundary
  364. int16_t x1 = x < 0 ? 0 : x; // limit
  365. int16_t y1 = y < 0 ? 0 : y; // limit
  366. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  367. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  368. w1 -= x1 - x;
  369. h1 -= y1 - y;
  370. //Send I80 Display Command (User defined command of IT8951)
  371. _writeCommand16(USDEF_I80_CMD_DPY_AREA); //0x0034
  372. _waitWhileBusy2("refresh cmd", refresh_cmd_time);
  373. //Write arguments
  374. _writeData16(x1);
  375. _waitWhileBusy2("refresh x", refresh_par_time);
  376. _writeData16(y1);
  377. _waitWhileBusy2("refresh y", refresh_par_time);
  378. _writeData16(w1);
  379. _waitWhileBusy2("refresh w", refresh_par_time);
  380. _writeData16(h1);
  381. _waitWhileBusy2("refresh h", refresh_par_time);
  382. _writeData16(partial_update_mode ? 1 : 2); // mode
  383. _waitWhileBusy("refresh", full_refresh_time);
  384. }
  385. void GxEPD2_it60::powerOff(void)
  386. {
  387. _PowerOff();
  388. }
  389. void GxEPD2_it60::hibernate()
  390. {
  391. if (_power_is_on) _PowerOff();
  392. if (_rst >= 0)
  393. {
  394. // this does not work, does not reduce power, uses more than in stand by mode
  395. //delay(1000);
  396. //_IT8951Sleep();
  397. //delay(1000);
  398. //_hibernating = true;
  399. }
  400. }
  401. void GxEPD2_it60::_send8pixel(uint8_t data)
  402. {
  403. for (uint8_t j = 0; j < 8; j++)
  404. {
  405. SPI.transfer(data & 0x80 ? 0x00 : 0xFF);
  406. data <<= 1;
  407. }
  408. }
  409. void GxEPD2_it60::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
  410. {
  411. //_IT8951WriteReg(LISAR + 2 , IT8951DevInfo.usImgBufAddrH);
  412. //_IT8951WriteReg(LISAR , IT8951DevInfo.usImgBufAddrL);
  413. uint16_t usArg[5];
  414. //usArg[0] = (IT8951_LDIMG_L_ENDIAN << 8 ) | (IT8951_8BPP << 4) | (IT8951_ROTATE_0);
  415. usArg[0] = (IT8951_LDIMG_B_ENDIAN << 8 ) | (IT8951_8BPP << 4) | (IT8951_ROTATE_0);
  416. usArg[1] = x;
  417. usArg[2] = y;
  418. usArg[3] = w;
  419. usArg[4] = h;
  420. _writeCommandData16(IT8951_TCON_LD_IMG_AREA , usArg , 5);
  421. }
  422. void GxEPD2_it60::_PowerOn()
  423. {
  424. if (!_power_is_on)
  425. {
  426. _IT8951SystemRun();
  427. _waitWhileBusy("_PowerOn", power_on_time);
  428. }
  429. _power_is_on = true;
  430. }
  431. void GxEPD2_it60::_PowerOff()
  432. {
  433. _IT8951StandBy();
  434. _waitWhileBusy("_PowerOff", power_off_time);
  435. _power_is_on = false;
  436. _using_partial_mode = false;
  437. }
  438. void GxEPD2_it60::_InitDisplay()
  439. {
  440. // we need a long reset pulse
  441. if (_hibernating && (_rst >= 0))
  442. {
  443. digitalWrite(_rst, LOW);
  444. delay(200);
  445. digitalWrite(_rst, HIGH);
  446. delay(200);
  447. }
  448. }
  449. void GxEPD2_it60::_Init_Full()
  450. {
  451. _InitDisplay();
  452. _PowerOn();
  453. _using_partial_mode = false;
  454. }
  455. void GxEPD2_it60::_Init_Part()
  456. {
  457. _InitDisplay();
  458. _PowerOn();
  459. _using_partial_mode = true;
  460. }
  461. void GxEPD2_it60::_waitWhileBusy2(const char* comment, uint16_t busy_time)
  462. {
  463. if (_busy >= 0)
  464. {
  465. unsigned long start = micros();
  466. while (1)
  467. {
  468. if (digitalRead(_busy) != _busy_level) break;
  469. delay(1);
  470. if (micros() - start > _busy_timeout)
  471. {
  472. Serial.println("Busy Timeout!");
  473. break;
  474. }
  475. }
  476. if (comment)
  477. {
  478. #if !defined(DISABLE_DIAGNOSTIC_OUTPUT)
  479. if (_diag_enabled)
  480. {
  481. unsigned long elapsed = micros() - start;
  482. if (elapsed > diag_min_time * 1000)
  483. {
  484. Serial.print(comment);
  485. Serial.print(" : ");
  486. Serial.println(elapsed);
  487. }
  488. }
  489. #endif
  490. }
  491. (void) start;
  492. }
  493. else delay(busy_time);
  494. }
  495. uint16_t GxEPD2_it60::_transfer16(uint16_t value)
  496. {
  497. uint16_t rv = SPI.transfer(value >> 8) << 8;
  498. return (rv | SPI.transfer(value));
  499. }
  500. void GxEPD2_it60::_writeCommand16(uint16_t c)
  501. {
  502. String s = String("_writeCommand16(0x") + String(c, HEX) + String(")");
  503. _waitWhileBusy2(s.c_str(), default_wait_time);
  504. SPI.beginTransaction(_spi_settings);
  505. if (_cs >= 0) digitalWrite(_cs, LOW);
  506. _transfer16(0x6000); // preamble for write command
  507. _waitWhileBusy2("_writeCommand16 preamble", default_wait_time);
  508. _transfer16(c);
  509. if (_cs >= 0) digitalWrite(_cs, HIGH);
  510. SPI.endTransaction();
  511. //_waitWhileBusy(s.c_str(), default_wait_time);
  512. }
  513. void GxEPD2_it60::_writeData16(uint16_t d)
  514. {
  515. _waitWhileBusy2("_writeData16", default_wait_time);
  516. SPI.beginTransaction(_spi_settings);
  517. if (_cs >= 0) digitalWrite(_cs, LOW);
  518. _transfer16(0x0000); // preamble for write data
  519. _waitWhileBusy2("_writeData16 preamble", default_wait_time);
  520. _transfer16(d);
  521. if (_cs >= 0) digitalWrite(_cs, HIGH);
  522. SPI.endTransaction();
  523. }
  524. void GxEPD2_it60::_writeData16(const uint16_t* d, uint32_t n)
  525. {
  526. _waitWhileBusy2("_writeData16", default_wait_time);
  527. SPI.beginTransaction(_spi_settings);
  528. if (_cs >= 0) digitalWrite(_cs, LOW);
  529. _transfer16(0x0000); // preamble for write data
  530. _waitWhileBusy2("_writeData16 preamble", default_wait_time);
  531. for (uint32_t i = 0; i < n; i++)
  532. {
  533. _transfer16(*d++);
  534. }
  535. if (_cs >= 0) digitalWrite(_cs, HIGH);
  536. SPI.endTransaction();
  537. }
  538. uint16_t GxEPD2_it60::_readData16()
  539. {
  540. _waitWhileBusy2("_readData16", default_wait_time);
  541. SPI.beginTransaction(_spi_settings);
  542. if (_cs >= 0) digitalWrite(_cs, LOW);
  543. _transfer16(0x1000); // preamble for read data
  544. _waitWhileBusy2("_readData16 preamble", default_wait_time);
  545. _transfer16(0); // dummy
  546. _waitWhileBusy2("_readData16 dummy", default_wait_time);
  547. uint16_t rv = _transfer16(0);
  548. if (_cs >= 0) digitalWrite(_cs, HIGH);
  549. SPI.endTransaction();
  550. return rv;
  551. }
  552. void GxEPD2_it60::_readData16(uint16_t* d, uint32_t n)
  553. {
  554. _waitWhileBusy2("_readData16", default_wait_time);
  555. SPI.beginTransaction(_spi_settings);
  556. if (_cs >= 0) digitalWrite(_cs, LOW);
  557. _transfer16(0x1000); // preamble for read data
  558. _waitWhileBusy2("_readData16 preamble", default_wait_time);
  559. _transfer16(0); // dummy
  560. _waitWhileBusy2("_readData16 dummy", default_wait_time);
  561. for (uint32_t i = 0; i < n; i++)
  562. {
  563. *d++ = _transfer16(0);
  564. //_waitWhileBusy("_readData16 data", default_wait_time);
  565. }
  566. if (_cs >= 0) digitalWrite(_cs, HIGH);
  567. SPI.endTransaction();
  568. }
  569. void GxEPD2_it60::_writeCommandData16(uint16_t c, const uint16_t* d, uint16_t n)
  570. {
  571. _writeCommand16(c);
  572. for (uint16_t i = 0; i < n; i++)
  573. {
  574. _writeData16(d[i]);
  575. }
  576. }
  577. void GxEPD2_it60::_IT8951SystemRun()
  578. {
  579. _writeCommand16(IT8951_TCON_SYS_RUN);
  580. }
  581. void GxEPD2_it60::_IT8951StandBy()
  582. {
  583. _writeCommand16(IT8951_TCON_STANDBY);
  584. }
  585. void GxEPD2_it60::_IT8951Sleep()
  586. {
  587. _writeCommand16(IT8951_TCON_SLEEP);
  588. }
  589. uint16_t GxEPD2_it60::_IT8951ReadReg(uint16_t usRegAddr)
  590. {
  591. uint16_t usData;
  592. //Send Cmd and Register Address
  593. _writeCommand16(IT8951_TCON_REG_RD);
  594. _writeData16(usRegAddr);
  595. //Read data from Host Data bus
  596. usData = _readData16();
  597. return usData;
  598. }
  599. void GxEPD2_it60::_IT8951WriteReg(uint16_t usRegAddr, uint16_t usValue)
  600. {
  601. //Send Cmd , Register Address and Write Value
  602. _writeCommand16(IT8951_TCON_REG_WR);
  603. _writeData16(usRegAddr);
  604. _writeData16(usValue);
  605. }
  606. uint16_t GxEPD2_it60::_IT8951GetVCOM(void)
  607. {
  608. uint16_t vcom;
  609. _writeCommand16(USDEF_I80_CMD_VCOM);
  610. _waitWhileBusy2("_IT8951GetVCOM", default_wait_time);
  611. _writeData16(0);
  612. //Read data from Host Data bus
  613. vcom = _readData16();
  614. return vcom;
  615. }
  616. void GxEPD2_it60::_IT8951SetVCOM(uint16_t vcom)
  617. {
  618. _writeCommand16(USDEF_I80_CMD_VCOM);
  619. _waitWhileBusy2("_IT8951SetVCOM", default_wait_time);
  620. _writeData16(1);
  621. //Read data from Host Data bus
  622. _writeData16(vcom);
  623. _waitWhileBusy2("_IT8951SetVCOM", set_vcom_time);
  624. }