GxEPD2_437c.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. // Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
  2. // Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
  3. //
  4. // based on Demo Example from Waveshare: https://github.com/waveshare/e-Paper/tree/master/Arduino/epd4in37g
  5. // Panel: 4.37inch 4-Color E-Paper : https://www.waveshare.com/product/displays/e-paper/4.37inch-e-paper-module-g.htm
  6. // Controller: unknown
  7. // initcode extracted from Waveshare library file epd4in37g.cpp from: https://github.com/waveshare/e-Paper/tree/master/Arduino/epd4in37g
  8. //
  9. // Author: Jean-Marc Zingg
  10. //
  11. // Version: see library.properties
  12. //
  13. // Library: https://github.com/ZinggJM/GxEPD2
  14. #include "GxEPD2_437c.h"
  15. GxEPD2_437c::GxEPD2_437c(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
  16. GxEPD2_EPD(cs, dc, rst, busy, LOW, 25000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
  17. {
  18. _paged = false;
  19. }
  20. void GxEPD2_437c::clearScreen(uint8_t value)
  21. {
  22. clearScreen(value, 0xFF);
  23. }
  24. void GxEPD2_437c::clearScreen(uint8_t black_value, uint8_t color_value)
  25. {
  26. writeScreenBuffer(black_value, color_value);
  27. refresh();
  28. }
  29. void GxEPD2_437c::writeScreenBuffer(uint8_t value)
  30. {
  31. writeScreenBuffer(value, 0xFF);
  32. }
  33. void GxEPD2_437c::writeScreenBuffer(uint8_t black_value, uint8_t color_value)
  34. {
  35. //Serial.println("writeScreenBuffer");
  36. if (!_init_display_done) _InitDisplay();
  37. _writeCommand(0x10);
  38. _startTransfer();
  39. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 4; i++)
  40. {
  41. _transfer(0xFF == black_value ? 0x55 : 0x00);
  42. }
  43. _endTransfer();
  44. _initial_write = false; // initial full screen buffer clean done
  45. }
  46. void GxEPD2_437c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  47. {
  48. //Serial.print("writeImage("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
  49. //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
  50. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  51. if (!_init_display_done) _InitDisplay();
  52. if (_initial_write) writeScreenBuffer();
  53. if (hasPartialUpdate)
  54. {
  55. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  56. x -= x % 8; // byte boundary
  57. w = wb * 8; // byte boundary
  58. int16_t x1 = x < 0 ? 0 : x; // limit
  59. int16_t y1 = y < 0 ? 0 : y; // limit
  60. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  61. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  62. int16_t dx = x1 - x;
  63. int16_t dy = y1 - y;
  64. w1 -= dx;
  65. h1 -= dy;
  66. if ((w1 <= 0) || (h1 <= 0)) return;
  67. _setPartialRamArea(x1, y1, w1, h1);
  68. _writeCommand(0x10);
  69. _startTransfer();
  70. for (int16_t i = 0; i < h1; i++)
  71. {
  72. for (int16_t j = 0; j < w1 / 8; j++)
  73. {
  74. uint8_t data = 0xFF;
  75. // use wb, h of bitmap for index!
  76. uint32_t idx = mirror_y ? j + dx / 8 + uint32_t((h - 1 - (i + dy))) * wb : j + dx / 8 + uint32_t(i + dy) * wb;
  77. if (pgm)
  78. {
  79. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  80. data = pgm_read_byte(&bitmap[idx]);
  81. #else
  82. data = bitmap[idx];
  83. #endif
  84. }
  85. else
  86. {
  87. data = bitmap[idx];
  88. }
  89. if (invert) data = ~data;
  90. for (int16_t k = 0; k < 2; k++)
  91. {
  92. uint8_t data2 = (data & 0x80 ? 0x40 : 0x00) | (data & 0x40 ? 0x10 : 0x00) |
  93. (data & 0x20 ? 0x04 : 0x00) | (data & 0x10 ? 0x01 : 0x00);
  94. data <<= 4;
  95. _transfer(data2);
  96. }
  97. }
  98. }
  99. _endTransfer();
  100. }
  101. else
  102. {
  103. if (_paged && (x == 0) && (w == int16_t(WIDTH)) && (h < int16_t(HEIGHT)))
  104. {
  105. //Serial.println("paged");
  106. _startTransfer();
  107. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
  108. {
  109. uint8_t data = bitmap[i];
  110. for (int16_t k = 0; k < 2; k++)
  111. {
  112. uint8_t data2 = (data & 0x80 ? 0x40 : 0x00) | (data & 0x40 ? 0x10 : 0x00) |
  113. (data & 0x20 ? 0x04 : 0x00) | (data & 0x10 ? 0x01 : 0x00);
  114. data <<= 4;
  115. _transfer(data2);
  116. }
  117. }
  118. _endTransfer();
  119. if (y + h == HEIGHT) // last page
  120. {
  121. //Serial.println("paged ended");
  122. _paged = false;
  123. }
  124. }
  125. else
  126. {
  127. _paged = false;
  128. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  129. x -= x % 8; // byte boundary
  130. w = wb * 8; // byte boundary
  131. if ((w <= 0) || (h <= 0)) return;
  132. _writeCommand(0x10);
  133. _startTransfer();
  134. for (int16_t i = 0; i < int16_t(HEIGHT); i++)
  135. {
  136. for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
  137. {
  138. uint8_t data = 0xFF;
  139. if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
  140. {
  141. uint32_t idx = mirror_y ? (j - x) / 8 + uint32_t((h - 1 - (i - y))) * wb : (j - x) / 8 + uint32_t(i - y) * wb;
  142. if (pgm)
  143. {
  144. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  145. data = pgm_read_byte(&bitmap[idx]);
  146. #else
  147. data = bitmap[idx];
  148. #endif
  149. }
  150. else
  151. {
  152. data = bitmap[idx];
  153. }
  154. if (invert) data = ~data;
  155. }
  156. for (int16_t k = 0; k < 2; k++)
  157. {
  158. uint8_t data2 = (data & 0x80 ? 0x40 : 0x00) | (data & 0x40 ? 0x10 : 0x00) |
  159. (data & 0x20 ? 0x04 : 0x00) | (data & 0x10 ? 0x01 : 0x00);
  160. data <<= 4;
  161. _transfer(data2);
  162. }
  163. }
  164. }
  165. _endTransfer();
  166. }
  167. }
  168. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  169. }
  170. void GxEPD2_437c::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)
  171. {
  172. if (!black && !color) return;
  173. if (!color) return writeImage(black, x, y, w, h, invert, mirror_y, pgm);
  174. //Serial.print("writeImage("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
  175. //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
  176. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  177. if (!_init_display_done) _InitDisplay();
  178. if (_initial_write) writeScreenBuffer();
  179. if (hasPartialUpdate)
  180. {
  181. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  182. x -= x % 8; // byte boundary
  183. w = wb * 8; // byte boundary
  184. int16_t x1 = x < 0 ? 0 : x; // limit
  185. int16_t y1 = y < 0 ? 0 : y; // limit
  186. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  187. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  188. int16_t dx = x1 - x;
  189. int16_t dy = y1 - y;
  190. w1 -= dx;
  191. h1 -= dy;
  192. if ((w1 <= 0) || (h1 <= 0)) return;
  193. _setPartialRamArea(x1, y1, w1, h1);
  194. _writeCommand(0x10);
  195. _startTransfer();
  196. for (int16_t i = 0; i < h1; i++)
  197. {
  198. for (int16_t j = 0; j < w1 / 8; j++)
  199. {
  200. uint8_t black_data = 0xFF, color_data = 0xFF;
  201. // use wb, h of bitmap for index!
  202. uint32_t idx = mirror_y ? j + dx / 8 + uint32_t((h - 1 - (i + dy))) * wb : j + dx / 8 + uint32_t(i + dy) * wb;
  203. if (pgm)
  204. {
  205. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  206. black_data = pgm_read_byte(&black[idx]);
  207. color_data = pgm_read_byte(&color[idx]);
  208. #else
  209. black_data = black[idx];
  210. color_data = color[idx];
  211. #endif
  212. }
  213. else
  214. {
  215. black_data = black[idx];
  216. color_data = color[idx];
  217. }
  218. if (invert)
  219. {
  220. black_data = ~black_data;
  221. color_data = ~color_data;
  222. }
  223. for (int16_t k = 0; k < 2; k++)
  224. {
  225. uint8_t out_data = 0x00;
  226. for (int16_t l = 0; l < 4; l++)
  227. {
  228. out_data <<= 2;
  229. if (!(color_data & 0x80)) out_data |= 0x03; // red
  230. else out_data |= black_data & 0x80 ? 0x01 : 0x00; // white or black
  231. black_data <<= 1;
  232. color_data <<= 1;
  233. }
  234. _transfer(out_data);
  235. }
  236. }
  237. }
  238. _endTransfer();
  239. }
  240. else
  241. {
  242. if (_paged && (x == 0) && (w == int16_t(WIDTH)) && (h < int16_t(HEIGHT)))
  243. {
  244. //Serial.println("paged");
  245. _startTransfer();
  246. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
  247. {
  248. uint8_t black_data = black[i];
  249. uint8_t color_data = color[i];
  250. for (int16_t k = 0; k < 2; k++)
  251. {
  252. uint8_t out_data = 0x00;
  253. for (int16_t l = 0; l < 4; l++)
  254. {
  255. out_data <<= 2;
  256. if (!(color_data & 0x80)) out_data |= 0x03; // red
  257. else out_data |= black_data & 0x80 ? 0x01 : 0x00; // white or black
  258. black_data <<= 1;
  259. color_data <<= 1;
  260. }
  261. _transfer(out_data);
  262. }
  263. }
  264. _endTransfer();
  265. if (y + h == HEIGHT) // last page
  266. {
  267. //Serial.println("paged ended");
  268. _paged = false;
  269. }
  270. }
  271. else
  272. {
  273. _paged = false;
  274. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  275. x -= x % 8; // byte boundary
  276. w = wb * 8; // byte boundary
  277. if ((w <= 0) || (h <= 0)) return;
  278. _writeCommand(0x10);
  279. _startTransfer();
  280. for (int16_t i = 0; i < int16_t(HEIGHT); i++)
  281. {
  282. for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
  283. {
  284. uint8_t black_data = 0xFF, color_data = 0xFF;
  285. if ((j >= x) && (j < x + w) && (i >= y) && (i < y + h))
  286. {
  287. uint32_t idx = mirror_y ? (j - x) / 8 + uint32_t((h - 1 - (i - y))) * wb : (j - x) / 8 + uint32_t(i - y) * wb;
  288. if (pgm)
  289. {
  290. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  291. black_data = pgm_read_byte(&black[idx]);
  292. color_data = pgm_read_byte(&color[idx]);
  293. #else
  294. black_data = black[idx];
  295. color_data = color[idx];
  296. #endif
  297. }
  298. else
  299. {
  300. black_data = black[idx];
  301. color_data = color[idx];
  302. }
  303. if (invert)
  304. {
  305. black_data = ~black_data;
  306. color_data = ~color_data;
  307. }
  308. }
  309. for (int16_t k = 0; k < 2; k++)
  310. {
  311. uint8_t out_data = 0x00;
  312. for (int16_t l = 0; l < 4; l++)
  313. {
  314. out_data <<= 2;
  315. if (!(color_data & 0x80)) out_data |= 0x03; // red
  316. else out_data |= black_data & 0x80 ? 0x01 : 0x00; // white or black
  317. black_data <<= 1;
  318. color_data <<= 1;
  319. }
  320. _transfer(out_data);
  321. }
  322. }
  323. }
  324. _endTransfer();
  325. }
  326. }
  327. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  328. }
  329. void GxEPD2_437c::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  330. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  331. {
  332. //Serial.print("writeImagePart("); Serial.print(x_part); Serial.print(", "); Serial.print(y_part); Serial.print(", ");
  333. //Serial.print(w_bitmap); Serial.print(", "); Serial.print(h_bitmap); Serial.print(", ");
  334. //Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
  335. //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
  336. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  337. if (!_init_display_done) _InitDisplay();
  338. if (_initial_write) writeScreenBuffer();
  339. if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
  340. if ((x_part < 0) || (x_part >= w_bitmap)) return;
  341. if ((y_part < 0) || (y_part >= h_bitmap)) return;
  342. int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
  343. x_part -= x_part % 8; // byte boundary
  344. w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
  345. h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
  346. // make x, w multiple of 8
  347. w += x % 8; // adjust for byte boundary of x
  348. x -= x % 8; // byte boundary ox
  349. w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
  350. int16_t x1 = x < 0 ? 0 : x; // limit
  351. int16_t y1 = y < 0 ? 0 : y; // limit
  352. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  353. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  354. int16_t dx = x1 - x;
  355. int16_t dy = y1 - y;
  356. w1 -= dx;
  357. h1 -= dy;
  358. if ((w1 <= 0) || (h1 <= 0)) return;
  359. if (hasPartialUpdate)
  360. {
  361. _setPartialRamArea(x1, y1, w1, h1);
  362. _writeCommand(0x10);
  363. _startTransfer();
  364. for (int16_t i = 0; i < h1; i++)
  365. {
  366. for (int16_t j = 0; j < w1 / 8; j++)
  367. {
  368. uint8_t data;
  369. // use wb_bitmap, h_bitmap of bitmap for index!
  370. uint32_t idx = mirror_y ? x_part / 8 + j + dx / 8 + uint32_t((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + uint32_t(y_part + i + dy) * wb_bitmap;
  371. if (pgm)
  372. {
  373. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  374. data = pgm_read_byte(&bitmap[idx]);
  375. #else
  376. data = bitmap[idx];
  377. #endif
  378. }
  379. else
  380. {
  381. data = bitmap[idx];
  382. }
  383. if (invert) data = ~data;
  384. for (int16_t k = 0; k < 2; k++)
  385. {
  386. uint8_t data2 = (data & 0x80 ? 0x40 : 0x00) | (data & 0x40 ? 0x10 : 0x00) |
  387. (data & 0x20 ? 0x04 : 0x00) | (data & 0x10 ? 0x01 : 0x00);
  388. data <<= 4;
  389. _transfer(data2);
  390. }
  391. }
  392. }
  393. _endTransfer();
  394. }
  395. else
  396. {
  397. _writeCommand(0x10);
  398. _startTransfer();
  399. for (int16_t i = 0; i < int16_t(HEIGHT); i++)
  400. {
  401. for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
  402. {
  403. uint8_t data = 0xFF;
  404. if ((j >= x1) && (j < x1 + w) && (i >= y1) && (i < y1 + h))
  405. {
  406. // use wb_bitmap, h_bitmap of bitmap for index!
  407. uint32_t idx = mirror_y ? (x_part + j - x1) / 8 + uint32_t((h_bitmap - 1 - (y_part + i - y1))) * wb_bitmap : (x_part + j - x1) / 8 + uint32_t(y_part + i - y1) * wb_bitmap;
  408. if (pgm)
  409. {
  410. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  411. data = pgm_read_byte(&bitmap[idx]);
  412. #else
  413. data = bitmap[idx];
  414. #endif
  415. }
  416. else
  417. {
  418. data = bitmap[idx];
  419. }
  420. if (invert) data = ~data;
  421. }
  422. for (int16_t k = 0; k < 2; k++)
  423. {
  424. uint8_t data2 = (data & 0x80 ? 0x40 : 0x00) | (data & 0x40 ? 0x10 : 0x00) |
  425. (data & 0x20 ? 0x04 : 0x00) | (data & 0x10 ? 0x01 : 0x00);
  426. data <<= 4;
  427. _transfer(data2);
  428. }
  429. }
  430. }
  431. _endTransfer();
  432. }
  433. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  434. }
  435. void GxEPD2_437c::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,
  436. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  437. {
  438. //Serial.print("writeImagePart("); Serial.print(x_part); Serial.print(", "); Serial.print(y_part); Serial.print(", ");
  439. //Serial.print(w_bitmap); Serial.print(", "); Serial.print(h_bitmap); Serial.print(", ");
  440. //Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
  441. //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
  442. if (!black && !color) return;
  443. if (!color) return writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  444. if (!_init_display_done) _InitDisplay();
  445. if (_initial_write) writeScreenBuffer();
  446. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  447. if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
  448. if ((x_part < 0) || (x_part >= w_bitmap)) return;
  449. if ((y_part < 0) || (y_part >= h_bitmap)) return;
  450. int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
  451. x_part -= x_part % 8; // byte boundary
  452. w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
  453. h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
  454. // make x, w multiple of 8
  455. w += x % 8; // adjust for byte boundary of x
  456. x -= x % 8; // byte boundary ox
  457. w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
  458. int16_t x1 = x < 0 ? 0 : x; // limit
  459. int16_t y1 = y < 0 ? 0 : y; // limit
  460. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  461. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  462. int16_t dx = x1 - x;
  463. int16_t dy = y1 - y;
  464. w1 -= dx;
  465. h1 -= dy;
  466. if ((w1 <= 0) || (h1 <= 0)) return;
  467. if (hasPartialUpdate)
  468. {
  469. _setPartialRamArea(x1, y1, w1, h1);
  470. _writeCommand(0x10);
  471. _startTransfer();
  472. for (int16_t i = 0; i < h1; i++)
  473. {
  474. for (int16_t j = 0; j < w1 / 8; j++)
  475. {
  476. uint8_t black_data = 0xFF, color_data = 0xFF;
  477. // use wb_bitmap, h_bitmap of bitmap for index!
  478. uint32_t idx = mirror_y ? x_part / 8 + j + dx / 8 + uint32_t((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + uint32_t(y_part + i + dy) * wb_bitmap;
  479. if (pgm)
  480. {
  481. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  482. black_data = pgm_read_byte(&black[idx]);
  483. color_data = pgm_read_byte(&color[idx]);
  484. #else
  485. black_data = black[idx];
  486. color_data = color[idx];
  487. #endif
  488. }
  489. else
  490. {
  491. black_data = black[idx];
  492. color_data = color[idx];
  493. }
  494. for (int16_t k = 0; k < 2; k++)
  495. {
  496. uint8_t out_data = 0x00;
  497. for (int16_t l = 0; l < 4; l++)
  498. {
  499. out_data <<= 2;
  500. if (!(color_data & 0x80)) out_data |= 0x03; // red
  501. else out_data |= black_data & 0x80 ? 0x01 : 0x00; // white or black
  502. black_data <<= 1;
  503. color_data <<= 1;
  504. }
  505. _transfer(out_data);
  506. }
  507. }
  508. }
  509. _endTransfer();
  510. }
  511. else
  512. {
  513. _writeCommand(0x10);
  514. _startTransfer();
  515. for (int16_t i = 0; i < int16_t(HEIGHT); i++)
  516. {
  517. for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
  518. {
  519. uint8_t black_data = 0xFF, color_data = 0xFF;
  520. if ((j >= x1) && (j < x1 + w) && (i >= y1) && (i < y1 + h))
  521. {
  522. // use wb_bitmap, h_bitmap of bitmap for index!
  523. uint32_t idx = mirror_y ? (x_part + j - x1) / 8 + uint32_t((h_bitmap - 1 - (y_part + i - y1))) * wb_bitmap : (x_part + j - x1) / 8 + uint32_t(y_part + i - y1) * wb_bitmap;
  524. if (pgm)
  525. {
  526. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  527. black_data = pgm_read_byte(&black[idx]);
  528. color_data = pgm_read_byte(&color[idx]);
  529. #else
  530. black_data = black[idx];
  531. color_data = color[idx];
  532. #endif
  533. }
  534. else
  535. {
  536. black_data = black[idx];
  537. color_data = color[idx];
  538. }
  539. if (invert)
  540. {
  541. black_data = ~black_data;
  542. color_data = ~color_data;
  543. }
  544. }
  545. for (int16_t k = 0; k < 2; k++)
  546. {
  547. uint8_t out_data = 0x00;
  548. for (int16_t l = 0; l < 4; l++)
  549. {
  550. out_data <<= 2;
  551. if (!(color_data & 0x80)) out_data |= 0x03; // red
  552. else out_data |= black_data & 0x80 ? 0x01 : 0x00; // white or black
  553. black_data <<= 1;
  554. color_data <<= 1;
  555. }
  556. _transfer(out_data);
  557. }
  558. }
  559. }
  560. _endTransfer();
  561. }
  562. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  563. }
  564. void GxEPD2_437c::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)
  565. {
  566. if (!data1) return;
  567. //Serial.print("writeNative("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
  568. //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
  569. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  570. if (!_init_display_done) _InitDisplay();
  571. if (_initial_write) writeScreenBuffer();
  572. if (hasPartialUpdate)
  573. {
  574. int16_t wb = (w + 3) / 4; // width bytes, bitmaps are padded
  575. x -= x % 4; // byte boundary
  576. w = wb * 4; // byte boundary
  577. int16_t x1 = x < 0 ? 0 : x; // limit
  578. int16_t y1 = y < 0 ? 0 : y; // limit
  579. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  580. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  581. int16_t dx = x1 - x;
  582. int16_t dy = y1 - y;
  583. w1 -= dx;
  584. h1 -= dy;
  585. if ((w1 <= 0) || (h1 <= 0)) return;
  586. _setPartialRamArea(x1, y1, w1, h1);
  587. _writeCommand(0x10);
  588. _startTransfer();
  589. for (int16_t i = 0; i < h1; i++)
  590. {
  591. for (int16_t j = 0; j < w1 / 4; j++)
  592. {
  593. uint8_t data;
  594. // use wb, h of bitmap for index!
  595. uint32_t idx = mirror_y ? j + dx / 4 + uint32_t((h - 1 - (i + dy))) * wb : j + dx / 4 + uint32_t(i + dy) * wb;
  596. if (pgm)
  597. {
  598. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  599. data = pgm_read_byte(&data1[idx]);
  600. #else
  601. data = data1[idx];
  602. #endif
  603. }
  604. else
  605. {
  606. data = data1[idx];
  607. }
  608. if (invert) data = ~data;
  609. _transfer(data);
  610. }
  611. }
  612. _endTransfer();
  613. }
  614. else
  615. {
  616. if (_paged && (x == 0) && (w == int16_t(WIDTH)) && (h < int16_t(HEIGHT)))
  617. {
  618. //Serial.println("paged");
  619. _startTransfer();
  620. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 4; i++)
  621. {
  622. uint8_t data = data1[i];
  623. _transfer(data);
  624. }
  625. _endTransfer();
  626. if (y + h == HEIGHT) // last page
  627. {
  628. //Serial.println("paged ended");
  629. _paged = false;
  630. }
  631. }
  632. else
  633. {
  634. //Serial.println("not paged");
  635. _paged = false;
  636. int16_t wb = (w + 3) / 4; // width bytes, bitmaps are padded
  637. x -= x % 4; // byte boundary
  638. w = wb * 4; // byte boundary
  639. if ((w <= 0) || (h <= 0)) return;
  640. _writeCommand(0x10);
  641. _startTransfer();
  642. for (int16_t i = 0; i < int16_t(HEIGHT); i++)
  643. {
  644. for (int16_t j = 0; j < int16_t(WIDTH); j += 4)
  645. {
  646. uint8_t data = 0x55;
  647. if (data1)
  648. {
  649. if ((j >= x) && (j < x + w) && (i >= y) && (i < y + h))
  650. {
  651. uint32_t idx = mirror_y ? (j - x) / 4 + uint32_t((h - 1 - (i - y))) * wb : (j - x) / 4 + uint32_t(i - y) * wb;
  652. if (pgm)
  653. {
  654. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  655. data = pgm_read_byte(&data1[idx]);
  656. #else
  657. data = data1[idx];
  658. #endif
  659. }
  660. else
  661. {
  662. data = data1[idx];
  663. }
  664. if (invert) data = ~data;
  665. }
  666. }
  667. _transfer(data);
  668. }
  669. }
  670. _endTransfer();
  671. }
  672. }
  673. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  674. }
  675. void GxEPD2_437c::writeNativePart(const uint8_t* data1, const uint8_t* data2, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  676. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  677. {
  678. if (!data1) return;
  679. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  680. if (!_init_display_done) _InitDisplay();
  681. if (_initial_write) writeScreenBuffer();
  682. if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
  683. if ((x_part < 0) || (x_part >= w_bitmap)) return;
  684. if ((y_part < 0) || (y_part >= h_bitmap)) return;
  685. int16_t wb_bitmap = (w_bitmap + 3) / 4; // width bytes, bitmaps are padded
  686. x_part -= x_part % 4; // byte boundary
  687. w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
  688. h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
  689. w += x % 4; // adjust for byte boundary of x
  690. x -= x % 4; // byte boundary
  691. w = 4 * ((w + 3) / 4); // byte boundary, bitmaps are padded
  692. int16_t x1 = x < 0 ? 0 : x; // limit
  693. int16_t y1 = y < 0 ? 0 : y; // limit
  694. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  695. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  696. int16_t dx = x1 - x;
  697. int16_t dy = y1 - y;
  698. w1 -= dx;
  699. h1 -= dy;
  700. if ((w1 <= 0) || (h1 <= 0)) return;
  701. if (hasPartialUpdate)
  702. {
  703. _setPartialRamArea(x1, y1, w1, h1);
  704. _writeCommand(0x10);
  705. _startTransfer();
  706. for (int16_t i = 0; i < h1; i++)
  707. {
  708. for (int16_t j = 0; j < w1 / 4; j++)
  709. {
  710. uint8_t data;
  711. // use wb_bitmap, h_bitmap of bitmap for index!
  712. uint32_t idx = mirror_y ? x_part / 4 + j + dx / 4 + uint32_t((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 4 + j + dx / 4 + uint32_t(y_part + i + dy) * wb_bitmap;
  713. if (pgm)
  714. {
  715. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  716. data = pgm_read_byte(&data1[idx]);
  717. #else
  718. data = data1[idx];
  719. #endif
  720. }
  721. else
  722. {
  723. data = data1[idx];
  724. }
  725. if (invert) data = ~data;
  726. _transfer(data);
  727. }
  728. }
  729. _endTransfer();
  730. }
  731. else
  732. {
  733. _writeCommand(0x10);
  734. _startTransfer();
  735. for (int16_t i = 0; i < int16_t(HEIGHT); i++)
  736. {
  737. for (int16_t j = 0; j < int16_t(WIDTH); j += 4)
  738. {
  739. uint8_t data = 0x55;
  740. if ((j >= x1) && (j < x1 + w) && (i >= y1) && (i < y1 + h))
  741. {
  742. // use wb_bitmap, h_bitmap of bitmap for index!
  743. uint32_t idx = mirror_y ? (x_part + j - x1) / 4 + uint32_t((h_bitmap - 1 - (y_part + i - y1))) * wb_bitmap : (x_part + j - x1) / 4 + uint32_t(y_part + i - y1) * wb_bitmap;
  744. if (pgm)
  745. {
  746. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  747. data = pgm_read_byte(&data1[idx]);
  748. #else
  749. data = data1[idx];
  750. #endif
  751. }
  752. else
  753. {
  754. data = data1[idx];
  755. }
  756. if (invert) data = ~data;
  757. }
  758. _transfer(data);
  759. }
  760. }
  761. _endTransfer();
  762. }
  763. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  764. }
  765. void GxEPD2_437c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  766. {
  767. writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
  768. refresh(x, y, w, h);
  769. }
  770. void GxEPD2_437c::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  771. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  772. {
  773. writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  774. refresh(x, y, w, h);
  775. }
  776. void GxEPD2_437c::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)
  777. {
  778. writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
  779. refresh(x, y, w, h);
  780. }
  781. void GxEPD2_437c::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,
  782. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  783. {
  784. writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  785. refresh(x, y, w, h);
  786. }
  787. void GxEPD2_437c::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)
  788. {
  789. writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
  790. refresh(x, y, w, h);
  791. }
  792. void GxEPD2_437c::refresh(bool partial_update_mode)
  793. {
  794. if (hasPartialUpdate) _setPartialRamArea(0, 0, WIDTH, HEIGHT);
  795. _refresh(partial_update_mode);
  796. }
  797. void GxEPD2_437c::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
  798. {
  799. // intersection with screen
  800. int16_t w1 = x < 0 ? w + x : w; // reduce
  801. int16_t h1 = y < 0 ? h + y : h; // reduce
  802. int16_t x1 = x < 0 ? 0 : x; // limit
  803. int16_t y1 = y < 0 ? 0 : y; // limit
  804. w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
  805. h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
  806. if ((w1 <= 0) || (h1 <= 0)) return;
  807. // make x1, w1 multiple of 4
  808. w1 += x1 % 4;
  809. if (w1 % 4 > 0) w1 += 4 - w1 % 4;
  810. x1 -= x1 % 4;
  811. bool fullscreen = ((x1 == 0) && (y1 == 0) && (w1 == WIDTH) && (h1 == HEIGHT));
  812. if (hasPartialUpdate) _setPartialRamArea(x1, y1, w1, h1, !fullscreen);
  813. _refresh(!fullscreen);
  814. }
  815. void GxEPD2_437c::powerOff()
  816. {
  817. _PowerOff();
  818. }
  819. void GxEPD2_437c::hibernate()
  820. {
  821. _PowerOff();
  822. if (_rst >= 0)
  823. {
  824. _writeCommand(0x07); // deep sleep
  825. _writeData(0xA5); // control code
  826. _hibernating = true;
  827. _init_display_done = false;
  828. }
  829. }
  830. void GxEPD2_437c::setPaged()
  831. {
  832. if (!hasPartialUpdate)
  833. {
  834. _paged = true;
  835. _InitDisplay();
  836. _writeCommand(0x10);
  837. }
  838. }
  839. void GxEPD2_437c::_refresh(bool partial_update_mode)
  840. {
  841. _writeCommand(0x50); // VCOM and Data Interval Setting
  842. _writeData(partial_update_mode ? 0x97 : 0x37); // floating or white
  843. _writeCommand(0x12); // Display Refresh
  844. _writeData(0x00);
  845. delay(1);
  846. _waitWhileBusy("_refresh", full_refresh_time);
  847. //_power_is_on = false; // not needed
  848. _init_display_done = false; // needed
  849. }
  850. void GxEPD2_437c::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial_mode)
  851. {
  852. //Serial.print("_setPartialRamArea("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
  853. //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
  854. _writeCommand(0x83);
  855. _writeData(x / 256);
  856. _writeData(x % 256);
  857. _writeData((x + w - 1) / 256);
  858. _writeData((x + w - 1) % 256);
  859. _writeData(y / 256);
  860. _writeData(y % 256);
  861. _writeData((y + h - 1) / 256);
  862. _writeData((y + h - 1) % 256);
  863. _writeData(partial_mode ? 0x01 : 0x00);
  864. }
  865. void GxEPD2_437c::_PowerOn()
  866. {
  867. if (!_power_is_on)
  868. {
  869. _writeCommand(0x04);
  870. _waitWhileBusy("_PowerOn", power_on_time);
  871. }
  872. _power_is_on = true;
  873. }
  874. void GxEPD2_437c::_PowerOff()
  875. {
  876. if (_power_is_on)
  877. {
  878. _writeCommand(0x02);
  879. _writeData(0x00);
  880. _waitWhileBusy("_PowerOff", power_off_time);
  881. }
  882. _power_is_on = false;
  883. }
  884. void GxEPD2_437c::_InitDisplay()
  885. {
  886. if ((_rst >= 0) && (_hibernating || _initial_write))
  887. {
  888. digitalWrite(_rst, HIGH);
  889. delay(20); // At least 20ms delay
  890. digitalWrite(_rst, LOW); // Module reset
  891. delay(2); // At least 40ms delay, 2ms for WS "clever" reset
  892. digitalWrite(_rst, HIGH);
  893. delay(2); // At least 50ms delay (32ms measured)
  894. _waitWhileBusy("_InitDisplay reset", power_on_time);
  895. _hibernating = false;
  896. _power_is_on = false;
  897. }
  898. if (_initial_write) delay(20);
  899. _writeCommand(0xAA); // CMDH
  900. _writeData(0x49);
  901. _writeData(0x55);
  902. _writeData(0x20);
  903. _writeData(0x08);
  904. _writeData(0x09);
  905. _writeData(0x18);
  906. _writeCommand(0x01); // Power Settings
  907. _writeData(0x3F);
  908. _writeCommand(0x00); // Panel Settings
  909. _writeData(0x4F);
  910. _writeData(0x69);
  911. _writeCommand(0x05); // BTST1
  912. _writeData(0x40);
  913. _writeData(0x1F);
  914. _writeData(0x1F);
  915. _writeData(0x2C);
  916. _writeCommand(0x08); // BTST3
  917. _writeData(0x6F);
  918. _writeData(0x1F);
  919. _writeData(0x1F);
  920. _writeData(0x22);
  921. _writeCommand(0x06); // Booster Soft Start
  922. _writeData(0x6F);
  923. _writeData(0x1F);
  924. _writeData(0x17);
  925. _writeData(0x17);
  926. _writeCommand(0x03); // Power Off Sequence
  927. _writeData(0x00);
  928. _writeData(0x54);
  929. _writeData(0x00);
  930. _writeData(0x44);
  931. _writeCommand(0x50); // VCOM and Data Interval Setting
  932. _writeData(0x3F); // white border
  933. _writeCommand(0x60); // TCON
  934. _writeData(0x02);
  935. _writeData(0x00);
  936. _writeCommand(0x30); // PLL Control
  937. _writeData(0x08);
  938. _writeCommand(0x61); // Resolution Setting
  939. _writeData(0x02);
  940. _writeData(0x00);
  941. _writeData(0x01);
  942. _writeData(0x70);
  943. _writeCommand(0xE3); // PWS
  944. _writeData(0x2F);
  945. _writeCommand(0x84); // T_VDCS
  946. _writeData(0x01);
  947. _PowerOn();
  948. _init_display_done = true;
  949. }