GxEPD2_270.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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. // based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html
  5. // Controller: IL91874 : http://www.e-paper-display.com/download_detail/downloadsId=539.html
  6. //
  7. // Author: Jean-Marc Zingg
  8. //
  9. // Version: see library.properties
  10. //
  11. // Library: https://github.com/ZinggJM/GxEPD2
  12. #include "GxEPD2_270.h"
  13. GxEPD2_270::GxEPD2_270(int8_t cs, int8_t dc, int8_t rst, int8_t busy) :
  14. GxEPD2_EPD(cs, dc, rst, busy, LOW, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
  15. {
  16. }
  17. void GxEPD2_270::clearScreen(uint8_t value)
  18. {
  19. if (_initial)
  20. {
  21. _Init_Full();
  22. _writeCommand(0x10); // preset previous
  23. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  24. {
  25. _writeData(0xFF); // 0xFF is white
  26. }
  27. _writeCommand(0x13); // set current
  28. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  29. {
  30. _writeData(value);
  31. }
  32. _Update_Full();
  33. _initial = false;
  34. }
  35. if (!_using_partial_mode) _Init_Part();
  36. _setPartialRamArea(0x15, 0, 0, WIDTH, HEIGHT);
  37. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  38. {
  39. _writeData(value);
  40. }
  41. _refreshWindow(0, 0, WIDTH, HEIGHT);
  42. _waitWhileBusy("clearScreen", partial_refresh_time);
  43. _setPartialRamArea(0x14, 0, 0, WIDTH, HEIGHT);
  44. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  45. {
  46. _writeData(value);
  47. }
  48. }
  49. void GxEPD2_270::writeScreenBuffer(uint8_t value)
  50. {
  51. if (_initial) clearScreen(value);
  52. else _writeScreenBuffer(value);
  53. }
  54. void GxEPD2_270::_writeScreenBuffer(uint8_t value)
  55. {
  56. _Init_Part();
  57. _setPartialRamArea(0x15, 0, 0, WIDTH, HEIGHT);
  58. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  59. {
  60. _writeData(value);
  61. }
  62. }
  63. void GxEPD2_270::writeScreenBufferAgain(uint8_t value)
  64. {
  65. _Init_Part();
  66. _setPartialRamArea(0x14, 0, 0, WIDTH, HEIGHT);
  67. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  68. {
  69. _writeData(value);
  70. }
  71. }
  72. void GxEPD2_270::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  73. {
  74. _writeImage(0x15, bitmap, x, y, w, h, invert, mirror_y, pgm);
  75. }
  76. void GxEPD2_270::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  77. {
  78. _writeImage(0x14, bitmap, x, y, w, h, invert, mirror_y, pgm);
  79. }
  80. void GxEPD2_270::_writeImage(uint8_t command, const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  81. {
  82. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  83. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  84. x -= x % 8; // byte boundary
  85. w = wb * 8; // byte boundary
  86. int16_t x1 = x < 0 ? 0 : x; // limit
  87. int16_t y1 = y < 0 ? 0 : y; // limit
  88. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  89. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  90. int16_t dx = x1 - x;
  91. int16_t dy = y1 - y;
  92. w1 -= dx;
  93. h1 -= dy;
  94. if ((w1 <= 0) || (h1 <= 0)) return;
  95. if (!_using_partial_mode) _Init_Part();
  96. _setPartialRamArea(command, x1, y1, w1, h1);
  97. for (int16_t i = 0; i < h1; i++)
  98. {
  99. for (int16_t j = 0; j < w1 / 8; j++)
  100. {
  101. uint8_t data;
  102. // use wb, h of bitmap for index!
  103. int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
  104. if (pgm)
  105. {
  106. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  107. data = pgm_read_byte(&bitmap[idx]);
  108. #else
  109. data = bitmap[idx];
  110. #endif
  111. }
  112. else
  113. {
  114. data = bitmap[idx];
  115. }
  116. if (invert) data = ~data;
  117. _writeData(data);
  118. }
  119. }
  120. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  121. }
  122. void GxEPD2_270::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  123. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  124. {
  125. _writeImagePart(0x15, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  126. }
  127. void GxEPD2_270::writeImagePartAgain(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  128. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  129. {
  130. _writeImagePart(0x14, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  131. }
  132. void GxEPD2_270::_writeImagePart(uint8_t command, const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  133. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  134. {
  135. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  136. if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
  137. if ((x_part < 0) || (x_part >= w_bitmap)) return;
  138. if ((y_part < 0) || (y_part >= h_bitmap)) return;
  139. int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
  140. x_part -= x_part % 8; // byte boundary
  141. w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
  142. h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
  143. x -= x % 8; // byte boundary
  144. w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
  145. int16_t x1 = x < 0 ? 0 : x; // limit
  146. int16_t y1 = y < 0 ? 0 : y; // limit
  147. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  148. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  149. int16_t dx = x1 - x;
  150. int16_t dy = y1 - y;
  151. w1 -= dx;
  152. h1 -= dy;
  153. if ((w1 <= 0) || (h1 <= 0)) return;
  154. if (!_using_partial_mode) _Init_Part();
  155. _setPartialRamArea(command, x1, y1, w1, h1);
  156. for (int16_t i = 0; i < h1; i++)
  157. {
  158. for (int16_t j = 0; j < w1 / 8; j++)
  159. {
  160. uint8_t data;
  161. // use wb_bitmap, h_bitmap of bitmap for index!
  162. int16_t idx = mirror_y ? x_part / 8 + j + dx / 8 + ((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + (y_part + i + dy) * wb_bitmap;
  163. if (pgm)
  164. {
  165. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  166. data = pgm_read_byte(&bitmap[idx]);
  167. #else
  168. data = bitmap[idx];
  169. #endif
  170. }
  171. else
  172. {
  173. data = bitmap[idx];
  174. }
  175. if (invert) data = ~data;
  176. _writeData(data);
  177. }
  178. }
  179. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  180. }
  181. void GxEPD2_270::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)
  182. {
  183. if (black)
  184. {
  185. writeImage(black, x, y, w, h, invert, mirror_y, pgm);
  186. }
  187. }
  188. void GxEPD2_270::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,
  189. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  190. {
  191. if (black)
  192. {
  193. writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  194. }
  195. }
  196. void GxEPD2_270::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)
  197. {
  198. if (data1)
  199. {
  200. writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
  201. }
  202. }
  203. void GxEPD2_270::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  204. {
  205. writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
  206. refresh(x, y, w, h);
  207. writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
  208. }
  209. void GxEPD2_270::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  210. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  211. {
  212. writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  213. refresh(x, y, w, h);
  214. writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  215. }
  216. void GxEPD2_270::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)
  217. {
  218. if (black)
  219. {
  220. drawImage(black, x, y, w, h, invert, mirror_y, pgm);
  221. }
  222. }
  223. void GxEPD2_270::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,
  224. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  225. {
  226. if (black)
  227. {
  228. drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  229. }
  230. }
  231. void GxEPD2_270::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)
  232. {
  233. if (data1)
  234. {
  235. drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
  236. }
  237. }
  238. void GxEPD2_270::refresh(bool partial_update_mode)
  239. {
  240. if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
  241. else
  242. {
  243. if (_using_partial_mode) _Init_Full();
  244. _Update_Full();
  245. }
  246. }
  247. void GxEPD2_270::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
  248. {
  249. x -= x % 8; // byte boundary
  250. w -= x % 8; // byte boundary
  251. int16_t x1 = x < 0 ? 0 : x; // limit
  252. int16_t y1 = y < 0 ? 0 : y; // limit
  253. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  254. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  255. w1 -= x1 - x;
  256. h1 -= y1 - y;
  257. _refreshWindow(x1, y1, w1, h1);
  258. _waitWhileBusy("refresh", partial_refresh_time);
  259. }
  260. void GxEPD2_270::powerOff(void)
  261. {
  262. _PowerOff();
  263. }
  264. void GxEPD2_270::hibernate()
  265. {
  266. _PowerOff();
  267. if (_rst >= 0)
  268. {
  269. _writeCommand(0x07); // deep sleep
  270. _writeData(0xA5); // check code
  271. _hibernating = true;
  272. }
  273. }
  274. void GxEPD2_270::_setPartialRamArea(uint8_t command, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
  275. {
  276. w = (w + 7 + (x % 8)) & 0xfff8; // byte boundary exclusive (round up)
  277. _writeCommand(command);
  278. _writeData(x >> 8);
  279. _writeData(x & 0xf8);
  280. _writeData(y >> 8);
  281. _writeData(y & 0xff);
  282. _writeData(w >> 8);
  283. _writeData(w & 0xf8);
  284. _writeData(h >> 8);
  285. _writeData(h & 0xff);
  286. }
  287. void GxEPD2_270::_refreshWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
  288. {
  289. w = (w + 7 + (x % 8)) & 0xfff8; // byte boundary exclusive (round up)
  290. h = gx_uint16_min(h, 256); // strange controller error
  291. _writeCommand(0x16);
  292. _writeData(x >> 8);
  293. _writeData(x & 0xf8);
  294. _writeData(y >> 8);
  295. _writeData(y & 0xff);
  296. _writeData(w >> 8);
  297. _writeData(w & 0xf8);
  298. _writeData(h >> 8);
  299. _writeData(h & 0xff);
  300. }
  301. void GxEPD2_270::_PowerOn()
  302. {
  303. if (!_power_is_on)
  304. {
  305. _writeCommand(0x04);
  306. _waitWhileBusy("_PowerOn", power_on_time);
  307. }
  308. _power_is_on = true;
  309. }
  310. void GxEPD2_270::_PowerOff()
  311. {
  312. _writeCommand(0x02); // power off
  313. _waitWhileBusy("_PowerOff", power_off_time);
  314. _power_is_on = false;
  315. _using_partial_mode = false;
  316. }
  317. void GxEPD2_270::_InitDisplay()
  318. {
  319. if (_hibernating) _reset();
  320. _writeCommand(0x01); //POWER SETTING
  321. _writeData (0x03);
  322. _writeData (0x00);
  323. _writeData (0x2b);
  324. _writeData (0x2b);
  325. _writeCommand(0x06); //boost
  326. _writeData (0x07); //A
  327. _writeData (0x07); //B
  328. _writeData (0x17); //C
  329. _writeCommand(0x16);
  330. _writeData(0x00);
  331. //_writeCommand(0x04);
  332. //_waitWhileBusy("_wakeUp Power On");
  333. _writeCommand(0x00); //panel setting
  334. _writeData(0xbf); //KW-BF KWR-AF BWROTP 0f
  335. _writeCommand(0x30); //PLL setting
  336. _writeData (0x3a); //90 50HZ 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
  337. _writeCommand(0x61); //resolution setting
  338. _writeData (0x00);
  339. _writeData (0xb0); //176
  340. _writeData (0x01);
  341. _writeData (0x08); //264
  342. _writeCommand(0x82); //vcom_DC setting
  343. _writeData (0x08); //0x28:-2.0V,0x12:-0.9V
  344. }
  345. //full screen update LUT
  346. const uint8_t GxEPD2_270::lut_20_vcomDC[] PROGMEM =
  347. {
  348. 0x00, 0x00,
  349. 0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
  350. 0x60, 0x28, 0x28, 0x00, 0x00, 0x01,
  351. 0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
  352. 0x00, 0x12, 0x12, 0x00, 0x00, 0x01,
  353. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  354. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  355. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  356. };
  357. const uint8_t GxEPD2_270::lut_21_ww[] PROGMEM =
  358. {
  359. 0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
  360. 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
  361. 0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
  362. 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
  363. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  364. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  365. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  366. };
  367. const uint8_t GxEPD2_270::lut_22_bw[] PROGMEM =
  368. {
  369. 0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
  370. 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
  371. 0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
  372. 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
  373. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  374. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  375. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  376. };
  377. const uint8_t GxEPD2_270::lut_23_wb[] PROGMEM =
  378. {
  379. 0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
  380. 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
  381. 0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
  382. 0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
  383. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  384. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  385. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  386. };
  387. const uint8_t GxEPD2_270::lut_24_bb[] PROGMEM =
  388. {
  389. 0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
  390. 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
  391. 0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
  392. 0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
  393. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  394. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  395. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  396. };
  397. //partial screen update LUT
  398. const uint8_t GxEPD2_270::lut_20_vcomDC_partial[] PROGMEM =
  399. {
  400. 0x00, 0x00,
  401. 0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
  402. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  403. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  404. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  405. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  406. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  407. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  408. };
  409. const uint8_t GxEPD2_270::lut_21_ww_partial[] PROGMEM =
  410. {
  411. 0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
  412. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  413. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  414. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  415. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  416. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  417. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  418. };
  419. const uint8_t GxEPD2_270::lut_22_bw_partial[] PROGMEM =
  420. {
  421. 0x80, 0x19, 0x01, 0x00, 0x00, 0x01,
  422. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  423. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  424. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  425. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  426. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  427. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  428. };
  429. const uint8_t GxEPD2_270::lut_23_wb_partial[] PROGMEM =
  430. {
  431. 0x40, 0x19, 0x01, 0x00, 0x00, 0x01,
  432. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  433. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  434. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  435. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  436. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  437. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  438. };
  439. const uint8_t GxEPD2_270::lut_24_bb_partial[] PROGMEM =
  440. {
  441. 0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
  442. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  443. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  444. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  445. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  446. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  447. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  448. };
  449. void GxEPD2_270::_Init_Full()
  450. {
  451. _InitDisplay();
  452. _writeCommand(0x50); //VCOM AND DATA INTERVAL SETTING
  453. _writeData(0x97); //WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
  454. _writeCommand(0x20);
  455. _writeDataPGM(lut_20_vcomDC, sizeof(lut_20_vcomDC));
  456. _writeCommand(0x21);
  457. _writeDataPGM(lut_21_ww, sizeof(lut_21_ww));
  458. _writeCommand(0x22);
  459. _writeDataPGM(lut_22_bw, sizeof(lut_22_bw));
  460. _writeCommand(0x23);
  461. _writeDataPGM(lut_23_wb, sizeof(lut_23_wb));
  462. _writeCommand(0x24);
  463. _writeDataPGM(lut_24_bb, sizeof(lut_24_bb));
  464. _PowerOn();
  465. _using_partial_mode = false;
  466. }
  467. void GxEPD2_270::_Init_Part()
  468. {
  469. _InitDisplay();
  470. _writeCommand(0x50); //VCOM AND DATA INTERVAL SETTING
  471. _writeData(0x17); //WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
  472. _writeCommand(0x20);
  473. _writeDataPGM(lut_20_vcomDC_partial, sizeof(lut_20_vcomDC_partial));
  474. _writeCommand(0x21);
  475. _writeDataPGM(lut_21_ww_partial, sizeof(lut_21_ww_partial));
  476. _writeCommand(0x22);
  477. _writeDataPGM(lut_22_bw_partial, sizeof(lut_22_bw_partial));
  478. _writeCommand(0x23);
  479. _writeDataPGM(lut_23_wb_partial, sizeof(lut_23_wb_partial));
  480. _writeCommand(0x24);
  481. _writeDataPGM(lut_24_bb_partial, sizeof(lut_24_bb_partial));
  482. _PowerOn();
  483. _using_partial_mode = true;
  484. }
  485. void GxEPD2_270::_Update_Full()
  486. {
  487. _writeCommand(0x12); //display refresh
  488. _waitWhileBusy("_Update_Full", full_refresh_time);
  489. }
  490. void GxEPD2_270::_Update_Part()
  491. {
  492. _writeCommand(0x12); //display refresh
  493. _waitWhileBusy("_Update_Part", partial_refresh_time);
  494. }
  495. void GxEPD2_270::_writeDataPGM(const uint8_t* data, uint16_t n)
  496. {
  497. SPI.beginTransaction(_spi_settings);
  498. for (uint8_t i = 0; i < n; i++)
  499. {
  500. if (_cs >= 0) digitalWrite(_cs, LOW);
  501. SPI.transfer(pgm_read_byte(&*data++));
  502. if (_cs >= 0) digitalWrite(_cs, HIGH);
  503. }
  504. SPI.endTransaction();
  505. }