#include #include "EPD.h" #include #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "GUI_Paint.h" #include "freertos/timers.h" //#include "../components/../main/user_sleep.h" #include "esp_timer.h" uint8_t current_display = 0; #include "../../main/user_sleep.h" #include "esp_sleep.h" static const char *LOG_TAG = "EPD"; #if HARDWARE_SPI spi_device_handle_t epd_spi; // uint8_t cmd[1]={0}; // epd_write_cmd(screen,0x00,false); // cmd[0] = 0x17; // epd_write_data(screen,cmd,1); //Place data into DRAM. Constant data gets placed into DROM by default, which is not accessible by DMA. DRAM_ATTR static const epd_init_cmd_t init_cmds[]={ {0x00,{0x1f,0x0E},2}, {0x50,{0x18,0x07},2}, {0xe0,{0x02},1}, {0xe5,{0x5c},1}, {0x11, {0}, 0x80}, #if 0 {0x00,{0x1B},1}, #else //{0x00,{0x8F},1}, #endif {0, {0}, 0xff}, }; //This function is called (in irq context!) just before a transmission starts. It will //set the D/C line to the value indicated in the user field. static void spi_pre_transfer_callback(spi_transaction_t *t) { int dc=(int)t->user; gpio_set_level(PIN_L_DC, dc); gpio_set_level(PIN_R_DC, dc); } #if 0 void epd_spi_write(struct EPD_INFO_SET* epd_pin_set,unsigned char value) { int i = 0,data = value; epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL); for(i=0;i<8;i++) { if(data&0x0080) { epd_set_level(epd_pin_set->sda_pin,HIGH_LEVEL); } else { epd_set_level(epd_pin_set->sda_pin,LOW_LEVEL); } // ets_delay_us(1); epd_set_level(epd_pin_set->sclk_pin, HIGH_LEVEL); // ets_delay_us(1); epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL); data = ((data)<<1 & 0xff); } } #endif /********************************************************************************* * function : SPI_Write * Description : spi写入数据 * Input : * Output : * Author : 祁鑫 Data : 2023 8.11 **********************************************************************************/ IRAM_ATTR void SPI_Write(unsigned char value) { int i=0,data=value; int j = 100; gpio_set_level(PIN_SPI_CLK, 0); for(i=0;i<8;i++) { if(data&0x0080) { gpio_set_level(PIN_SPI_MOSI, 1); //EPD_SDA_1; }else { gpio_set_level(PIN_SPI_MOSI, 0); //EPD_SDA_0; } //vTaskDelay(1/ portTICK_PERIOD_MS); gpio_set_level(PIN_SPI_CLK, 1); //vTaskDelay(1/ portTICK_PERIOD_MS); gpio_set_level(PIN_SPI_CLK, 0); data=((data<<1)&0xff); } } //Initialize the display void epd_init(void) { #if !SOFTWARE_SPI_ENABLE //硬件spi esp_err_t ret; spi_bus_config_t buscfg={ .miso_io_num=-1, .mosi_io_num=PIN_SPI_MOSI, .sclk_io_num=PIN_SPI_CLK, .quadwp_io_num=-1, .quadhd_io_num=-1, .max_transfer_sz=4096//dma }; spi_device_interface_config_t devcfg={ .clock_speed_hz=20*1000*1000, //Clock out at 10 MHz .mode=0, //SPI mode 0 .spics_io_num=-1, //CS pin .queue_size=7, //We want to be able to queue 7 transactions at a time .pre_cb=spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line }; //Initialize the SPI bus ret=spi_bus_initialize(EPD_HOST, &buscfg, SPI_DMA_CH_AUTO); ESP_ERROR_CHECK(ret); //Attach the LCD to the SPI bus ret=spi_bus_add_device(EPD_HOST, &devcfg, &epd_spi); ESP_ERROR_CHECK(ret); #else //软件模拟spi gpio_reset_pin(PIN_SPI_MOSI); gpio_reset_pin(PIN_SPI_CLK); gpio_reset_pin(PIN_L_CS); gpio_reset_pin(PIN_L_DC); gpio_reset_pin(PIN_L_RST); gpio_reset_pin(PIN_L_BUSY); gpio_reset_pin(PIN_R_CS); gpio_reset_pin(PIN_R_DC); gpio_reset_pin(PIN_R_RST); gpio_reset_pin(PIN_R_BUSY); #endif //gpio_reset_pin(PIN_L_CS); //Initialize non-SPI GPIOs gpio_config_t io_conf = {}; io_conf.pin_bit_mask = PIN_EPD_OUTPUT; io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pull_up_en = 0; gpio_config(&io_conf); io_conf.pin_bit_mask = PIN_EPD_INPUT; io_conf.mode = GPIO_MODE_INPUT; io_conf.pull_up_en = 0; gpio_config(&io_conf); //Reset the display int reson = is_wake_up_reson(); //返回唤醒的原因 if ( 1 //(reson != ESP_SLEEP_WAKEUP_ULP) && (reson != ESP_SLEEP_WAKEUP_TIMER) && (reson != ESP_SLEEP_WAKEUP_EXT0) ) { gpio_set_level(PIN_L_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_L_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_R_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_R_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); #if 1 int cmd=0; //Send all the commands while (init_cmds[cmd].databytes!=0xff) { #if 1 epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); #endif if (init_cmds[cmd].databytes&0x80) { vTaskDelay(100 / portTICK_PERIOD_MS); } cmd++; } #endif } #if QUICK_DISPLAY uint8_t *old_buffer= heap_caps_malloc(480*81, MALLOC_CAP_8BIT); memset(old_buffer,0X00,480*81); epd_cache_quick_full_screen_refresh(SCREEN_LEFT,NULL,old_buffer); epd_write_cmd(SCREEN_LEFT,0x04,false); //POWER ON epd_check_status(SCREEN_LEFT); //waiting for the electronic paper IC to release the idle signal //Refresh epd_refresh(SCREEN_LEFT); epd_write_cmd(SCREEN_LEFT,0x02,false); // Power OFF epd_check_status(SCREEN_LEFT); epd_sleep(SCREEN_LEFT); free(old_buffer); #else #endif } void epd_init_cmd(screen_t screen) { if( screen == SCREEN_LEFT) { gpio_set_level(PIN_L_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_L_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); int cmd=0; //Send all the commands while (init_cmds[cmd].databytes!=0xff) { #if 1 epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); #endif if (init_cmds[cmd].databytes&0x80) { vTaskDelay(10 / portTICK_PERIOD_MS); } cmd++; } } if( screen == SCREEN_RIGHT) { gpio_set_level(PIN_R_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_R_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); int cmd=0; //Send all the commands while (init_cmds[cmd].databytes!=0xff) { #if 1 epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); #endif if (init_cmds[cmd].databytes&0x80) { vTaskDelay(100 / portTICK_PERIOD_MS); } cmd++; } } } static void spi_get_result(spi_device_handle_t spi) { spi_transaction_t *rtrans = NULL; esp_err_t ret; spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); //assert(ret==ESP_OK); } void epd_cmd(spi_device_handle_t spi, const uint8_t cmd, bool keep_cs_active) { #if !SOFTWARE_SPI_ENABLE esp_err_t ret; spi_transaction_t t; memset(&t, 0, sizeof(t)); //Zero out the transaction t.length=8; //Command is 8 bits t.tx_buffer=&cmd; //The data is the cmd itself t.user=(void*)0; //D/C needs to be set to 0 if (keep_cs_active) { t.flags = SPI_TRANS_CS_KEEP_ACTIVE; //Keep CS active after data transfer } ret=spi_device_queue_trans(spi, &t, portMAX_DELAY); // assert(ret==ESP_OK); //Should have had no issues. spi_get_result(spi); #else SPI_Write(cmd); #endif } void epd_data(spi_device_handle_t spi, const uint8_t *data, int len) { #if !SOFTWARE_SPI_ENABLE esp_err_t ret; spi_transaction_t t; int i; if (len==0) return; //no need to send anything if(len > SPI_MAX_LEN) { for(i=0;i= 200){ printf("l---------------time out ---\n"); break; } #else t_after_us = esp_timer_get_time(); if((t_after_us-t_before_us)>1000*1000) { printf("t_before_us =%lld ,t_after_us = %lld\n",t_before_us,t_after_us); return 0; break; } #endif } } else if(screen == SCREEN_RIGHT) { //while(!gpio_get_level(PIN_R_BUSY)); while(1) { busy = gpio_get_level(PIN_R_BUSY); busy = (busy & 0x01); if(busy==1) { // printf("right lcd idle\r\n"); break; } #if 0 vTaskDelay(10 / portTICK_PERIOD_MS); count ++; if(count >= 200){ printf("r---------------time out ---\n"); break; } #else t_after_us = esp_timer_get_time(); if((t_after_us-t_before_us)>1000*1000) { printf(" r t_before_us =%lld ,t_after_us = %lld\n",t_before_us,t_after_us); return 0; break; } #endif } } else { ESP_LOGE(LOG_TAG,"check err:screen"); } } #endif return 1; } void deepsleep_epd_check_status(screen_t screen) { if(screen == SCREEN_LEFT) { while(!gpio_get_level(PIN_L_BUSY)); } else if(screen == SCREEN_RIGHT) { while(!gpio_get_level(PIN_R_BUSY)); } else { ESP_LOGE(LOG_TAG,"check err:screen"); } } void epd_check_power_off(screen_t screen) { if(screen == SCREEN_LEFT) { while(gpio_get_level(PIN_L_BUSY)) { vTaskDelay(20 / portTICK_PERIOD_MS); printf("left power off\r\n"); } } else if(screen == SCREEN_RIGHT) { while(gpio_get_level(PIN_R_BUSY)) { vTaskDelay(20 / portTICK_PERIOD_MS); printf("right power off\r\n"); } } else { ESP_LOGE(LOG_TAG,"check err:screen"); } } void epd_check_power_on(screen_t screen) { if(screen == SCREEN_LEFT) { while(gpio_get_level(PIN_L_BUSY)) { printf("left power on\r\n"); } } else if(screen == SCREEN_RIGHT) { while(gpio_get_level(PIN_R_BUSY)) { printf("right power on\r\n"); } } else { ESP_LOGE(LOG_TAG,"check err:screen"); } } void epd_refresh(screen_t screen) { epd_write_cmd(screen,0x12,false);//DISPLAY REFRESH //ets_delay_us(200); //!!!The delay here is necessary, 200uS at least!!! //vTaskDelay(1 / portTICK_PERIOD_MS); epd_check_status(screen); //waiting for the electronic paper } void epd_sleep(screen_t screen) { //printf("SLEEP SCREEN =%d\r\n",screen); #if 0 epd_write_cmd(screen,0x04,false); // Power ON epd_check_power_on(screen); #endif //epd_check_status(screen); //epd_refresh(screen); uint8_t tmp = 0xa5; epd_write_cmd(screen,0x07,false); epd_write_data(screen,&tmp,1); //vTaskDelay(20 / portTICK_PERIOD_MS); #if 0 epd_write_cmd(screen,0x02,false); // Power OFF vTaskDelay(20 / portTICK_PERIOD_MS); epd_check_power_off(screen); #endif #if 1 //epd_write_cmd(screen,0x02,false); // Power OFF //epd_check_status(screen); #endif } IRAM_ATTR void epd_display(screen_t screen,const unsigned char* picData) { epd_write_cmd(screen,0x13,false); epd_check_status(screen); epd_write_data(screen,picData,38880); epd_check_status(screen); epd_write_cmd(screen,0x04,false); //POWER ON epd_check_status(screen); //waiting for the electronic paper IC to release the idle signal //Refresh epd_refresh(screen); epd_write_cmd(screen,0x02,false); // Power OFF epd_check_status(screen); epd_sleep(screen); } #if 1 void epd_cache(screen_t screen,const unsigned char* picData) { epd_write_cmd(screen,0x13,false); epd_write_data(screen,picData,38880); } void epd_cache_quick_full_screen_refresh(screen_t screen,const unsigned char* old,const unsigned char* new) { if((screen == SCREEN_LEFT)&&(old!=NULL)) { printf("left quick\r\n"); //Reset the display gpio_set_level(PIN_L_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_L_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); uint8_t cmd[1]={0}; epd_write_cmd(screen,0x00,false); cmd[0] = 0x1F; epd_write_data(screen,cmd,1); #if 0 uint8_t cmd[1]={0}; epd_write_cmd(screen,0x61,false); cmd[0] = 0xF0; epd_write_data(screen,cmd,1); cmd[0] = 0x01; epd_write_data(screen,cmd,1); cmd[0] = 0xA0; epd_write_data(screen,cmd,1); #endif #if 0 int cmd=0; //Send all the commands while (init_cmds[cmd].databytes!=0xff) { epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); if (init_cmds[cmd].databytes&0x80) { vTaskDelay(100 / portTICK_PERIOD_MS); } cmd++; } #endif } if((screen == SCREEN_RIGHT)&&(old!=NULL)) { printf("right quick\r\n"); gpio_set_level(PIN_R_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_R_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); // uint8_t cmd[1]={0}; // epd_write_cmd(screen,0x00,false); // cmd[0] = 0x1F; // epd_write_data(screen,cmd,1); #if 0 uint8_t cmd[1]={0}; epd_write_cmd(screen,0x61,false); cmd[0] = 0xF0; epd_write_data(screen,cmd,1); cmd[0] = 0x01; epd_write_data(screen,cmd,1); cmd[0] = 0xA0; epd_write_data(screen,cmd,1); #endif #if 0 int cmd=0; //Send all the commands while (init_cmds[cmd].databytes!=0xff) { epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false); epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F); if (init_cmds[cmd].databytes&0x80) { vTaskDelay(100 / portTICK_PERIOD_MS); } cmd++; } #endif } if (old !=NULL) { epd_write_cmd(screen,0x10,false); epd_check_status(screen); epd_write_data(screen,old,38880); } #if 0 uint8_t cmd[1]={0}; epd_write_cmd(screen,0x61,false); cmd[0] = 0xF0; epd_write_data(screen,cmd,1); cmd[0] = 0x01; epd_write_data(screen,cmd,1); cmd[0] = 0xA0; epd_write_data(screen,cmd,1); #endif epd_write_cmd(screen,0x13,false); epd_write_data(screen,new,38880); } #endif void epd_display_partal(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, screen_t screen,const unsigned char* picData) { unsigned int row, col; uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L; Xstart_H = ((Xstart)>>8) & 0xff; Xstart_L = (Xstart) & 0xff; Ystart_H = ((Ystart)>>8) & 0xff; Ystart_L = (Ystart) & 0xff; Xend_H = ((Xend-1)>>8) & 0xff; Xend_L = (Xend-1) & 0xff; Yend_H = ((Yend-1)>>8) & 0xff; Yend_L = (Yend-1) & 0xff; epd_write_cmd(screen,0x91,false); // partial in epd_check_status(screen); epd_write_cmd(screen,0x90,false); epd_check_status(screen); epd_write_data(screen,&Xstart_H,1); epd_write_data(screen,&Xstart_L,1); epd_write_data(screen,&Xend_H,1); epd_write_data(screen,&Xend_L,1); epd_write_data(screen,&Ystart_H,1); epd_write_data(screen,&Ystart_L,1); epd_write_data(screen,&Yend_H,1); epd_write_data(screen,&Yend_L,1); uint8_t tmp = 0x01; epd_write_data(screen,&tmp,1); epd_write_cmd(screen,0x13,false); epd_check_status(screen); epd_write_data(screen,picData,((Yend - Ystart)*(Xend - Xstart)/8)); epd_write_cmd(screen,0x92,false); epd_write_cmd(screen,0x04,false); // Power ON epd_check_status(screen); epd_refresh(screen); epd_write_cmd(screen,0x02,false); // Power OFF epd_check_status(screen); } void epd_partial_cache(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, screen_t screen,const unsigned char* picData) { unsigned int row, col; uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L; Xstart_H = ((Xstart)>>8) & 0xff; Xstart_L = (Xstart) & 0xff; Ystart_H = ((Ystart)>>8) & 0xff; Ystart_L = (Ystart) & 0xff; Xend_H = ((Xend-1)>>8) & 0xff; Xend_L = (Xend-1) & 0xff; Yend_H = ((Yend-1)>>8) & 0xff; Yend_L = (Yend-1) & 0xff; epd_write_cmd(screen,0x91,false); // partial in epd_check_status(screen); epd_write_cmd(screen,0x90,false); epd_check_status(screen); epd_write_data(screen,&Xstart_H,1); epd_write_data(screen,&Xstart_L,1); epd_write_data(screen,&Xend_H,1); epd_write_data(screen,&Xend_L,1); epd_write_data(screen,&Ystart_H,1); epd_write_data(screen,&Ystart_L,1); epd_write_data(screen,&Yend_H,1); epd_write_data(screen,&Yend_L,1); uint8_t tmp = 0x01; epd_write_data(screen,&tmp,1); epd_write_cmd(screen,0x13,false); epd_check_status(screen); epd_write_data(screen,picData,((Yend - Ystart)*(Xend - Xstart)/8)); epd_write_cmd(screen,0x92,false); } void epd_cache_quick_partial_screen_refresh(screen_t screen,uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,const unsigned char* old,const unsigned char* new) { if((screen == SCREEN_LEFT)&&(old!=NULL)) { printf("left partial quick\r\n"); //Reset the display gpio_set_level(PIN_L_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_L_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); uint8_t cmd[1]={0}; epd_write_cmd(screen,0x00,false); cmd[0] = 0x1F; epd_write_data(screen,cmd,1); } if((screen == SCREEN_RIGHT)&&(old!=NULL)) { printf("right partial quick\r\n"); gpio_set_level(PIN_R_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_R_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); } #if 0 if (old !=NULL) { epd_write_cmd(screen,0x10,false); epd_write_data(screen,old,38880); } epd_write_cmd(screen,0x13,false); epd_write_data(screen,new,38880); #endif unsigned int row, col; uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L; Xstart_H = ((Xstart)>>8) & 0xff; Xstart_L = (Xstart) & 0xff; Ystart_H = ((Ystart)>>8) & 0xff; Ystart_L = (Ystart) & 0xff; Xend_H = ((Xend-1)>>8) & 0xff; Xend_L = (Xend-1) & 0xff; Yend_H = ((Yend-1)>>8) & 0xff; Yend_L = (Yend-1) & 0xff; epd_write_cmd(screen,0x91,false); // partial in epd_check_status(screen); epd_write_cmd(screen,0x90,false); epd_check_status(screen); epd_write_data(screen,&Xstart_H,1); epd_write_data(screen,&Xstart_L,1); epd_write_data(screen,&Xend_H,1); epd_write_data(screen,&Xend_L,1); epd_write_data(screen,&Ystart_H,1); epd_write_data(screen,&Ystart_L,1); epd_write_data(screen,&Yend_H,1); epd_write_data(screen,&Yend_L,1); uint8_t tmp = 0x01; epd_write_data(screen,&tmp,1); // epd_write_cmd(screen,0x13,false); // epd_check_status(screen); printf("1\r\n"); if (old !=NULL) { printf("2\r\n"); epd_write_cmd(screen,0x10,false); epd_check_status(screen); epd_write_data(screen,old,((Yend - Ystart)*(Xend - Xstart)/8)); epd_write_cmd(screen,0x92,false); } printf("3\r\n"); epd_write_cmd(screen,0x13,false); epd_check_status(screen); epd_write_data(screen,new,((Yend - Ystart)*(Xend - Xstart)/8)); epd_write_cmd(screen,0x92,false); } static uint8_t get_data(uint8_t * color, uint8_t pix_size) { uint8_t data = 0; int i =0, j = 0; for (i = 0; i < 8; i++) { data = data | (color[j] << (7-i)); j = j + pix_size; } return data; } void epd_partial_cache1(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, screen_t screen,const unsigned char* picData) { unsigned int row, col; uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L; Xstart_H = ((Xstart)>>8) & 0xff; Xstart_L = (Xstart) & 0xff; Ystart_H = ((Ystart)>>8) & 0xff; Ystart_L = (Ystart) & 0xff; Xend_H = ((Xend-1)>>8) & 0xff; Xend_L = (Xend-1) & 0xff; Yend_H = ((Yend-1)>>8) & 0xff; Yend_L = (Yend-1) & 0xff; epd_write_cmd(screen,0x91,false); // partial in epd_check_status(screen); epd_write_cmd(screen,0x90,false); epd_check_status(screen); epd_write_data(screen,&Xstart_H,1); epd_write_data(screen,&Xstart_L,1); epd_write_data(screen,&Xend_H,1); epd_write_data(screen,&Xend_L,1); epd_write_data(screen,&Ystart_H,1); epd_write_data(screen,&Ystart_L,1); epd_write_data(screen,&Yend_H,1); epd_write_data(screen,&Yend_L,1); uint8_t tmp = 0x01; epd_write_data(screen,&tmp,1); epd_write_cmd(screen,0x13,false); epd_check_status(screen); #if 0 epd_write_data(screen,picData,((Yend - Ystart)*(Xend - Xstart))); #else uint8_t data; // disp_drv.hor_res = 648; // disp_drv.ver_res = 480; for (int i = 480 - 1; i >=0 ; i--) { for (int j = 0; j < 648; ) { data = get_data(&picData[j + i * 648 * 1], 1); //printf("%02x",data); epd_write_data(screen,&data,1); j = j + 8 * 1; } } #endif epd_write_cmd(screen,0x92,false); } void epd_powerOn_refresh(screen_t screen) { epd_write_cmd(screen,0x04,false); // Power ON epd_check_status(screen); epd_refresh(screen); epd_write_cmd(screen,0x02,false); // Power OFF epd_check_status(screen); } // 定义最大重复计数 #define MAX_REPEAT 255 // 压缩函数 unsigned int compressRLE(uint8_t *input, unsigned int size, uint8_t *output) { unsigned int i = 0; unsigned int outputSize = 0; while (i < size) { uint8_t current = input[i]; unsigned int count = 1; i++; while (i < size && input[i] == current && count < MAX_REPEAT) { count++; i++; } // 输出像素值和计数值到output output[outputSize++] = current; output[outputSize++] = count; } return outputSize; } // 解压函数 unsigned int decompressRLE(uint8_t *input, unsigned int size, uint8_t *output) { unsigned int i = 0; unsigned int outputSize = 0; while (i < size) { uint8_t current = input[i]; i++; unsigned int count = input[i]; i++; // 输出像素值count次到output for (unsigned int j = 0; j < count; j++) { output[outputSize++] = current; } } return outputSize; } void test() { // 定义图像数据(十六进制数组) uint8_t imageData[] = {0x12, 0x12, 0x12, 0x13, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15}; int imageSize = sizeof(imageData) / sizeof(imageData[0]); printf("原始图像数据:\n"); for (int i = 0; i < imageSize; i++) { printf("0x%02X ", imageData[i]); } printf("\n"); uint8_t compressedData[2 * imageSize]; // 假设压缩后的数据不会超过原数据的两倍大小 uint8_t decompressedData[imageSize]; // 假设解压后的数据不会超过原数据大小 printf("压缩后的数据:\n"); int compressedSize = compressRLE(imageData, imageSize, compressedData); for (int i = 0; i < compressedSize; i++) { printf("0x%02X ", compressedData[i]); } printf("\n"); printf("解压后的数据:\n"); int decompressedSize = decompressRLE(compressedData, compressedSize, decompressedData); for (int i = 0; i < decompressedSize; i++) { printf("0x%02X ", decompressedData[i]); } printf("\n"); printf("压缩后的数据大小:%d 字节\n", compressedSize); printf("解压后的数据大小:%d 字节\n", decompressedSize); } // uint8_t tmp[38880]; IRAM_ATTR bool epd_cache_quick(screen_t screen,const unsigned char* old,const unsigned char* new) { bool ret = false; if((screen == SCREEN_LEFT)&&(old!=NULL)) { printf("epd_cache_quick\r\n"); //Reset the display gpio_set_level(PIN_L_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_L_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); ret = epd_check_status(screen); if(!ret) { printf("err:2busy !!!!!\n"); goto err; } uint8_t cmd[1]={0}; epd_write_cmd(screen,0x00,false); cmd[0] = 0x1F; epd_write_data(screen,cmd,1); } if((screen == SCREEN_RIGHT)&&(old!=NULL)) { printf("right partial quick\r\n"); gpio_set_level(PIN_R_RST, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(PIN_R_RST, 1); vTaskDelay(10 / portTICK_PERIOD_MS); ret = epd_check_status(screen); if(!ret) { printf("err:3busy !!!!!\n"); goto err; } uint8_t cmd2[1]={0}; epd_write_cmd(screen,0x00,false); cmd2[0] = 0x1F; epd_write_data(screen,cmd2,1); } #if 1 if (old !=NULL) { epd_write_cmd(screen,0x10,false); ret = epd_check_status(screen); if(!ret) { printf("err:busy !!!!!\n"); goto err; } epd_write_data(screen,old,38880); ret = epd_check_status(screen); if(!ret) { printf("err:2busy !!!!!\n"); goto err; } } #else epd_write_cmd(screen,0x10,false); epd_check_status(screen); memcpy(&tmp,new,38880); for(int i=0;i<38880;i++) { tmp[i] = ~tmp[i]; } epd_write_data(screen,&tmp,38880); #endif epd_write_cmd(screen,0x13,false); ret = epd_check_status(screen); if(!ret) { printf("err:2busy !!!!!\n"); goto err; } epd_write_data(screen,new,38880); ret = epd_check_status(screen); if(!ret) { printf("err:2busy !!!!!\n"); goto err; } #if 0 if(screen == SCREEN_LEFT) { left_refresh_complete = true; } if(screen == SCREEN_RIGHT) { right_refresh_complete = true; } #else //vTaskDelay(0000 / portTICK_PERIOD_MS); //refresh_timer_start(500); //xTimerStart(slow_display_timer, 0); //开始定时器 #endif return true; err: ESP_LOGE(LOG_TAG,"err:epd_check_status"); return false; } void epd_powerOn_refresh_sleep(screen_t screen) { epd_write_cmd(screen,0x04,false); // Power ON epd_check_status(screen); epd_refresh(screen); epd_sleep(screen); } void deepsleep_epd_powerOn_refresh_sleep(screen_t screen) { epd_write_cmd(screen,0x04,false); // Power ON //epd_check_status(screen); deepsleep_epd_check_status(screen); epd_write_cmd(screen,0x12,false);//DISPLAY REFRESH deepsleep_epd_check_status(screen); //epd_refresh(screen); //epd_sleep(screen); } #else/*HAREWARE_SPI*/ static void task_delay_ms(uint32_t ms_count) { vTaskDelay(ms_count / portTICK_PERIOD_MS); } void epd_pin_init(struct EPD_INFO_SET* epd_pin_set) { esp_log_level_set("gpio",ESP_LOG_NONE);//close gpio logging ESP_LOGI(LOG_TAG,"epd_pin_init"); #define EPD_OUT_PIN_SEL ((1ULL<sclk_pin)|\ (1ULL<sda_pin)|\ (1ULL<res_pin)|\ (1ULL<dc_pin)|\ (1ULL<cs_pin)) #define EPD_IN_PIN_SEL (1ULL<busy_pin) gpio_config_t epd_pin_cfg = {}; epd_pin_cfg.intr_type = GPIO_INTR_DISABLE; epd_pin_cfg.mode = GPIO_MODE_OUTPUT; epd_pin_cfg.pin_bit_mask =EPD_OUT_PIN_SEL; epd_pin_cfg.pull_down_en = 0; epd_pin_cfg.pull_up_en = 0; gpio_config(&epd_pin_cfg); epd_pin_cfg.intr_type = GPIO_INTR_DISABLE; epd_pin_cfg.mode = GPIO_MODE_INPUT; epd_pin_cfg.pin_bit_mask =EPD_IN_PIN_SEL; epd_pin_cfg.pull_down_en = 0; epd_pin_cfg.pull_up_en = 1; gpio_config(&epd_pin_cfg); esp_log_level_set("gpio",LOG_LOCAL_LEVEL); } void epd_spi_write(struct EPD_INFO_SET* epd_pin_set,unsigned char value) { int i = 0,data = value; epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL); for(i=0;i<8;i++) { if(data&0x0080) { epd_set_level(epd_pin_set->sda_pin,HIGH_LEVEL); } else { epd_set_level(epd_pin_set->sda_pin,LOW_LEVEL); } // ets_delay_us(1); epd_set_level(epd_pin_set->sclk_pin, HIGH_LEVEL); // ets_delay_us(1); epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL); data = ((data)<<1 & 0xff); } } void epd_write_cmd(struct EPD_INFO_SET* epd_pin_set, unsigned char command) { epd_set_level(epd_pin_set->cs_pin, LOW_LEVEL); epd_set_level(epd_pin_set->dc_pin, LOW_LEVEL); epd_spi_write(epd_pin_set,command); epd_set_level(epd_pin_set->cs_pin, HIGH_LEVEL); } void epd_write_data(struct EPD_INFO_SET* epd_pin_set, unsigned char command) { epd_set_level(epd_pin_set->cs_pin, LOW_LEVEL); epd_set_level(epd_pin_set->dc_pin, HIGH_LEVEL); epd_spi_write(epd_pin_set,command); epd_set_level(epd_pin_set->cs_pin, HIGH_LEVEL); //ets_delay_us(2); } void epd_init(struct EPD_INFO_SET* epd_pin_set) { epd_set_level(epd_pin_set->res_pin, LOW_LEVEL); task_delay_ms(10); epd_set_level(epd_pin_set->res_pin, HIGH_LEVEL); task_delay_ms(10); } void epd_check_status(struct EPD_INFO_SET* epd_pin_set) { while(!epd_get_level(epd_pin_set->busy_pin)); } void epd_refresh(struct EPD_INFO_SET* epd_pin_set) { epd_write_cmd(epd_pin_set,0x12);//DISPLAY REFRESH //ets_delay_us(200); //!!!The delay here is necessary, 200uS at least!!! task_delay_ms(1); epd_check_status(epd_pin_set); //waiting for the electronic paper } void epd_sleep(struct EPD_INFO_SET* epd_pin_set) { epd_write_cmd(epd_pin_set,0x07); epd_write_data(epd_pin_set,0xa5); } void epd_screen_init(struct EPD_INFO_SET* epd_pin_set) { epd_pin_init(epd_pin_set); epd_init(epd_pin_set); epd_write_cmd(epd_pin_set,0x00); epd_write_data(epd_pin_set,0x1f); epd_write_data(epd_pin_set,0x09); epd_write_cmd(epd_pin_set,0x50); epd_write_data(epd_pin_set,0x18); epd_write_data(epd_pin_set,0x07); epd_write_cmd(epd_pin_set,0xe0); epd_write_data(epd_pin_set,0x02); epd_write_cmd(epd_pin_set,0xe5); epd_write_data(epd_pin_set,0x5c); } void epd_clear_black(struct EPD_INFO_SET* epd_pin_set) { unsigned int i; epd_write_cmd(epd_pin_set,0x13); for(i=0;i<38880;i++) { epd_write_data(epd_pin_set,0xff); } epd_write_cmd(epd_pin_set,0x04); //POWER ON epd_check_status(epd_pin_set); //waiting for the electronic paper IC to release the idle signal epd_refresh(epd_pin_set); epd_write_cmd(epd_pin_set,0x02); // Power OFF epd_check_status(epd_pin_set); } void epd_clear_write(struct EPD_INFO_SET* epd_pin_set) { unsigned int i; epd_write_cmd(epd_pin_set,0x13); for(i=0;i<38880;i++) { epd_write_data(epd_pin_set,0x00); } epd_write_cmd(epd_pin_set,0x04); //POWER ON epd_check_status(epd_pin_set); //waiting for the electronic paper IC to release the idle signal //Refresh epd_refresh(epd_pin_set); epd_write_cmd(epd_pin_set,0x02); // Power OFF epd_check_status(epd_pin_set); } // PAINT left_screen_paint; // PAINT right_screen_paint; void epd_display(struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData) { unsigned int i; epd_write_cmd(epd_pin_set,0x13); for(i=0;i<38880;i++) { epd_write_data(epd_pin_set,picData[i]); } epd_write_cmd(epd_pin_set,0x04); //POWER ON epd_check_status(epd_pin_set); //waiting for the electronic paper IC to release the idle signal //Refresh epd_refresh(epd_pin_set); epd_write_cmd(epd_pin_set,0x02); // Power OFF epd_check_status(epd_pin_set); } void epd_cache(struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData) { unsigned int i; epd_write_cmd(epd_pin_set,0x13); for(i=0;i<38880;i++) { epd_write_data(epd_pin_set,picData[i]); } } void epd_display_partal(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData) { unsigned int row, col; uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L; Xstart_H = ((Xstart)>>8) & 0xff; Xstart_L = (Xstart) & 0xff; Ystart_H = ((Ystart)>>8) & 0xff; Ystart_L = (Ystart) & 0xff; Xend_H = ((Xend-1)>>8) & 0xff; Xend_L = (Xend-1) & 0xff; Yend_H = ((Yend-1)>>8) & 0xff; Yend_L = (Yend-1) & 0xff; epd_write_cmd(epd_pin_set,0x91); // partial in epd_check_status(epd_pin_set); epd_write_cmd(epd_pin_set,0x90); epd_check_status(epd_pin_set); epd_write_data(epd_pin_set,Xstart_H); epd_write_data(epd_pin_set,Xstart_L); epd_write_data(epd_pin_set,Xend_H); epd_write_data(epd_pin_set,Xend_L); epd_write_data(epd_pin_set,Ystart_H); epd_write_data(epd_pin_set,Ystart_L); epd_write_data(epd_pin_set,Yend_H); epd_write_data(epd_pin_set,Yend_L); epd_write_data(epd_pin_set,0x01); epd_write_cmd(epd_pin_set,0x13); epd_check_status(epd_pin_set); int i = 0; for(col=0; col<(Yend - Ystart); col++) { for(row=0; row<((Xend - Xstart)/8); row++) { epd_write_data(epd_pin_set,picData[i++]); } } epd_write_cmd(epd_pin_set,0x92); epd_write_cmd(epd_pin_set,0x04); // Power ON epd_check_status(epd_pin_set); epd_refresh(epd_pin_set); epd_write_cmd(epd_pin_set,0x02); // Power OFF epd_check_status(epd_pin_set); } void epd_partial_cache(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData) { unsigned int row, col; uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L; Xstart_H = ((Xstart)>>8) & 0xff; Xstart_L = (Xstart) & 0xff; Ystart_H = ((Ystart)>>8) & 0xff; Ystart_L = (Ystart) & 0xff; Xend_H = ((Xend-1)>>8) & 0xff; Xend_L = (Xend-1) & 0xff; Yend_H = ((Yend-1)>>8) & 0xff; Yend_L = (Yend-1) & 0xff; epd_write_cmd(epd_pin_set,0x91); // partial in epd_check_status(epd_pin_set); epd_write_cmd(epd_pin_set,0x90); epd_check_status(epd_pin_set); epd_write_data(epd_pin_set,Xstart_H); epd_write_data(epd_pin_set,Xstart_L); epd_write_data(epd_pin_set,Xend_H); epd_write_data(epd_pin_set,Xend_L); epd_write_data(epd_pin_set,Ystart_H); epd_write_data(epd_pin_set,Ystart_L); epd_write_data(epd_pin_set,Yend_H); epd_write_data(epd_pin_set,Yend_L); epd_write_data(epd_pin_set,0x01); epd_write_cmd(epd_pin_set,0x13); epd_check_status(epd_pin_set); int i = 0; for(col=0; col<(Yend - Ystart); col++) { for(row=0; row<((Xend - Xstart)/8); row++) { epd_write_data(epd_pin_set,picData[i++]); } } epd_write_cmd(epd_pin_set,0x92); } void epd_powerOn_refresh(struct EPD_INFO_SET* epd_pin_set) { epd_write_cmd(epd_pin_set,0x04); // Power ON epd_check_status(epd_pin_set); epd_refresh(epd_pin_set); epd_write_cmd(epd_pin_set,0x02); // Power OFF epd_check_status(epd_pin_set); } #endif/*HAREWARE_SPI*/