25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

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