GxEPD2_1248.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  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 Good Display:
  5. // Panel: GDEW1248T3 : http://www.e-paper-display.com/products_detail/productId=414.html
  6. // Controller: IL0326 : http://www.e-paper-display.com/download_detail/downloadsId=768.html
  7. //
  8. // Author: Jean-Marc Zingg
  9. //
  10. // Version: see library.properties
  11. //
  12. // Library: https://github.com/ZinggJM/GxEPD2
  13. #include "GxEPD2_1248.h"
  14. #if defined(ESP32)
  15. // general constructor for use with all parameters on ESP32, e.g. for Waveshare ESP32 driver board mounted on connection board
  16. GxEPD2_1248::GxEPD2_1248(int8_t sck, int8_t miso, int8_t mosi,
  17. int8_t cs_m1, int8_t cs_s1, int8_t cs_m2, int8_t cs_s2,
  18. int8_t dc1, int8_t dc2, int8_t rst1, int8_t rst2,
  19. int8_t busy_m1, int8_t busy_s1, int8_t busy_m2, int8_t busy_s2) :
  20. GxEPD2_EPD(cs_m1, dc1, rst1, busy_m1, LOW, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
  21. _sck(sck), _miso(miso), _mosi(mosi), _dc1(dc1), _dc2(dc2), _rst1(rst1), _rst2(rst2),
  22. _cs_m1(cs_m1), _cs_s1(cs_s1), _cs_m2(cs_m2), _cs_s2(cs_s2),
  23. _busy_m1(busy_m1), _busy_s1(busy_s1), _busy_m2(busy_m2), _busy_s2(busy_s2),
  24. _temperature(20),
  25. M1(648, 492, false, cs_m1, dc1),
  26. S1(656, 492, false, cs_s1, dc1),
  27. M2(656, 492, true, cs_m2, dc2),
  28. S2(648, 492, true, cs_s2, dc2)
  29. {
  30. }
  31. #endif
  32. // general constructor for use with standard SPI pins, default SCK, MISO and MOSI
  33. GxEPD2_1248::GxEPD2_1248(int8_t cs_m1, int8_t cs_s1, int8_t cs_m2, int8_t cs_s2,
  34. int8_t dc1, int8_t dc2, int8_t rst1, int8_t rst2,
  35. int8_t busy_m1, int8_t busy_s1, int8_t busy_m2, int8_t busy_s2) :
  36. GxEPD2_EPD(cs_m1, dc1, rst1, busy_m1, LOW, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
  37. _sck(SCK), _miso(MISO), _mosi(MOSI), _dc1(dc1), _dc2(dc2), _rst1(rst1), _rst2(rst2),
  38. _cs_m1(cs_m1), _cs_s1(cs_s1), _cs_m2(cs_m2), _cs_s2(cs_s2),
  39. _busy_m1(busy_m1), _busy_s1(busy_s1), _busy_m2(busy_m2), _busy_s2(busy_s2),
  40. _temperature(20),
  41. M1(648, 492, false, cs_m1, dc1),
  42. S1(656, 492, false, cs_s1, dc1),
  43. M2(656, 492, true, cs_m2, dc2),
  44. S2(648, 492, true, cs_s2, dc2)
  45. {
  46. }
  47. // constructor with minimal parameter set, standard SPI, dc1 and dc2, rst1 and rst2 to one pin, one busy used (can be -1)
  48. GxEPD2_1248::GxEPD2_1248(int8_t cs_m1, int8_t cs_s1, int8_t cs_m2, int8_t cs_s2, int8_t dc, int8_t rst, int8_t busy) :
  49. GxEPD2_EPD(23, 25, 33, 32, LOW, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
  50. _sck(SCK), _miso(MISO), _mosi(MOSI), _dc1(dc), _dc2(dc), _rst1(rst), _rst2(rst),
  51. _cs_m1(cs_m1), _cs_s1(cs_s1), _cs_m2(cs_m2), _cs_s2(cs_s2),
  52. _busy_m1(busy), _busy_s1(busy), _busy_m2(busy), _busy_s2(busy),
  53. _temperature(20),
  54. M1(648, 492, false, cs_m1, dc),
  55. S1(656, 492, false, cs_s1, dc),
  56. M2(656, 492, true, cs_m2, dc),
  57. S2(648, 492, true, cs_s2, dc)
  58. {
  59. }
  60. void GxEPD2_1248::init(uint32_t serial_diag_bitrate)
  61. {
  62. init(serial_diag_bitrate, true, 20, false);
  63. }
  64. void GxEPD2_1248::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode)
  65. {
  66. _initial_write = initial;
  67. _initial_refresh = initial;
  68. _using_partial_mode = false;
  69. if (serial_diag_bitrate > 0)
  70. {
  71. Serial.begin(serial_diag_bitrate);
  72. _diag_enabled = true;
  73. Serial.println(); Serial.println("GxEPD2_1248::init()");
  74. }
  75. pinMode(_cs_m1, OUTPUT);
  76. pinMode(_cs_s1, OUTPUT);
  77. pinMode(_cs_m2, OUTPUT);
  78. pinMode(_cs_s2, OUTPUT);
  79. pinMode(_dc1, OUTPUT);
  80. pinMode(_dc2, OUTPUT);
  81. pinMode(_rst1, OUTPUT);
  82. pinMode(_rst2, OUTPUT);
  83. pinMode(_busy_m1, INPUT);
  84. pinMode(_busy_s1, INPUT);
  85. pinMode(_busy_m2, INPUT);
  86. pinMode(_busy_s2, INPUT);
  87. digitalWrite(_cs_m1, HIGH);
  88. digitalWrite(_cs_s1, HIGH);
  89. digitalWrite(_cs_m2, HIGH);
  90. digitalWrite(_cs_s2, HIGH);
  91. _initSPI();
  92. _reset();
  93. // only relevant for full refresh, comment out if 20 is ok
  94. _getMasterTemperature();
  95. }
  96. void GxEPD2_1248::clearScreen(uint8_t value)
  97. {
  98. writeScreenBuffer(value);
  99. refresh(true);
  100. writeScreenBufferAgain(value);
  101. }
  102. void GxEPD2_1248::writeScreenBuffer(uint8_t value)
  103. {
  104. if (!_using_partial_mode) _Init_Part();
  105. if (_initial_write)
  106. {
  107. M1.writeScreenBuffer(0x10, value);
  108. S1.writeScreenBuffer(0x10, value);
  109. M2.writeScreenBuffer(0x10, value);
  110. S2.writeScreenBuffer(0x10, value);
  111. }
  112. M1.writeScreenBuffer(0x13, value);
  113. S1.writeScreenBuffer(0x13, value);
  114. M2.writeScreenBuffer(0x13, value);
  115. S2.writeScreenBuffer(0x13, value);
  116. _initial_write = false; // initial full screen buffer clean done
  117. }
  118. void GxEPD2_1248::writeScreenBufferAgain(uint8_t value)
  119. {
  120. if (!_using_partial_mode) _Init_Part();
  121. M1.writeScreenBuffer(0x10, value);
  122. S1.writeScreenBuffer(0x10, value);
  123. M2.writeScreenBuffer(0x10, value);
  124. S2.writeScreenBuffer(0x10, value);
  125. }
  126. void GxEPD2_1248::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  127. {
  128. if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
  129. if (!_using_partial_mode) _Init_Part();
  130. S2.writeImagePart(0x13, bitmap, 0, 0, w, h, x, y, w, h, invert, mirror_y, pgm);
  131. M2.writeImagePart(0x13, bitmap, 0, 0, w, h, x - S2.WIDTH, y, w, h, invert, mirror_y, pgm);
  132. M1.writeImagePart(0x13, bitmap, 0, 0, w, h, x, y - S2.HEIGHT, w, h, invert, mirror_y, pgm);
  133. S1.writeImagePart(0x13, bitmap, 0, 0, w, h, x - M1.WIDTH, y - M2.HEIGHT, w, h, invert, mirror_y, pgm);
  134. }
  135. void GxEPD2_1248::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  136. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  137. {
  138. if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
  139. if (!_using_partial_mode) _Init_Part();
  140. S2.writeImagePart(0x13, bitmap, x_part, y_part, w, h, x, y, w, h, invert, mirror_y, pgm);
  141. M2.writeImagePart(0x13, bitmap, x_part, y_part, w, h, x - S2.WIDTH, y, w, h, invert, mirror_y, pgm);
  142. M1.writeImagePart(0x13, bitmap, x_part, y_part, w, h, x, y - S2.HEIGHT, w, h, invert, mirror_y, pgm);
  143. S1.writeImagePart(0x13, bitmap, x_part, y_part, w, h, x - M1.WIDTH, y - M2.HEIGHT, w, h, invert, mirror_y, pgm);
  144. }
  145. void GxEPD2_1248::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  146. {
  147. if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
  148. if (!_using_partial_mode) _Init_Part();
  149. S2.writeImagePart(0x10, bitmap, 0, 0, w, h, x, y, w, h, invert, mirror_y, pgm);
  150. M2.writeImagePart(0x10, bitmap, 0, 0, w, h, x - S2.WIDTH, y, w, h, invert, mirror_y, pgm);
  151. M1.writeImagePart(0x10, bitmap, 0, 0, w, h, x, y - S2.HEIGHT, w, h, invert, mirror_y, pgm);
  152. S1.writeImagePart(0x10, bitmap, 0, 0, w, h, x - M1.WIDTH, y - M2.HEIGHT, w, h, invert, mirror_y, pgm);
  153. }
  154. void GxEPD2_1248::writeImagePartAgain(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  155. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  156. {
  157. if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
  158. if (!_using_partial_mode) _Init_Part();
  159. S2.writeImagePart(0x10, bitmap, x_part, y_part, w, h, x, y, w, h, invert, mirror_y, pgm);
  160. M2.writeImagePart(0x10, bitmap, x_part, y_part, w, h, x - S2.WIDTH, y, w, h, invert, mirror_y, pgm);
  161. M1.writeImagePart(0x10, bitmap, x_part, y_part, w, h, x, y - S2.HEIGHT, w, h, invert, mirror_y, pgm);
  162. S1.writeImagePart(0x10, bitmap, x_part, y_part, w, h, x - M1.WIDTH, y - M2.HEIGHT, w, h, invert, mirror_y, pgm);
  163. }
  164. void GxEPD2_1248::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)
  165. {
  166. if (black)
  167. {
  168. writeImage(black, x, y, w, h, invert, mirror_y, pgm);
  169. }
  170. }
  171. void GxEPD2_1248::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,
  172. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  173. {
  174. if (black)
  175. {
  176. writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  177. }
  178. }
  179. void GxEPD2_1248::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)
  180. {
  181. if (data1)
  182. {
  183. writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
  184. }
  185. }
  186. void GxEPD2_1248::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  187. {
  188. writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
  189. refresh(x, y, w, h);
  190. writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
  191. }
  192. void GxEPD2_1248::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  193. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  194. {
  195. writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  196. refresh(x, y, w, h);
  197. writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  198. }
  199. void GxEPD2_1248::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)
  200. {
  201. if (black)
  202. {
  203. drawImage(black, x, y, w, h, invert, mirror_y, pgm);
  204. }
  205. }
  206. void GxEPD2_1248::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,
  207. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  208. {
  209. if (black)
  210. {
  211. drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
  212. }
  213. }
  214. void GxEPD2_1248::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)
  215. {
  216. if (data1)
  217. {
  218. drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
  219. }
  220. }
  221. void GxEPD2_1248::refresh(bool partial_update_mode)
  222. {
  223. if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
  224. else
  225. {
  226. if (_using_partial_mode) _Init_Full();
  227. _Update_Full();
  228. _initial_refresh = false; // initial full update done
  229. }
  230. }
  231. void GxEPD2_1248::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
  232. {
  233. if (_initial_refresh) return refresh(false); // initial update needs be full update
  234. if (!_using_partial_mode) _Init_Part();
  235. _Update_Part();
  236. }
  237. void GxEPD2_1248::powerOff(void)
  238. {
  239. _PowerOff();
  240. }
  241. void GxEPD2_1248::hibernate()
  242. {
  243. _PowerOff();
  244. if (_rst >= 0)
  245. {
  246. _writeCommandAll(0x07); // deep sleep
  247. _writeDataAll(0xA5); // check code
  248. _hibernating = true;
  249. }
  250. }
  251. void GxEPD2_1248::_reset(void)
  252. {
  253. digitalWrite(_rst1, LOW);
  254. digitalWrite(_rst2, LOW);
  255. delay(200);
  256. digitalWrite(_rst1, HIGH);
  257. digitalWrite(_rst2, HIGH);
  258. delay(200);
  259. _hibernating = false;
  260. }
  261. void GxEPD2_1248::_initSPI()
  262. {
  263. #if defined(ESP32)
  264. if ((SCK != _sck) || (MISO != _miso) || (MOSI != _mosi))
  265. {
  266. SPI.end();
  267. SPI.begin(_sck, _miso, _mosi, _cs_m1);
  268. }
  269. else SPI.begin();
  270. #else
  271. SPI.begin();
  272. #endif
  273. }
  274. void GxEPD2_1248::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
  275. {
  276. uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
  277. uint16_t ye = y + h - 1;
  278. x &= 0xFFF8; // byte boundary
  279. _writeCommand(0x90); // partial window
  280. _writeData(x / 256);
  281. _writeData(x % 256);
  282. _writeData(xe / 256);
  283. _writeData(xe % 256);
  284. _writeData(y / 256);
  285. _writeData(y % 256);
  286. _writeData(ye / 256);
  287. _writeData(ye % 256);
  288. _writeData(0x01);
  289. }
  290. void GxEPD2_1248::_PowerOn()
  291. {
  292. if (!_power_is_on)
  293. {
  294. _writeCommandMaster(0x04);
  295. _waitWhileAnyBusy("_PowerOn", power_on_time);
  296. }
  297. _power_is_on = true;
  298. }
  299. void GxEPD2_1248::_PowerOff()
  300. {
  301. if (_power_is_on)
  302. {
  303. _writeCommandMaster(0x02); // power off
  304. _waitWhileAnyBusy("_PowerOff", power_on_time);
  305. }
  306. _power_is_on = false;
  307. _using_partial_mode = false;
  308. }
  309. void GxEPD2_1248::_InitDisplay()
  310. {
  311. if (_hibernating) _reset();
  312. //panel setting
  313. M1.writeCommand(0x00);
  314. M1.writeData(0x1f); //KW-3f KWR-2F BWROTP 0f BWOTP 1f
  315. S1.writeCommand(0x00);
  316. S1.writeData(0x1f);
  317. M2.writeCommand(0x00);
  318. M2.writeData(0x13); // reverse scan
  319. S2.writeCommand(0x00);
  320. S2.writeData(0x13); // reverse scan
  321. // booster soft start
  322. M1.writeCommand(0x06);
  323. M1.writeData(0x17); //A
  324. M1.writeData(0x17); //B
  325. M1.writeData(0x39); //C
  326. M1.writeData(0x17);
  327. M2.writeCommand(0x06);
  328. M2.writeData(0x17);
  329. M2.writeData(0x17);
  330. M2.writeData(0x39);
  331. M2.writeData(0x17);
  332. //resolution setting
  333. M1.writeCommand(0x61);
  334. M1.writeData(0x02);
  335. M1.writeData(0x88); //source 648
  336. M1.writeData(0x01); //gate 492
  337. M1.writeData(0xEC);
  338. S1.writeCommand(0x61);
  339. S1.writeData(0x02);
  340. S1.writeData(0x90); //source 656
  341. S1.writeData(0x01); //gate 492
  342. S1.writeData(0xEC);
  343. M2.writeCommand(0x61);
  344. M2.writeData(0x02);
  345. M2.writeData(0x90); //source 656
  346. M2.writeData(0x01); //gate 492
  347. M2.writeData(0xEC);
  348. S2.writeCommand(0x61);
  349. S2.writeData(0x02);
  350. S2.writeData(0x88); //source 648
  351. S2.writeData(0x01); //gate 492
  352. S2.writeData(0xEC);
  353. _writeCommandAll(0x15); //DUSPI
  354. _writeDataAll(0x20); // normal (single DIN) SPI
  355. _writeCommandAll(0x50); //Vcom and data interval setting
  356. _writeDataAll(0x21); //Border KW
  357. //_writeDataAll(0x29); // LUTKW, N2OCP: copy new to old DOES NOT WORK
  358. _writeDataAll(0x07);
  359. _writeCommandAll(0x60); //TCON
  360. _writeDataAll(0x22);
  361. _writeCommandAll(0xE3);
  362. _writeDataAll(0x00);
  363. _writeCommandAll(0xe0); //Cascade setting
  364. _writeDataAll(0x03);
  365. _writeCommandAll(0xe5); //Force temperature
  366. _writeDataAll(_temperature);
  367. }
  368. // experimental partial screen update LUTs with balanced charge
  369. // LUTs are filled with zeroes
  370. //#define T1 35 // charge balance pre-phase
  371. //#define T2 0 // optional extension
  372. //#define T3 35 // color change phase (b/w)
  373. //#define T4 0 // optional extension for one color
  374. //#define T1 20 // charge balance pre-phase
  375. //#define T2 10 // optional extension
  376. //#define T3 20 // color change phase (b/w)
  377. //#define T4 10 // optional extension for one color
  378. #define T1 25 // charge balance pre-phase
  379. #define T2 10 // optional extension
  380. #define T3 25 // color change phase (b/w)
  381. #define T4 10 // optional extension for one color
  382. const unsigned char GxEPD2_1248::lut_20_LUTC_partial[] PROGMEM =
  383. {
  384. 0x00, T1, T2, T3, T4, 1, // 00 00 00 00
  385. };
  386. const unsigned char GxEPD2_1248::lut_21_LUTWW_partial[] PROGMEM =
  387. { // 10 w
  388. 0x00, T1, T2, T3, T4, 1, // 00 00 00 00
  389. };
  390. const unsigned char GxEPD2_1248::lut_22_LUTKW_partial[] PROGMEM =
  391. { // 10 w
  392. //0x48, T1, T2, T3, T4, 1, // 01 00 10 00
  393. 0x5A, T1, T2, T3, T4, 1, // 01 01 10 10 more white
  394. };
  395. const unsigned char GxEPD2_1248::lut_23_LUTWK_partial[] PROGMEM =
  396. { // 01 b
  397. 0x84, T1, T2, T3, T4, 1, // 10 00 01 00
  398. //0xA5, T1, T2, T3, T4, 1, // 10 10 01 01 more black
  399. };
  400. const unsigned char GxEPD2_1248::lut_24_LUTKK_partial[] PROGMEM =
  401. { // 01 b
  402. 0x00, T1, T2, T3, T4, 1, // 00 00 00 00
  403. };
  404. const unsigned char GxEPD2_1248::lut_25_LUTBD_partial[] PROGMEM =
  405. {
  406. 0x00, T1, T2, T3, T4, 1, // 00 00 00 00
  407. };
  408. void GxEPD2_1248::_Init_Full()
  409. {
  410. _InitDisplay();
  411. // LUT from OTP
  412. M1.writeCommand(0x00);
  413. M1.writeData(0x1f); //KW-3f KWR-2F BWROTP 0f BWOTP 1f
  414. S1.writeCommand(0x00);
  415. S1.writeData(0x1f);
  416. M2.writeCommand(0x00);
  417. M2.writeData(0x13); // reverse scan
  418. S2.writeCommand(0x00);
  419. S2.writeData(0x13); // reverse scan
  420. _PowerOn();
  421. _using_partial_mode = false;
  422. }
  423. void GxEPD2_1248::_Init_Part()
  424. {
  425. _InitDisplay();
  426. // LUT from registers
  427. M1.writeCommand(0x00);
  428. M1.writeData(0x3f); //KW-3f KWR-2F BWROTP 0f BWOTP 1f
  429. S1.writeCommand(0x00);
  430. S1.writeData(0x3f);
  431. M2.writeCommand(0x00);
  432. M2.writeData(0x33);
  433. S2.writeCommand(0x00);
  434. S2.writeData(0x33);
  435. _writeCommandAll(0x82); // vcom_DC setting
  436. _writeDataAll (0x1C);
  437. _writeCommandAll(0x50); // VCOM AND DATA INTERVAL SETTING
  438. _writeDataAll(0x31); //Border KW
  439. _writeDataAll(0x07);
  440. _writeCommandAll(0x20);
  441. _writeDataPGM_All(lut_20_LUTC_partial, sizeof(lut_20_LUTC_partial), 60 - sizeof(lut_20_LUTC_partial));
  442. _writeCommandAll(0x21);
  443. _writeDataPGM_All(lut_21_LUTWW_partial, sizeof(lut_21_LUTWW_partial), 60 - sizeof(lut_21_LUTWW_partial));
  444. _writeCommandAll(0x22);
  445. _writeDataPGM_All(lut_22_LUTKW_partial, sizeof(lut_22_LUTKW_partial), 60 - sizeof(lut_22_LUTKW_partial));
  446. _writeCommandAll(0x23);
  447. _writeDataPGM_All(lut_23_LUTWK_partial, sizeof(lut_23_LUTWK_partial), 60 - sizeof(lut_23_LUTWK_partial));
  448. _writeCommandAll(0x24);
  449. _writeDataPGM_All(lut_24_LUTKK_partial, sizeof(lut_24_LUTKK_partial), 60 - sizeof(lut_24_LUTKK_partial));
  450. _writeCommandAll(0x25);
  451. _writeDataPGM_All(lut_25_LUTBD_partial, sizeof(lut_25_LUTBD_partial), 60 - sizeof(lut_25_LUTBD_partial));
  452. _PowerOn();
  453. _using_partial_mode = true;
  454. }
  455. void GxEPD2_1248::_Update_Full()
  456. {
  457. _writeCommandAll(0x12); //display refresh
  458. _waitWhileAnyBusy("_Update_Full", full_refresh_time);
  459. }
  460. void GxEPD2_1248::_Update_Part()
  461. {
  462. _writeCommandAll(0x12); //display refresh
  463. _waitWhileAnyBusy("_Update_Part", partial_refresh_time);
  464. }
  465. void GxEPD2_1248::_writeCommandMaster(uint8_t c)
  466. {
  467. SPI.beginTransaction(_spi_settings);
  468. digitalWrite(_dc1, LOW);
  469. digitalWrite(_dc2, LOW);
  470. digitalWrite(_cs_m1, LOW);
  471. digitalWrite(_cs_m2, LOW);
  472. SPI.transfer(c);
  473. digitalWrite(_cs_m1, HIGH);
  474. digitalWrite(_cs_m2, HIGH);
  475. digitalWrite(_dc1, HIGH);
  476. digitalWrite(_dc2, HIGH);
  477. SPI.endTransaction();
  478. }
  479. void GxEPD2_1248::_writeDataMaster(uint8_t d)
  480. {
  481. SPI.beginTransaction(_spi_settings);
  482. digitalWrite(_cs_m1, LOW);
  483. digitalWrite(_cs_m2, LOW);
  484. SPI.transfer(d);
  485. digitalWrite(_cs_m1, HIGH);
  486. digitalWrite(_cs_m2, HIGH);
  487. SPI.endTransaction();
  488. }
  489. void GxEPD2_1248::_writeCommandAll(uint8_t c)
  490. {
  491. SPI.beginTransaction(_spi_settings);
  492. digitalWrite(_dc1, LOW);
  493. digitalWrite(_dc2, LOW);
  494. digitalWrite(_cs_m1, LOW);
  495. digitalWrite(_cs_s1, LOW);
  496. digitalWrite(_cs_m2, LOW);
  497. digitalWrite(_cs_s2, LOW);
  498. SPI.transfer(c);
  499. digitalWrite(_cs_m1, HIGH);
  500. digitalWrite(_cs_s1, HIGH);
  501. digitalWrite(_cs_m2, HIGH);
  502. digitalWrite(_cs_s2, HIGH);
  503. digitalWrite(_dc1, HIGH);
  504. digitalWrite(_dc2, HIGH);
  505. SPI.endTransaction();
  506. }
  507. void GxEPD2_1248::_writeDataAll(uint8_t d)
  508. {
  509. SPI.beginTransaction(_spi_settings);
  510. digitalWrite(_cs_m1, LOW);
  511. digitalWrite(_cs_s1, LOW);
  512. digitalWrite(_cs_m2, LOW);
  513. digitalWrite(_cs_s2, LOW);
  514. SPI.transfer(d);
  515. digitalWrite(_cs_m1, HIGH);
  516. digitalWrite(_cs_s1, HIGH);
  517. digitalWrite(_cs_m2, HIGH);
  518. digitalWrite(_cs_s2, HIGH);
  519. SPI.endTransaction();
  520. }
  521. void GxEPD2_1248::_writeDataPGM_All(const uint8_t* data, uint16_t n, int16_t fill_with_zeroes)
  522. {
  523. SPI.beginTransaction(_spi_settings);
  524. digitalWrite(_cs_m1, LOW);
  525. digitalWrite(_cs_s1, LOW);
  526. digitalWrite(_cs_m2, LOW);
  527. digitalWrite(_cs_s2, LOW);
  528. for (uint16_t i = 0; i < n; i++)
  529. {
  530. SPI.transfer(pgm_read_byte(&*data++));
  531. }
  532. while (fill_with_zeroes > 0)
  533. {
  534. SPI.transfer(0x00);
  535. fill_with_zeroes--;
  536. }
  537. digitalWrite(_cs_m1, HIGH);
  538. digitalWrite(_cs_s1, HIGH);
  539. digitalWrite(_cs_m2, HIGH);
  540. digitalWrite(_cs_s2, HIGH);
  541. SPI.endTransaction();
  542. }
  543. void GxEPD2_1248::_waitWhileAnyBusy(const char* comment, uint16_t busy_time)
  544. {
  545. if (_busy_m1 >= 0)
  546. {
  547. delay(1); // add some margin to become active
  548. unsigned long start = micros();
  549. while (1)
  550. {
  551. delay(1); // add some margin to become active
  552. bool nb_m1 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_m1) : true;
  553. bool nb_s1 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_s1) : true;
  554. bool nb_m2 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_m2) : true;
  555. bool nb_s2 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_s2) : true;
  556. if (nb_m1 && nb_s1 && nb_m2 && nb_s2) break;
  557. delay(1);
  558. if (micros() - start > _busy_timeout)
  559. {
  560. Serial.println("Busy Timeout!");
  561. break;
  562. }
  563. }
  564. if (comment)
  565. {
  566. if (_diag_enabled)
  567. {
  568. unsigned long elapsed = micros() - start;
  569. Serial.print(comment);
  570. Serial.print(" : ");
  571. Serial.println(elapsed);
  572. }
  573. }
  574. (void) start;
  575. }
  576. else delay(busy_time);
  577. }
  578. void GxEPD2_1248::_getMasterTemperature()
  579. {
  580. uint8_t value = 0;
  581. M1.writeCommand(0x40);
  582. _waitWhileAnyBusy("getMasterTemperature", 300);
  583. SPI.end();
  584. pinMode(_mosi, INPUT);
  585. delay(100);
  586. digitalWrite(_sck, HIGH);
  587. pinMode(_sck, OUTPUT);
  588. digitalWrite(_cs_m1, LOW);
  589. pinMode(_mosi, INPUT);
  590. for (uint16_t i = 0; i < 8; i++)
  591. {
  592. digitalWrite(_sck, LOW);
  593. value <<= 1;
  594. delayMicroseconds(2);
  595. if (digitalRead(_mosi)) value |= 0x01;
  596. delayMicroseconds(2);
  597. digitalWrite(_sck, HIGH);
  598. delayMicroseconds(2);
  599. }
  600. digitalWrite(_cs_m1, HIGH);
  601. pinMode(_sck, INPUT);
  602. _temperature = value;
  603. _initSPI();
  604. if (_diag_enabled)
  605. {
  606. Serial.print("Master Temperature is "); Serial.println(value);
  607. }
  608. }
  609. void GxEPD2_1248::_readController(uint8_t cmd, uint8_t* data, uint16_t n, int8_t cs, int8_t dc)
  610. {
  611. if (cs < 0) cs = _cs_m1;
  612. if (dc < 0) dc = _dc1;
  613. SPI.beginTransaction(_spi_settings);
  614. digitalWrite(cs, LOW);
  615. digitalWrite(dc, LOW);
  616. SPI.transfer(cmd);
  617. digitalWrite(dc, HIGH);
  618. digitalWrite(cs, HIGH);
  619. SPI.endTransaction();
  620. _waitWhileAnyBusy("_readController", 300);
  621. SPI.end();
  622. pinMode(_mosi, INPUT);
  623. delay(100);
  624. digitalWrite(_sck, HIGH);
  625. pinMode(_sck, OUTPUT);
  626. digitalWrite(cs, LOW);
  627. pinMode(_mosi, INPUT);
  628. for (uint16_t j = 0; j < n; j++)
  629. {
  630. uint8_t value = 0;
  631. for (uint16_t i = 0; i < 8; i++)
  632. {
  633. digitalWrite(_sck, LOW);
  634. value <<= 1;
  635. delayMicroseconds(2);
  636. if (digitalRead(_mosi)) value |= 0x01;
  637. delayMicroseconds(2);
  638. digitalWrite(_sck, HIGH);
  639. delayMicroseconds(2);
  640. }
  641. data[j] = value;
  642. }
  643. digitalWrite(cs, HIGH);
  644. pinMode(_sck, INPUT);
  645. _initSPI();
  646. }
  647. GxEPD2_1248::ScreenPart::ScreenPart(uint16_t width, uint16_t height, bool rev_scan, int8_t cs, int8_t dc) :
  648. WIDTH(width), HEIGHT(height), _rev_scan(rev_scan),
  649. _cs(cs), _dc(dc), _spi_settings(4000000, MSBFIRST, SPI_MODE0)
  650. {
  651. }
  652. void GxEPD2_1248::ScreenPart::writeScreenBuffer(uint8_t command, uint8_t value)
  653. {
  654. writeCommand(command); // set current or previous
  655. for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
  656. {
  657. writeData(value);
  658. }
  659. }
  660. void GxEPD2_1248::ScreenPart::writeImagePart(uint8_t command, const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
  661. int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  662. {
  663. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  664. if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
  665. if ((x_part < 0) || (x_part >= w_bitmap)) return;
  666. if ((y_part < 0) || (y_part >= h_bitmap)) return;
  667. int32_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
  668. x_part -= x_part % 8; // byte boundary
  669. w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
  670. h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
  671. x -= x % 8; // byte boundary
  672. w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
  673. int16_t x1 = x < 0 ? 0 : x; // limit
  674. int16_t y1 = y < 0 ? 0 : y; // limit
  675. int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
  676. int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
  677. int16_t dx = x1 - x;
  678. int16_t dy = y1 - y;
  679. w1 -= dx;
  680. h1 -= dy;
  681. if ((w1 <= 0) || (h1 <= 0)) return;
  682. //Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(", "); Serial.println(h);
  683. //Serial.print("->"); Serial.print(x1); Serial.print(", "); Serial.print(y1); Serial.print(", "); Serial.print(w1); Serial.print(", "); Serial.println(h1);
  684. writeCommand(0x91); // partial in
  685. delay(1);
  686. _setPartialRamArea(x1, y1, w1, h1);
  687. writeCommand(command);
  688. _startTransfer();
  689. for (int16_t i = 0; i < h1; i++)
  690. {
  691. for (int16_t j = 0; j < w1 / 8; j++)
  692. {
  693. uint8_t data;
  694. // use wb_bitmap, h_bitmap of bitmap for index!
  695. int32_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;
  696. if (pgm)
  697. {
  698. #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
  699. data = pgm_read_byte(&bitmap[idx]);
  700. #else
  701. data = bitmap[idx];
  702. #endif
  703. }
  704. else
  705. {
  706. data = bitmap[idx];
  707. }
  708. if (invert) data = ~data;
  709. _transfer(data);
  710. }
  711. }
  712. _endTransfer();
  713. writeCommand(0x92); // partial out
  714. delay(1); // yield() to avoid WDT on ESP8266 and ESP32
  715. }
  716. void GxEPD2_1248::ScreenPart::writeCommand(uint8_t c)
  717. {
  718. SPI.beginTransaction(_spi_settings);
  719. if (_dc >= 0) digitalWrite(_dc, LOW);
  720. if (_cs >= 0) digitalWrite(_cs, LOW);
  721. SPI.transfer(c);
  722. if (_cs >= 0) digitalWrite(_cs, HIGH);
  723. if (_dc >= 0) digitalWrite(_dc, HIGH);
  724. SPI.endTransaction();
  725. }
  726. void GxEPD2_1248::ScreenPart::writeData(uint8_t d)
  727. {
  728. SPI.beginTransaction(_spi_settings);
  729. if (_cs >= 0) digitalWrite(_cs, LOW);
  730. SPI.transfer(d);
  731. if (_cs >= 0) digitalWrite(_cs, HIGH);
  732. SPI.endTransaction();
  733. }
  734. void GxEPD2_1248::ScreenPart::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
  735. {
  736. if (_rev_scan) x = WIDTH - w - x;
  737. uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
  738. uint16_t ye = y + h - 1;
  739. x &= 0xFFF8; // byte boundary
  740. writeCommand(0x90); // partial window
  741. writeData(x / 256);
  742. writeData(x % 256);
  743. writeData(xe / 256);
  744. writeData(xe % 256);
  745. writeData(y / 256);
  746. writeData(y % 256);
  747. writeData(ye / 256);
  748. writeData(ye % 256);
  749. writeData(0x01);
  750. }
  751. void GxEPD2_1248::ScreenPart::_startTransfer()
  752. {
  753. SPI.beginTransaction(_spi_settings);
  754. if (_cs >= 0) digitalWrite(_cs, LOW);
  755. }
  756. void GxEPD2_1248::ScreenPart::_transfer(uint8_t value)
  757. {
  758. SPI.transfer(value);
  759. }
  760. void GxEPD2_1248::ScreenPart::_endTransfer()
  761. {
  762. if (_cs >= 0) digitalWrite(_cs, HIGH);
  763. SPI.endTransaction();
  764. }