GxEPD2_154c.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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: IL0376F : http://www.e-paper-display.com/download_detail/downloadsId=541.html
  6. //
  7. // Author: Jean-Marc Zingg
  8. //
  9. // Version: see library.properties
  10. //
  11. // Library: https://github.com/ZinggJM/GxEPD2
  12. #include "GxEPD2_154c.h"
  13. const uint8_t GxEPD2_154c::bw2grey[] =
  14. {
  15. 0b00000000, 0b00000011, 0b00001100, 0b00001111,
  16. 0b00110000, 0b00110011, 0b00111100, 0b00111111,
  17. 0b11000000, 0b11000011, 0b11001100, 0b11001111,
  18. 0b11110000, 0b11110011, 0b11111100, 0b11111111,
  19. };
  20. GxEPD2_154c::GxEPD2_154c(int8_t cs, int8_t dc, int8_t rst, int8_t busy) :
  21. GxEPD2_EPD(cs, dc, rst, busy, LOW, 20000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
  22. {
  23. _paged = false;
  24. _second_phase = false;
  25. }
  26. void GxEPD2_154c::init(uint32_t serial_diag_bitrate)
  27. {
  28. GxEPD2_EPD::init(serial_diag_bitrate);
  29. _paged = false;
  30. _second_phase = false;
  31. }
  32. void GxEPD2_154c::init(uint32_t serial_diag_bitrate, bool initial, bool pulldown_rst_mode)
  33. {
  34. GxEPD2_EPD::init(serial_diag_bitrate, initial, pulldown_rst_mode);
  35. _paged = false;
  36. _second_phase = false;
  37. }
  38. void GxEPD2_154c::clearScreen(uint8_t value)
  39. {
  40. clearScreen(value, 0xFF);
  41. }
  42. void GxEPD2_154c::clearScreen(uint8_t black_value, uint8_t color_value)
  43. {
  44. _Init_Full();
  45. _writeCommand(0x10);
  46. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  47. {
  48. _writeData(bw2grey[(black_value & 0xF0) >> 4]);
  49. _writeData(bw2grey[black_value & 0x0F]);
  50. }
  51. _writeCommand(0x13);
  52. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  53. {
  54. _writeData(color_value);
  55. }
  56. _Update_Full();
  57. }
  58. void GxEPD2_154c::writeScreenBuffer(uint8_t value)
  59. {
  60. writeScreenBuffer(value, 0xFF);
  61. }
  62. void GxEPD2_154c::writeScreenBuffer(uint8_t black_value, uint8_t color_value)
  63. {
  64. _Init_Full();
  65. _writeCommand(0x10);
  66. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  67. {
  68. _writeData(bw2grey[(black_value & 0xF0) >> 4]);
  69. _writeData(bw2grey[black_value & 0x0F]);
  70. }
  71. _writeCommand(0x13);
  72. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  73. {
  74. _writeData(color_value);
  75. }
  76. }
  77. void GxEPD2_154c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  78. {
  79. writeImage(bitmap, NULL, x, y, w, h, invert, mirror_y, pgm);
  80. }
  81. void GxEPD2_154c::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)
  82. {
  83. //Serial.print("writeImage("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
  84. //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
  85. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  86. if (_paged && (x == 0) && (w == WIDTH) && (h < HEIGHT))
  87. {
  88. //Serial.println("paged");
  89. if (!_second_phase)
  90. {
  91. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
  92. {
  93. _writeData(bw2grey[(black[i] & 0xF0) >> 4]);
  94. _writeData(bw2grey[black[i] & 0x0F]);
  95. }
  96. if (y + h == HEIGHT) // last page
  97. {
  98. //Serial.println("phase 1 ended");
  99. _second_phase = true;
  100. _writeCommand(0x13);
  101. }
  102. }
  103. else
  104. {
  105. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
  106. {
  107. _writeData(color[i]);
  108. }
  109. if (y + h == HEIGHT) // last page
  110. {
  111. //Serial.println("phase 2 ended");
  112. _second_phase = false;
  113. _paged = false;
  114. }
  115. }
  116. }
  117. else
  118. {
  119. _paged = false;
  120. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  121. x -= x % 8; // byte boundary
  122. w = wb * 8; // byte boundary
  123. if ((w <= 0) || (h <= 0)) return;
  124. _Init_Full();
  125. _writeCommand(0x10);
  126. for (int16_t i = 0; i < HEIGHT; i++)
  127. {
  128. for (int16_t j = 0; j < WIDTH; j += 8)
  129. {
  130. uint8_t data = 0xFF;
  131. if (black)
  132. {
  133. if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
  134. {
  135. int16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
  136. if (pgm)
  137. {
  138. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  139. data = pgm_read_byte(&black[idx]);
  140. #else
  141. data = black[idx];
  142. #endif
  143. }
  144. else
  145. {
  146. data = black[idx];
  147. }
  148. if (invert) data = ~data;
  149. }
  150. }
  151. //_writeData(data);
  152. _writeData(bw2grey[(data & 0xF0) >> 4]);
  153. _writeData(bw2grey[data & 0x0F]);
  154. }
  155. }
  156. _writeCommand(0x13);
  157. for (int16_t i = 0; i < HEIGHT; i++)
  158. {
  159. for (int16_t j = 0; j < WIDTH; j += 8)
  160. {
  161. uint8_t data = 0xFF;
  162. if (color)
  163. {
  164. if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
  165. {
  166. int16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
  167. if (pgm)
  168. {
  169. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  170. data = pgm_read_byte(&color[idx]);
  171. #else
  172. data = color[idx];
  173. #endif
  174. }
  175. else
  176. {
  177. data = color[idx];
  178. }
  179. if (invert) data = ~data;
  180. }
  181. }
  182. _writeData(data);
  183. }
  184. }
  185. }
  186. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  187. }
  188. void GxEPD2_154c::writeImagePart(const uint8_t bitmap[], 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. writeImagePart(bitmap, NULL, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  192. }
  193. void GxEPD2_154c::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,
  194. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  195. {
  196. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  197. if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
  198. if ((x_part < 0) || (x_part >= w_bitmap)) return;
  199. if ((y_part < 0) || (y_part >= h_bitmap)) return;
  200. int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
  201. x_part -= x_part % 8; // byte boundary
  202. w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
  203. h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
  204. x -= x % 8; // byte boundary
  205. w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
  206. int16_t x1 = x < 0 ? 0 : x; // limit
  207. int16_t y1 = y < 0 ? 0 : y; // limit
  208. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  209. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  210. int16_t dx = x1 - x;
  211. int16_t dy = y1 - y;
  212. w1 -= dx;
  213. h1 -= dy;
  214. if ((w1 <= 0) || (h1 <= 0)) return;
  215. _Init_Full();
  216. _writeCommand(0x10);
  217. for (int16_t i = 0; i < HEIGHT; i++)
  218. {
  219. for (int16_t j = 0; j < WIDTH; j += 8)
  220. {
  221. uint8_t data = 0xFF;
  222. if (black)
  223. {
  224. if ((j >= x1) && (j <= x1 + w) && (i >= y1) && (i < y1 + h))
  225. {
  226. // use wb_bitmap, h_bitmap of bitmap for index!
  227. //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;
  228. int16_t idx = mirror_y ? (x_part + j - x1) / 8 + ((h_bitmap - 1 - (y_part + i - y1))) * wb_bitmap : (x_part + j - x1) / 8 + (y_part + i - y1) * wb_bitmap;
  229. if (pgm)
  230. {
  231. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  232. data = pgm_read_byte(&black[idx]);
  233. #else
  234. data = black[idx];
  235. #endif
  236. }
  237. else
  238. {
  239. data = black[idx];
  240. }
  241. if (invert) data = ~data;
  242. }
  243. }
  244. //_writeData(data);
  245. _writeData(bw2grey[(data & 0xF0) >> 4]);
  246. _writeData(bw2grey[data & 0x0F]);
  247. }
  248. }
  249. _writeCommand(0x13);
  250. for (int16_t i = 0; i < HEIGHT; i++)
  251. {
  252. for (int16_t j = 0; j < WIDTH; j += 8)
  253. {
  254. uint8_t data = 0xFF;
  255. if (color)
  256. {
  257. if ((j >= x1) && (j <= x1 + w) && (i >= y1) && (i < y1 + h))
  258. {
  259. // use wb_bitmap, h_bitmap of bitmap for index!
  260. int16_t idx = mirror_y ? (x_part + j - x1) / 8 + ((h_bitmap - 1 - (y_part + i - y1))) * wb_bitmap : (x_part + j - x1) / 8 + (y_part + i - y1) * wb_bitmap;
  261. if (pgm)
  262. {
  263. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  264. data = pgm_read_byte(&color[idx]);
  265. #else
  266. data = color[idx];
  267. #endif
  268. }
  269. else
  270. {
  271. data = color[idx];
  272. }
  273. if (invert) data = ~data;
  274. }
  275. }
  276. _writeData(data);
  277. }
  278. }
  279. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  280. }
  281. void GxEPD2_154c::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)
  282. {
  283. if (data1)
  284. {
  285. writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
  286. }
  287. }
  288. void GxEPD2_154c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  289. {
  290. writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
  291. refresh(x, y, w, h);
  292. }
  293. void GxEPD2_154c::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  294. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  295. {
  296. writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  297. refresh(x, y, w, h);
  298. }
  299. void GxEPD2_154c::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)
  300. {
  301. writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
  302. refresh(x, y, w, h);
  303. }
  304. void GxEPD2_154c::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,
  305. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  306. {
  307. writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  308. refresh(x, y, w, h);
  309. }
  310. void GxEPD2_154c::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)
  311. {
  312. writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
  313. refresh(x, y, w, h);
  314. }
  315. void GxEPD2_154c::refresh(bool partial_update_mode)
  316. {
  317. if (_paged) return;
  318. _Update_Full();
  319. }
  320. void GxEPD2_154c::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
  321. {
  322. _Update_Full();
  323. }
  324. void GxEPD2_154c::powerOff()
  325. {
  326. _PowerOff();
  327. }
  328. void GxEPD2_154c::hibernate()
  329. {
  330. _PowerOff();
  331. if (_rst >= 0)
  332. {
  333. // check if it supports this command!
  334. _writeCommand(0x07); // deep sleep
  335. _writeData(0xA5); // check code
  336. _hibernating = true;
  337. }
  338. }
  339. void GxEPD2_154c::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
  340. {
  341. }
  342. void GxEPD2_154c::_PowerOn()
  343. {
  344. if (!_power_is_on)
  345. {
  346. _writeCommand(0x04);
  347. _waitWhileBusy("_PowerOn", power_on_time);
  348. }
  349. _power_is_on = true;
  350. }
  351. void GxEPD2_154c::_PowerOff()
  352. {
  353. _writeCommand(0x50);
  354. _writeData(0x17); //BD floating
  355. _writeCommand(0x82); //to solve Vcom drop
  356. _writeData(0x00);
  357. _writeCommand(0x01); //power setting
  358. _writeData(0x02); //gate switch to external
  359. _writeData(0x00);
  360. _writeData(0x00);
  361. _writeData(0x00);
  362. delay(1500); //delay 1.5S
  363. _writeCommand(0x02); // power off
  364. //_waitWhileBusy("_PowerOff", power_off_time);
  365. _power_is_on = false;
  366. }
  367. void GxEPD2_154c::setPaged()
  368. {
  369. _paged = true;
  370. _second_phase = false;
  371. _Init_Full();
  372. _writeCommand(0x10);
  373. }
  374. void GxEPD2_154c::_InitDisplay()
  375. {
  376. if (_hibernating) _reset();
  377. _writeCommand(0x01);
  378. _writeData(0x07);
  379. _writeData(0x00);
  380. _writeData(0x08);
  381. _writeData(0x00);
  382. _writeCommand(0x06);
  383. _writeData(0x07);
  384. _writeData(0x07);
  385. _writeData(0x07);
  386. _PowerOn(); //power on needed here!
  387. _writeCommand(0x00);
  388. _writeData(0xcf);
  389. _writeCommand(0x50);
  390. _writeData(0x37);
  391. _writeCommand(0x30);
  392. _writeData(0x39);
  393. _writeCommand(0x61);
  394. _writeData(0xC8);
  395. _writeData(0x00);
  396. _writeData(0xC8);
  397. _writeCommand(0x82);
  398. _writeData(0x0E);
  399. }
  400. const uint8_t GxEPD2_154c::lut_20_vcom0[] PROGMEM = { 0x0E , 0x14 , 0x01 , 0x0A , 0x06 , 0x04 , 0x0A , 0x0A , 0x0F , 0x03 , 0x03 , 0x0C , 0x06 , 0x0A , 0x00 };
  401. const uint8_t GxEPD2_154c::lut_21_w[] PROGMEM = { 0x0E , 0x14 , 0x01 , 0x0A , 0x46 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x86 , 0x0A , 0x04 };
  402. const uint8_t GxEPD2_154c::lut_22_b[] PROGMEM = { 0x0E , 0x14 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x4A , 0x04 };
  403. const uint8_t GxEPD2_154c::lut_23_g1[] PROGMEM = { 0x8E , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
  404. const uint8_t GxEPD2_154c::lut_24_g2[] PROGMEM = { 0x8E , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
  405. const uint8_t GxEPD2_154c::lut_25_vcom1[] PROGMEM = { 0x03 , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
  406. const uint8_t GxEPD2_154c::lut_26_red0[] PROGMEM = { 0x83 , 0x5D , 0x01 , 0x81 , 0x48 , 0x23 , 0x77 , 0x77 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
  407. const uint8_t GxEPD2_154c::lut_27_red1[] PROGMEM = { 0x03 , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
  408. void GxEPD2_154c::_Init_Full()
  409. {
  410. _InitDisplay();
  411. _writeCommand(0x20);
  412. _writeDataPGM(lut_20_vcom0, sizeof(lut_20_vcom0));
  413. _writeCommand(0x21);
  414. _writeDataPGM(lut_21_w, sizeof(lut_21_w));
  415. _writeCommand(0x22);
  416. _writeDataPGM(lut_22_b, sizeof(lut_22_b));
  417. _writeCommand(0x23);
  418. _writeDataPGM(lut_23_g1, sizeof(lut_23_g1));
  419. _writeCommand(0x24);
  420. _writeDataPGM(lut_24_g2, sizeof(lut_24_g2));
  421. _writeCommand(0x25);
  422. _writeDataPGM(lut_25_vcom1, sizeof(lut_25_vcom1));
  423. _writeCommand(0x26);
  424. _writeDataPGM(lut_26_red0, sizeof(lut_26_red0));
  425. _writeCommand(0x27);
  426. _writeDataPGM(lut_27_red1, sizeof(lut_27_red1));
  427. _PowerOn();
  428. }
  429. void GxEPD2_154c::_Init_Part()
  430. {
  431. _InitDisplay();
  432. _PowerOn();
  433. }
  434. void GxEPD2_154c::_Update_Full()
  435. {
  436. _writeCommand(0x12); //display refresh
  437. _waitWhileBusy("_Update_Full", full_refresh_time);
  438. }
  439. void GxEPD2_154c::_Update_Part()
  440. {
  441. _writeCommand(0x12); //display refresh
  442. _waitWhileBusy("_Update_Part", partial_refresh_time);
  443. }