GxEPD2_583c.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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: IL0371 : http://www.e-paper-display.com/download_detail/downloadsId=536.html
  6. //
  7. // Author: Jean-Marc Zingg
  8. //
  9. // Version: see library.properties
  10. //
  11. // Library: https://github.com/ZinggJM/GxEPD2
  12. #include "GxEPD2_583c.h"
  13. //#include "WaveTables3c.h"
  14. GxEPD2_583c::GxEPD2_583c(int8_t cs, int8_t dc, int8_t rst, int8_t busy) :
  15. GxEPD2_EPD(cs, dc, rst, busy, LOW, 40000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
  16. {
  17. _initial = true;
  18. _power_is_on = false;
  19. _hibernating = false;
  20. }
  21. void GxEPD2_583c::init(uint32_t serial_diag_bitrate)
  22. {
  23. GxEPD2_EPD::init(serial_diag_bitrate);
  24. _initial = true;
  25. _power_is_on = false;
  26. _hibernating = false;
  27. }
  28. void GxEPD2_583c::clearScreen(uint8_t value)
  29. {
  30. if (value == 0xFF) value = 0x33; // white value for this controller
  31. _Init_Part();
  32. _writeCommand(0x91); // partial in
  33. _setPartialRamArea(0, 0, WIDTH, HEIGHT);
  34. _writeCommand(0x10);
  35. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 2; i++)
  36. {
  37. _writeData(value);
  38. }
  39. _Update_Part();
  40. _writeCommand(0x92); // partial out
  41. }
  42. void GxEPD2_583c::clearScreen(uint8_t black_value, uint8_t color_value)
  43. {
  44. _Init_Part();
  45. _writeCommand(0x91); // partial in
  46. _setPartialRamArea(0, 0, WIDTH, HEIGHT);
  47. _writeCommand(0x10);
  48. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  49. {
  50. _send8pixel(~black_value, ~color_value);
  51. }
  52. _Update_Part();
  53. _writeCommand(0x92); // partial out
  54. }
  55. void GxEPD2_583c::writeScreenBuffer(uint8_t value)
  56. {
  57. if (value == 0xFF) value = 0x33; // white value for this controller
  58. _Init_Part();
  59. _writeCommand(0x91); // partial in
  60. _setPartialRamArea(0, 0, WIDTH, HEIGHT);
  61. _writeCommand(0x10);
  62. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 2; i++)
  63. {
  64. _writeData(value);
  65. }
  66. _writeCommand(0x92); // partial out
  67. }
  68. void GxEPD2_583c::writeScreenBuffer(uint8_t black_value, uint8_t color_value)
  69. {
  70. _Init_Part();
  71. _writeCommand(0x91); // partial in
  72. _setPartialRamArea(0, 0, WIDTH, HEIGHT);
  73. _writeCommand(0x10);
  74. for (uint32_t i = 0; uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  75. {
  76. _send8pixel(~black_value, ~color_value);
  77. }
  78. _writeCommand(0x92); // partial out
  79. }
  80. void GxEPD2_583c::writeImage(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. writeImage(bitmap, NULL, x, y, w, h, invert, mirror_y, pgm);
  83. }
  84. void GxEPD2_583c::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)
  85. {
  86. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  87. int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
  88. x -= x % 8; // byte boundary
  89. w = wb * 8; // byte boundary
  90. int16_t x1 = x < 0 ? 0 : x; // limit
  91. int16_t y1 = y < 0 ? 0 : y; // limit
  92. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  93. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  94. int16_t dx = x1 - x;
  95. int16_t dy = y1 - y;
  96. w1 -= dx;
  97. h1 -= dy;
  98. if ((w1 <= 0) || (h1 <= 0)) return;
  99. _Init_Part();
  100. _writeCommand(0x91); // partial in
  101. _setPartialRamArea(x1, y1, w1, h1);
  102. _writeCommand(0x10);
  103. for (int16_t i = 0; i < h1; i++)
  104. {
  105. for (int16_t j = 0; j < w1 / 8; j++)
  106. {
  107. uint8_t black_data = 0xFF;
  108. uint8_t color_data = 0xFF;
  109. if (black)
  110. {
  111. // use wb, h of bitmap for index!
  112. int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
  113. if (pgm)
  114. {
  115. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  116. black_data = pgm_read_byte(&black[idx]);
  117. #else
  118. black_data = black[idx];
  119. #endif
  120. }
  121. else
  122. {
  123. black_data = black[idx];
  124. }
  125. if (invert) black_data = ~black_data;
  126. }
  127. if (color)
  128. {
  129. // use wb, h of bitmap for index!
  130. int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
  131. if (pgm)
  132. {
  133. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  134. color_data = pgm_read_byte(&color[idx]);
  135. #else
  136. color_data = color[idx];
  137. #endif
  138. }
  139. else
  140. {
  141. color_data = color[idx];
  142. }
  143. if (invert) color_data = ~color_data;
  144. }
  145. _send8pixel(~black_data, ~color_data);
  146. }
  147. #if defined(ESP8266)
  148. yield();
  149. #endif
  150. }
  151. _writeCommand(0x92); // partial out
  152. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  153. }
  154. void GxEPD2_583c::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)
  155. {
  156. if (data1)
  157. {
  158. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  159. int16_t wb = (w + 1) / 2; // width bytes, bitmaps are padded
  160. x -= x % 2; // byte boundary
  161. w = wb * 2; // byte boundary
  162. int16_t x1 = x < 0 ? 0 : x; // limit
  163. int16_t y1 = y < 0 ? 0 : y; // limit
  164. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  165. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  166. int16_t dx = x1 - x;
  167. int16_t dy = y1 - y;
  168. w1 -= dx;
  169. h1 -= dy;
  170. if ((w1 <= 0) || (h1 <= 0)) return;
  171. _Init_Part();
  172. _writeCommand(0x91); // partial in
  173. _setPartialRamArea(x1, y1, w1, h1);
  174. _writeCommand(0x10);
  175. for (int16_t i = 0; i < h1; i++)
  176. {
  177. for (int16_t j = 0; j < w1 / 2; j++)
  178. {
  179. uint8_t data;
  180. // use wb, h of bitmap for index!
  181. int16_t idx = mirror_y ? j + dx / 2 + ((h - 1 - (i + dy))) * wb : j + dx / 2 + (i + dy) * wb;
  182. if (pgm)
  183. {
  184. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  185. data = pgm_read_byte(&data1[idx]);
  186. #else
  187. data = data1[idx];
  188. #endif
  189. }
  190. else
  191. {
  192. data = data1[idx];
  193. }
  194. if (invert) data = ~data;
  195. _writeData(data);
  196. }
  197. }
  198. _writeCommand(0x92); // partial out
  199. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  200. }
  201. }
  202. void GxEPD2_583c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  203. {
  204. writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
  205. refresh(x, y, w, h);
  206. }
  207. void GxEPD2_583c::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)
  208. {
  209. writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
  210. refresh(x, y, w, h);
  211. }
  212. void GxEPD2_583c::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)
  213. {
  214. writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
  215. refresh(x, y, w, h);
  216. }
  217. void GxEPD2_583c::refresh(bool partial_update_mode)
  218. {
  219. if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
  220. else _Update_Full();
  221. }
  222. void GxEPD2_583c::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
  223. {
  224. x -= x % 8; // byte boundary
  225. w -= x % 8; // byte boundary
  226. int16_t x1 = x < 0 ? 0 : x; // limit
  227. int16_t y1 = y < 0 ? 0 : y; // limit
  228. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  229. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  230. w1 -= x1 - x;
  231. h1 -= y1 - y;
  232. _Init_Part();
  233. _setPartialRamArea(x1, y1, w1, h1);
  234. _Update_Part();
  235. }
  236. void GxEPD2_583c::powerOff()
  237. {
  238. _PowerOff();
  239. }
  240. void GxEPD2_583c::hibernate()
  241. {
  242. _PowerOff();
  243. if (_rst >= 0)
  244. {
  245. // check if it supports this command!
  246. _writeCommand(0x07); // deep sleep
  247. _writeData(0xA5); // check code
  248. _hibernating = true;
  249. }
  250. }
  251. void GxEPD2_583c::_send8pixel(uint8_t black_data, uint8_t color_data)
  252. {
  253. for (uint8_t j = 0; j < 8; j++)
  254. {
  255. uint8_t t = 0x00; // black
  256. if (black_data & 0x80); // keep black
  257. else if (color_data & 0x80) t = 0x04; //color
  258. else t = 0x03; // white
  259. t <<= 4;
  260. black_data <<= 1;
  261. color_data <<= 1;
  262. j++;
  263. if (black_data & 0x80); // keep black
  264. else if (color_data & 0x80) t |= 0x04; //color
  265. else t |= 0x03; // white
  266. black_data <<= 1;
  267. color_data <<= 1;
  268. _writeData(t);
  269. }
  270. }
  271. void GxEPD2_583c::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
  272. {
  273. uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
  274. uint16_t ye = y + h - 1;
  275. x &= 0xFFF8; // byte boundary
  276. xe |= 0x0007; // byte boundary
  277. _writeCommand(0x90); // partial window
  278. _writeData(x / 256);
  279. _writeData(x % 256);
  280. _writeData(xe / 256);
  281. _writeData(xe % 256);
  282. _writeData(y / 256);
  283. _writeData(y % 256);
  284. _writeData(ye / 256);
  285. _writeData(ye % 256);
  286. //_writeData(0x01); // distortion on full right half
  287. _writeData(0x00); // distortion on right half
  288. }
  289. void GxEPD2_583c::_PowerOn()
  290. {
  291. if (!_power_is_on)
  292. {
  293. _writeCommand(0x04);
  294. _waitWhileBusy("_PowerOn", power_on_time);
  295. }
  296. _power_is_on = true;
  297. }
  298. void GxEPD2_583c::_PowerOff()
  299. {
  300. _writeCommand(0x02); // power off
  301. _waitWhileBusy("_PowerOff", power_off_time);
  302. _power_is_on = false;
  303. }
  304. void GxEPD2_583c::_InitDisplay()
  305. {
  306. if (_hibernating && (_rst >= 0))
  307. {
  308. digitalWrite(_rst, LOW);
  309. delay(20);
  310. digitalWrite(_rst, HIGH);
  311. delay(200);
  312. _hibernating = false;
  313. }
  314. _writeCommand(0x01);
  315. _writeData (0x37); //POWER SETTING
  316. _writeData (0x00);
  317. _writeCommand(0X00); //PANNEL SETTING
  318. _writeData(0xCF);
  319. _writeData(0x08);
  320. _writeCommand(0x06); //boost
  321. _writeData (0xc7);
  322. _writeData (0xcc);
  323. _writeData (0x28);
  324. _writeCommand(0x30); //PLL setting
  325. //_writeData (0x3a); //PLL: 0-15��:0x3C, 15+:0x3A
  326. _writeData (0x3c); //PLL: 0-15��:0x3C, 15+:0x3A
  327. _writeCommand(0X41); //TEMPERATURE SETTING
  328. _writeData(0x00);
  329. _writeCommand(0X50); //VCOM AND DATA INTERVAL SETTING
  330. _writeData(0x77);
  331. _writeCommand(0X60); //TCON SETTING
  332. _writeData(0x22);
  333. _writeCommand(0x61); //600*448
  334. _writeData (0x02); //source 600
  335. _writeData (0x58);
  336. _writeData (0x01); //gate 448
  337. _writeData (0xc0);
  338. _writeCommand(0X82); //VCOM VOLTAGE SETTING
  339. _writeData(0x28); //all temperature range
  340. _writeCommand(0xe5); //FLASH MODE
  341. _writeData(0x03);
  342. }
  343. void GxEPD2_583c::_Init_Full()
  344. {
  345. _InitDisplay();
  346. _PowerOn();
  347. }
  348. void GxEPD2_583c::_Init_Part()
  349. {
  350. _InitDisplay();
  351. _PowerOn();
  352. }
  353. void GxEPD2_583c::_Update_Full()
  354. {
  355. _writeCommand(0x12); //display refresh
  356. _waitWhileBusy("_Update_Full", full_refresh_time);
  357. }
  358. void GxEPD2_583c::_Update_Part()
  359. {
  360. _writeCommand(0x12); //display refresh
  361. _waitWhileBusy("_Update_Part", partial_refresh_time);
  362. }