您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

779 行
23 KiB

  1. /*
  2. * Author: LoBo (loboris@gmail.com, loboris.github)
  3. *
  4. * Module supporting SPI ePaper displays
  5. *
  6. * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS
  7. * USING DIRECT or DMA SPI TRANSFER MODEs
  8. *
  9. */
  10. #include "spi_master_lobo.h"
  11. #include <errno.h>
  12. #include <stdio.h>
  13. #include <time.h>
  14. #include <string.h>
  15. #include "esp_system.h"
  16. #include "freertos/FreeRTOS.h"
  17. #include "freertos/task.h"
  18. #include "esp_heap_alloc_caps.h"
  19. #include "soc/spi_reg.h"
  20. #include "EPDspi.h"
  21. #define EPD_DEBUG 1
  22. #define EPD2X9 1
  23. #define xDot 128
  24. #define yDot 296
  25. #define DELAYTIME 1500
  26. // ===== Global ======
  27. spi_lobo_device_handle_t disp_spi;
  28. uint8_t *gs_disp_buffer;
  29. uint8_t *disp_buffer;
  30. uint8_t *gs_drawBuff;
  31. uint8_t *drawBuff;
  32. int _width;
  33. int _height;
  34. uint16_t gs_used_shades;
  35. uint8_t _gs;
  36. uint8_t *LUT_part;
  37. uint8_t LUTDefault_fastest[31];
  38. uint8_t LUTDefault_part[31];
  39. uint8_t LUT_gs[31];
  40. uint8_t LUTDefault_full[31];
  41. uint8_t lvl_buf[16];
  42. uint8_t lvl_buf_jpg[16];
  43. // =====
  44. static uint8_t GDOControl[] = {0x01, (yDot-1)%256, (yDot-1)/256, 0x00};
  45. static uint8_t softstart[4] = {0x0c, 0xd7, 0xd6, 0x9d};
  46. static uint8_t VCOMVol[2] = {0x2c, 0xa8}; // VCOM 7c
  47. static uint8_t DummyLine[2] = {0x3a, 0x1a}; // 4 dummy line per gate
  48. static uint8_t Gatetime[2] = {0x3b, 0x08}; // 2us per line
  49. static uint8_t RamDataEntryMode[2] = {0x11, 0x01}; // Ram data entry mode
  50. static uint8_t Border[2] = {0x3c, 0x61}; // Border control ( 0x61: white border; 0x51: black border
  51. /*
  52. There are totally 20 phases for programmable Source waveform of different phase length.
  53. The phase period defined as TP [n] * T FRAME , where TP [n] range from 0 to 15.
  54. TP [n] = 0 indicates phase skipped
  55. Source Voltage Level: VS [n-XY] is constant in each phase
  56. VS [n-XY] indicates the voltage in phase n for transition from GS X to GS Y
  57.  00 – VSS
  58.  01 – VSH
  59.  10 – VSL
  60.  11 – NA
  61. VS [n-XY] and TP[n] are stored in waveform lookup table register [LUT].
  62. VS coding: VS[0-11] VS[0-10] VS[0-01] VS[0-00]
  63. */
  64. // --- VS ---- ---- TP ----
  65. //uint8_t LUTDefault_full[31] = {0x32, 0x02,0x02,0x01,0x11,0x12,0x12,0x22,0x22,0x66,0x69,0x69,0x59,0x58,0x99,0x99,0x88,0x00,0x00,0x00,0x00, 0xF8,0xB4,0x13,0x51,0x35,0x51,0x51,0x19,0x01,0x00};
  66. uint8_t LUTDefault_full[31] = {0x32, 0x11,0x11,0x10,0x02,0x02,0x22,0x22,0x22,0x22,0x22,0x51,0x51,0x55,0x88,0x08,0x08,0x88,0x88,0x00,0x00, 0x34,0x23,0x12,0x21,0x24,0x28,0x22,0x21,0xA1,0x01};
  67. uint8_t LUTDefault_part[31] = {0x32, 0x10,0x18,0x18,0x08,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x13,0x14,0x44,0x12,0x00,0x00,0x00,0x00,0x00,0x00};
  68. uint8_t LUT_gs[31] = {0x32, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  69. uint8_t LUTFastest[31] = {0x32, 0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  70. uint8_t lvl_buf[16] = {32,70,110,150,185,210,220,225,230,235,240,243,248,251,253,255};
  71. uint8_t lvl_buf_jpg[16] = {4,8,12,16,22,30,40,60,80,110,140,180,220,240,250,255};
  72. uint8_t *LUT_part = LUTDefault_part;
  73. spi_lobo_device_handle_t disp_spi = NULL;
  74. uint8_t *gs_disp_buffer = NULL;
  75. uint8_t *disp_buffer = NULL;
  76. uint8_t *drawBuff = NULL;
  77. uint8_t *gs_drawBuff = NULL;
  78. int _width = EPD_DISPLAY_WIDTH;
  79. int _height = EPD_DISPLAY_HEIGHT;
  80. uint8_t _gs = 0;
  81. uint16_t gs_used_shades = 0;
  82. //-----------------------------------------------------------
  83. static void IRAM_ATTR _dma_send(uint8_t *data, uint32_t size)
  84. {
  85. //Fill DMA descriptors
  86. spi_lobo_dmaworkaround_transfer_active(disp_spi->host->dma_chan); //mark channel as active
  87. spi_lobo_setup_dma_desc_links(disp_spi->host->dmadesc_tx, size, data, false);
  88. disp_spi->host->hw->user.usr_mosi_highpart=0;
  89. disp_spi->host->hw->dma_out_link.addr=(int)(&disp_spi->host->dmadesc_tx[0]) & 0xFFFFF;
  90. disp_spi->host->hw->dma_out_link.start=1;
  91. disp_spi->host->hw->user.usr_mosi_highpart=0;
  92. disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = (size * 8) - 1;
  93. // Start transfer
  94. disp_spi->host->hw->cmd.usr = 1;
  95. // Wait for SPI bus ready
  96. while (disp_spi->host->hw->cmd.usr);
  97. //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
  98. if (disp_spi->host->dma_chan) spi_lobo_dmaworkaround_idle(disp_spi->host->dma_chan);
  99. // Reset DMA
  100. disp_spi->host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
  101. disp_spi->host->hw->dma_out_link.start=0;
  102. disp_spi->host->hw->dma_in_link.start=0;
  103. disp_spi->host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
  104. disp_spi->host->hw->dma_conf.out_data_burst_en=1;
  105. }
  106. //--------------------------------------------------------------------------
  107. static void IRAM_ATTR _direct_send(uint8_t *data, uint32_t len, uint8_t rep)
  108. {
  109. uint32_t cidx = 0; // buffer index
  110. uint32_t wd = 0;
  111. int idx = 0;
  112. int bits = 0;
  113. int wbits = 0;
  114. taskDISABLE_INTERRUPTS();
  115. while (len) {
  116. wd |= (uint32_t)data[idx] << wbits;
  117. wbits += 8;
  118. if (wbits == 32) {
  119. bits += wbits;
  120. wbits = 0;
  121. disp_spi->host->hw->data_buf[idx++] = wd;
  122. wd = 0;
  123. }
  124. len--; // Decrement data counter
  125. if (rep == 0) cidx++; // if not repeating data, increment buffer index
  126. }
  127. if (bits) {
  128. while (disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready
  129. // Load send buffer
  130. disp_spi->host->hw->user.usr_mosi_highpart = 0;
  131. disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1;
  132. disp_spi->host->hw->user.usr_mosi = 1;
  133. disp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0;
  134. disp_spi->host->hw->user.usr_miso = 0;
  135. disp_spi->host->hw->cmd.usr = 1; // Start transfer
  136. }
  137. // Wait for SPI bus ready
  138. while (disp_spi->host->hw->cmd.usr);
  139. taskENABLE_INTERRUPTS();
  140. }
  141. // ================================================================
  142. // === Main function to send data to display ======================
  143. // If rep==true: repeat sending data to display 'len' times
  144. // If rep==false: send 'len' data bytes from buffer to display
  145. // ** Device must already be selected and address window set **
  146. // ================================================================
  147. //---------------------------------------------------------------------------
  148. static void IRAM_ATTR SPI_send_data(uint8_t *data, uint32_t len, uint8_t rep)
  149. {
  150. if (len == 0) return;
  151. if ((len*8) <= 512) _direct_send(data, len, rep);
  152. else if (rep == 0) _dma_send(data, len);
  153. else {
  154. // ==== Repeat data, more than 512 bits total ====
  155. uint8_t *transbuf = pvPortMallocCaps(len, MALLOC_CAP_DMA);
  156. if (transbuf == NULL) return;
  157. memset(transbuf, data[0], len);
  158. _dma_send(transbuf, len);
  159. free(transbuf);
  160. }
  161. }
  162. // Send one byte to display
  163. //-------------------------------------
  164. void IRAM_ATTR SPI_Write(uint8_t value)
  165. {
  166. disp_spi->host->hw->data_buf[0] = (uint32_t)value;
  167. // Load send buffer
  168. disp_spi->host->hw->user.usr_mosi_highpart = 0;
  169. disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7;
  170. disp_spi->host->hw->user.usr_mosi = 1;
  171. disp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0;
  172. disp_spi->host->hw->user.usr_miso = 0;
  173. // Start transfer
  174. disp_spi->host->hw->cmd.usr = 1;
  175. // Wait for SPI bus ready
  176. while (disp_spi->host->hw->cmd.usr);
  177. }
  178. // Check display busy line and wait while busy
  179. //-----------------------
  180. static uint8_t ReadBusy()
  181. {
  182. for (int i=0; i<400; i++){
  183. if (isEPD_BUSY == EPD_BUSY_LEVEL) return 1;
  184. vTaskDelay(10 / portTICK_RATE_MS);
  185. }
  186. return 0;
  187. }
  188. //-----------------------
  189. static uint8_t WaitBusy()
  190. {
  191. if (isEPD_BUSY != EPD_BUSY_LEVEL) return 1;
  192. vTaskDelay(10 / portTICK_RATE_MS);
  193. if (isEPD_BUSY != EPD_BUSY_LEVEL) return 1;
  194. return 0;
  195. }
  196. // Write one command without parameters
  197. //---------------------------------------
  198. static void EPD_WriteCMD(uint8_t command)
  199. {
  200. spi_lobo_device_select(disp_spi, 0);
  201. EPD_DC_0; // command write
  202. SPI_Write(command);
  203. }
  204. // Write command with one paramet
  205. //---------------------------------------
  206. static void EPD_WriteCMD_p1(uint8_t command,uint8_t para)
  207. {
  208. spi_lobo_device_select(disp_spi, 0);
  209. //ReadBusy();
  210. EPD_DC_0; // command write
  211. SPI_Write(command);
  212. EPD_DC_1; // data write
  213. SPI_Write(para);
  214. spi_lobo_device_deselect(disp_spi);
  215. }
  216. //----------------
  217. void EPD_PowerOn()
  218. {
  219. EPD_WriteCMD_p1(0x22,0xc0);
  220. EPD_WriteCMD(0x20);
  221. //EPD_WriteCMD(0xff);
  222. spi_lobo_device_deselect(disp_spi);
  223. #if EPD_DEBUG
  224. if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
  225. if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
  226. #else
  227. WaitBusy();
  228. ReadBusy();
  229. #endif
  230. }
  231. //-----------------
  232. void EPD_PowerOff()
  233. {
  234. EPD_WriteCMD_p1(0x22,0x03);
  235. EPD_WriteCMD(0x20);
  236. //EPD_WriteCMD(0xff);
  237. spi_lobo_device_deselect(disp_spi);
  238. #if EPD_DEBUG
  239. if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
  240. if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
  241. #else
  242. WaitBusy();
  243. ReadBusy();
  244. #endif
  245. #ifdef POWER_Pin
  246. gpio_set_level(DC_Pin, 0);
  247. gpio_set_level(MOSI_Pin, 0);
  248. gpio_set_level(SCK_Pin, 0);
  249. gpio_set_level(RST_Pin, 0);
  250. gpio_set_level(CS_Pin, 0);
  251. gpio_set_level(POWER_Pin, 0);
  252. #endif
  253. }
  254. // Send command with multiple parameters
  255. //----------------------------------------------------
  256. static void EPD_Write(uint8_t *value, uint8_t datalen)
  257. {
  258. uint8_t i = 0;
  259. uint8_t *ptemp;
  260. ptemp = value;
  261. spi_lobo_device_select(disp_spi, 0);
  262. //ReadBusy();
  263. EPD_DC_0; // When DC is 0, write command
  264. SPI_Write(*ptemp); //The first byte is written with the command value
  265. ptemp++;
  266. EPD_DC_1; // When DC is 1, write data
  267. for(i= 0;i<datalen-1;i++){ // sub the data
  268. SPI_Write(*ptemp);
  269. ptemp++;
  270. }
  271. spi_lobo_device_deselect(disp_spi);
  272. }
  273. // Send data buffer to display
  274. //----------------------------------------------------------------------------
  275. static void EPD_WriteDispRam(uint8_t XSize, uint16_t YSize, uint8_t *Dispbuff)
  276. {
  277. if (XSize%8 != 0) XSize = XSize+(8-XSize%8);
  278. XSize = XSize/8;
  279. spi_lobo_device_select(disp_spi, 0);
  280. //ReadBusy();
  281. EPD_DC_0; //command write
  282. SPI_Write(0x24);
  283. EPD_DC_1; //data write
  284. SPI_send_data(Dispbuff, XSize*YSize, 0);
  285. spi_lobo_device_deselect(disp_spi);
  286. }
  287. // Fill the display with value
  288. //-------------------------------------------------------------------------------
  289. static void EPD_WriteDispRamMono(uint8_t XSize, uint16_t YSize, uint8_t dispdata)
  290. {
  291. if (XSize%8 != 0) XSize = XSize+(8-XSize%8);
  292. XSize = XSize/8;
  293. spi_lobo_device_select(disp_spi, 0);
  294. //ReadBusy();
  295. EPD_DC_0; // command write
  296. SPI_Write(0x24);
  297. EPD_DC_1; // data write
  298. SPI_send_data(&dispdata, XSize*YSize, 1);
  299. spi_lobo_device_deselect(disp_spi);
  300. }
  301. /*
  302. === Set RAM X - Address Start / End Position (44h) ===
  303. Specify the start/end positions of the window address in the X direction by 8 times address unit.
  304. Data is written to the RAM within the area determined by the addresses specified by XSA [4:0] and XEA [4:0].
  305. These addresses must be set before the RAM write. It allows on XEA [4:0] ≤ XSA [4:0].
  306. The settings follow the condition on 00h ≤ XSA [4:0], XEA [4:0] ≤ 1Dh.
  307. The windows is followed by the control setting of Data Entry Setting (R11h)
  308. === Set RAM Y - Address Start / End Position (45h) ===
  309. Specify the start/end positions of the window address in the Y direction by an address unit.
  310. Data is written to the RAM within the area determined by the addresses specified by YSA [8:0] and YEA [8:0].
  311. These addresses must be set before the RAM write.
  312. It allows YEA [8:0] ≤ YSA [8:0].
  313. The settings follow the condition on 00h ≤ YSA [8:0], YEA [8:0] ≤ 13Fh.
  314. The windows is followed by the control setting of Data Entry Setting (R11h)
  315. */
  316. //--------------------------------------------------------------------------------------
  317. static void EPD_SetRamArea(uint8_t Xstart, uint8_t Xend, uint16_t Ystart, uint16_t Yend)
  318. {
  319. uint8_t RamAreaX[3]; // X start and end
  320. uint8_t RamAreaY[5]; // Y start and end
  321. RamAreaX[0] = 0x44; // command
  322. RamAreaX[1] = Xstart;
  323. RamAreaX[2] = Xend;
  324. RamAreaY[0] = 0x45; // command
  325. RamAreaY[1] = Ystart & 0xFF;
  326. RamAreaY[2] = Ystart >> 8;
  327. RamAreaY[3] = Yend & 0xFF;
  328. RamAreaY[4] = Yend >> 8;
  329. EPD_Write(RamAreaX, sizeof(RamAreaX));
  330. EPD_Write(RamAreaY, sizeof(RamAreaY));
  331. }
  332. //Set RAM X and Y address counter
  333. /*
  334. === Set RAM Address Counter (4Eh-4Fh) ===
  335. adrX[4:0]: Make initial settings for the RAM X address in the address counter (AC).
  336. adrY[8:0]: Make initial settings for the RAM Y address in the address counter (AC).
  337. After RAM data is written, the address counter is automatically updated according to the settings with AM, ID
  338. bits and setting for a new RAM address is not required in the address counter.
  339. Therefore, data is written consecutively without setting an address.
  340. The address counter is not automatically updated when data is read out from the RAM.
  341. RAM address setting cannot be made during the standby mode.
  342. The address setting should be made within the area designated with window addresses which is controlled
  343. by the Data Entry Setting (R11h) {AM, ID[1:0]} ; RAM Address XStart / XEnd Position (R44h) and RAM Address Ystart /Yend Position (R45h).
  344. Otherwise undesirable image will be displayed on the Panel.
  345. */
  346. //----------------------------------------------------------
  347. static void EPD_SetRamPointer(uint8_t addrX, uint16_t addrY)
  348. {
  349. uint8_t RamPointerX[2]; // default (0,0)
  350. uint8_t RamPointerY[3];
  351. //Set RAM X address counter
  352. RamPointerX[0] = 0x4e;
  353. RamPointerX[1] = addrX;
  354. //Set RAM Y address counter
  355. RamPointerY[0] = 0x4f;
  356. RamPointerY[1] = addrY & 0xFF;
  357. RamPointerY[2] = addrY >> 8;
  358. EPD_Write(RamPointerX, sizeof(RamPointerX));
  359. EPD_Write(RamPointerY, sizeof(RamPointerY));
  360. }
  361. //Set RAM X and Y address Start / End position
  362. //Set RAM X and Y address counter
  363. //----------------------------------------------------------------------------------------------
  364. static void part_display(uint8_t RAM_XST, uint8_t RAM_XEND ,uint16_t RAM_YST, uint16_t RAM_YEND)
  365. {
  366. EPD_SetRamArea(RAM_XST, RAM_XEND, RAM_YST, RAM_YEND);
  367. EPD_SetRamPointer (RAM_XST, RAM_YST);
  368. }
  369. //Initialize the display
  370. //--------------------
  371. static void EPD_Init()
  372. {
  373. #ifdef POWER_Pin
  374. gpio_set_level(POWER_Pin, 1);
  375. vTaskDelay(100 / portTICK_RATE_MS);
  376. #else
  377. vTaskDelay(10 / portTICK_RATE_MS);
  378. #endif
  379. // reset
  380. EPD_RST_0;
  381. vTaskDelay(10 / portTICK_RATE_MS);
  382. #if EPD_DEBUG
  383. uint32_t t1 = clock();
  384. #endif
  385. EPD_RST_1;
  386. for (int n=0; n<50; n++) {
  387. vTaskDelay(10 / portTICK_RATE_MS);
  388. if (isEPD_BUSY == EPD_BUSY_LEVEL) break;
  389. }
  390. SPI_Write(0x12); // software reset
  391. vTaskDelay(10 / portTICK_RATE_MS);
  392. ReadBusy();
  393. // set registers
  394. EPD_Write(GDOControl, sizeof(GDOControl)); // Panel configuration, Gate selection
  395. EPD_Write(softstart, sizeof(softstart)); // X decrease, Y decrease
  396. EPD_Write(VCOMVol, sizeof(VCOMVol)); // VCOM setting
  397. EPD_Write(DummyLine, sizeof(DummyLine)); // dummy line per gate
  398. EPD_Write(Gatetime, sizeof(Gatetime)); // Gate time setting
  399. EPD_Write(Border, sizeof(Border));
  400. EPD_Write(RamDataEntryMode, sizeof(RamDataEntryMode)); // X increase, Y decrease
  401. EPD_SetRamArea(0x00, (xDot-1)/8, yDot-1, 0);
  402. EPD_SetRamPointer(0x00, yDot-1);
  403. #if EPD_DEBUG
  404. t1 = clock() - t1;
  405. printf("[EPD] Init: %u ms\r\n", t1);
  406. #endif
  407. }
  408. //------------------------------
  409. static void EPD_UpdateFull(void)
  410. {
  411. /*
  412. + Enable Clock Signal,
  413. + Then Enable CP
  414. - Then Load Temperature value
  415. - Then Load LUT
  416. - Then INITIAL DISPLAY
  417. + Then PATTERN DISPLAY
  418. + Then Disable CP
  419. + Then Disable OSC
  420. */
  421. EPD_WriteCMD_p1(0x22,0xC7);
  422. EPD_WriteCMD(0x20);
  423. //EPD_WriteCMD(0xff);
  424. spi_lobo_device_deselect(disp_spi);
  425. #if EPD_DEBUG
  426. if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
  427. if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
  428. #else
  429. WaitBusy();
  430. ReadBusy();
  431. #endif
  432. }
  433. //-------------------------------
  434. static void EPD_Update_Part(void)
  435. {
  436. /*
  437. - Enable Clock Signal,
  438. - Then Enable CP
  439. - Then Load Temperature value
  440. - Then Load LUT
  441. - Then INITIAL DISPLAY
  442. + Then PATTERN DISPLAY
  443. - Then Disable CP
  444. - Then Disable OSC
  445. */
  446. EPD_WriteCMD_p1(0x22,0x04);
  447. EPD_WriteCMD(0x20);
  448. //EPD_WriteCMD(0xff);
  449. spi_lobo_device_deselect(disp_spi);
  450. #if EPD_DEBUG
  451. if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
  452. if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
  453. #else
  454. WaitBusy();
  455. ReadBusy();
  456. #endif
  457. }
  458. /*******************************************************************************
  459. Full screen initialization
  460. ********************************************************************************/
  461. static void EPD_init_Full(void)
  462. {
  463. EPD_Init(); // Reset and set register
  464. EPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));
  465. EPD_PowerOn();
  466. }
  467. /*******************************************************************************
  468. Part screen initialization
  469. ********************************************************************************/
  470. static void EPD_init_Part(void)
  471. {
  472. EPD_Init(); // display
  473. EPD_Write((uint8_t *)LUT_part, 31);
  474. EPD_PowerOn();
  475. }
  476. /********************************************************************************
  477. parameter:
  478. Label :
  479. =1 Displays the contents of the DisBuffer
  480. =0 Displays the contents of the first byte in DisBuffer,
  481. ********************************************************************************/
  482. static void EPD_Dis_Full(uint8_t *DisBuffer,uint8_t type)
  483. {
  484. EPD_SetRamPointer(0x00, yDot-1); // set ram pointer
  485. if (type == 0){
  486. // Fill screen with white
  487. EPD_WriteDispRamMono(xDot, yDot, 0xff);
  488. }
  489. else {
  490. // Fill screen from buffer
  491. EPD_WriteDispRam(xDot, yDot, (uint8_t *)DisBuffer);
  492. }
  493. EPD_UpdateFull();
  494. }
  495. /********************************************************************************
  496. WARNING: X is smaller screen dimension (0~127) !
  497. Y is larger screen dimension (0~295) !
  498. parameter:
  499. xStart : X direction Start coordinate
  500. xEnd : X direction end coordinate
  501. yStart : Y direction Start coordinate
  502. yEnd : Y direction end coordinate
  503. DisBuffer : Display content
  504. type :
  505. =1 Displays the contents of the DisBuffer
  506. =0 Displays the contents of the first byte in DisBuffer,
  507. ********************************************************************************/
  508. static void EPD_Dis_Part(uint8_t xStart, uint8_t xEnd, uint16_t yStart, uint16_t yEnd, uint8_t *DisBuffer, uint8_t type)
  509. {
  510. if (type == 0) {
  511. // Repeated color
  512. part_display(xStart/8, xEnd/8, yEnd, yStart);
  513. EPD_WriteDispRamMono(xEnd-xStart+1, yEnd-yStart+1, DisBuffer[0]);
  514. EPD_Update_Part();
  515. part_display(xStart/8, xEnd/8, yEnd, yStart);
  516. EPD_WriteDispRamMono(xEnd-xStart+1, yEnd-yStart+1, DisBuffer[0]);
  517. }
  518. else {
  519. // From buffer
  520. part_display(xStart/8, xEnd/8, yEnd, yStart);
  521. EPD_WriteDispRam(xEnd-xStart+1, yEnd-yStart+1,DisBuffer);
  522. EPD_Update_Part();
  523. part_display(xStart/8, xEnd/8, yEnd, yStart);
  524. EPD_WriteDispRam(xEnd-xStart+1, yEnd-yStart+1,DisBuffer);
  525. }
  526. }
  527. //======================================================================================================================================
  528. // Clear full screen
  529. //=========================
  530. void EPD_DisplayClearFull()
  531. {
  532. uint8_t m;
  533. EPD_init_Full();
  534. #if EPD_DEBUG
  535. uint32_t t1 = clock();
  536. #endif
  537. m = 0x00;
  538. EPD_Dis_Full(&m, 0); //all black
  539. #if EPD_DEBUG
  540. t1 = clock() - t1;
  541. printf("[EPD] Clear black: %u ms\r\n", t1);
  542. t1 = clock();
  543. #endif
  544. m = 0xff;
  545. EPD_Dis_Full(&m, 0); //all white
  546. #if EPD_DEBUG
  547. t1 = clock() - t1;
  548. printf("[EPD] Clear white: %u ms\r\n", t1);
  549. #endif
  550. }
  551. // Partial clear screen
  552. //=========================
  553. void EPD_DisplayClearPart()
  554. {
  555. uint8_t m = 0xFF;
  556. EPD_init_Part();
  557. #if EPD_DEBUG
  558. uint32_t t1 = clock();
  559. EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
  560. m = 0x00;
  561. EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all black
  562. m = 0xFF;
  563. EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
  564. t1 = clock() - t1;
  565. printf("[EPD] Part Clear: %u ms\r\n", t1);
  566. #else
  567. EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
  568. m = 0x00;
  569. EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all black
  570. m = 0xFF;
  571. EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
  572. #endif
  573. }
  574. //==================================
  575. void EPD_DisplaySetFull(uint8_t val)
  576. {
  577. EPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));
  578. #if EPD_DEBUG
  579. uint32_t t1 = clock();
  580. EPD_Dis_Full(&val, 0);
  581. t1 = clock() - t1;
  582. printf("[EPD] Display Set Full: %u ms [%02x]\r\n", t1, val);
  583. #else
  584. EPD_Dis_Full(&val, 0);
  585. #endif
  586. }
  587. //======================================================================================
  588. void EPD_DisplaySetPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t val)
  589. {
  590. EPD_Write((uint8_t *)LUT_part, 31);
  591. #if EPD_DEBUG
  592. uint32_t t1 = clock();
  593. EPD_Dis_Part(yStart,yEnd,xStart,xEnd, &val,0);
  594. t1 = clock() - t1;
  595. printf("[EPD] Display Set Part: %u ms [%02x]\r\n", t1, val);
  596. #else
  597. EPD_Dis_Part(yStart,yEnd,xStart,xEnd, &val,0);
  598. #endif
  599. }
  600. //======================================
  601. void EPD_DisplayFull(uint8_t *DisBuffer)
  602. {
  603. EPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));
  604. #if EPD_DEBUG
  605. uint32_t t1 = clock();
  606. EPD_Dis_Full((uint8_t *)DisBuffer,1);
  607. t1 = clock() - t1;
  608. printf("[EPD] Display Full: %u ms\r\n", t1);
  609. #else
  610. EPD_Dis_Full((uint8_t *)DisBuffer,1);
  611. #endif
  612. }
  613. //==========================================================================================
  614. void EPD_DisplayPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t *DisBuffer)
  615. {
  616. EPD_Write((uint8_t *)LUT_part, 31);
  617. #if EPD_DEBUG
  618. uint32_t t1 = clock();
  619. EPD_Dis_Part(yStart,yEnd,xStart,xEnd,(uint8_t *)DisBuffer,1);
  620. t1 = clock() - t1;
  621. printf("[EPD] Display Part: %u ms [%02x:%02x]\r\n", t1, LUT_gs[1], LUT_gs[21]);
  622. #else
  623. EPD_Dis_Part(yStart,yEnd,xStart,xEnd,(uint8_t *)DisBuffer,1);
  624. #endif
  625. }
  626. //============
  627. void EPD_Cls()
  628. {
  629. EPD_DisplaySetPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, 0xFF);
  630. memset(disp_buffer, 0xFF, _width * (_height/8));
  631. memset(gs_disp_buffer, 0, _width * _height);
  632. gs_used_shades = 0;
  633. }
  634. //-------------------------------------------------------------------------------
  635. void EPD_gsUpdate(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t gs)
  636. {
  637. uint8_t val, buf_val, new_val;
  638. int count=0, changed=0;
  639. int x;
  640. uint8_t y;
  641. for (x=xStart; x<=xEnd; x++) {
  642. for (y=yStart; y<=yEnd; y++) {
  643. val = gs_drawBuff[(y * (xEnd-xStart+1)) + x];
  644. if (val > 15) val >>= 4;
  645. if (val == gs) {
  646. buf_val = drawBuff[(x * ((yEnd-yStart+1)>>3)) + (y>>3)];
  647. new_val = buf_val;
  648. if (gs > 0) new_val &= (0x80 >> (y % 8)) ^ 0xFF;
  649. else new_val |= (0x80 >> (y % 8));
  650. if (new_val != buf_val) {
  651. drawBuff[(x * (_height>>3)) + (y>>3)] = new_val;
  652. changed++;
  653. }
  654. count++;
  655. }
  656. }
  657. }
  658. if (changed) {
  659. #if EPD_DEBUG
  660. printf("[EPD] GS Update %02x, count=%d changed=%d\r\n", gs, count, changed);
  661. #endif
  662. uint8_t *_lutPart = LUT_part;
  663. memset(LUT_gs+1, 0, 30);
  664. if (gs > 0) {
  665. if (gs > 0) {
  666. LUT_gs[1] = 0x18;
  667. LUT_gs[21] = gs;
  668. }
  669. }
  670. else {
  671. LUT_gs[1] = 0x28;
  672. LUT_gs[2] = 0x00;
  673. LUT_gs[21] = 15;
  674. }
  675. LUT_part = LUT_gs;
  676. EPD_DisplayPart(xStart, xEnd, yStart, yEnd, drawBuff);
  677. LUT_part = _lutPart;
  678. }
  679. }
  680. //-----------------------------------------------------------------------
  681. void EPD_Update(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd)
  682. {
  683. if (_gs == 0) EPD_DisplayPart(xStart, xEnd, yStart, yEnd, drawBuff);
  684. else {
  685. for (int n=0; n<16; n++) {
  686. if (gs_used_shades & (1<<n)) EPD_gsUpdate(xStart, xEnd, yStart, yEnd, n);
  687. }
  688. }
  689. }
  690. //-------------------
  691. void EPD_UpdateScreen()
  692. {
  693. EPD_Update(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1);
  694. }
  695. //------------------------
  696. void EPD_wait(uint32_t ms)
  697. {
  698. if (ms < 100) ms = 100;
  699. uint32_t n = 0;
  700. while (n < ms) {
  701. vTaskDelay(100 / portTICK_RATE_MS);
  702. n += 100;
  703. }
  704. }