#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 < len; i = i + SPI_MAX_LEN) { memset(&t, 0, sizeof(t)); // Zero out the transaction t.length = SPI_MAX_LEN * 8; // Len is in bytes, transaction length is in bits. t.tx_buffer = data + i; // Data t.user = (void *)1; // D/C needs to be set to 1 ret = spi_device_queue_trans(spi, &t, portMAX_DELAY); // Transmit! // assert(ret==ESP_OK); //Should have had no issues. if (ret != ESP_OK) { printf("spi_device_queue_trans err:ret =%d", ret); } spi_get_result(spi); } i -= SPI_MAX_LEN; memset(&t, 0, sizeof(t)); // Zero out the transaction t.length = (len - i) * 8; // Len is in bytes, transaction length is in bits. t.tx_buffer = data + i; // Data t.user = (void *)1; // D/C needs to be set to 1 ret = spi_device_queue_trans(spi, &t, portMAX_DELAY); // Transmit! // assert(ret==ESP_OK); //Should have had no issues. if (ret != ESP_OK) { printf("spi_device_queue_trans err:ret =%d", ret); } spi_get_result(spi); return; } memset(&t, 0, sizeof(t)); // Zero out the transaction t.length = len * 8; // Len is in bytes, transaction length is in bits. t.tx_buffer = data; // Data t.user = (void *)1; // D/C needs to be set to 1 ret = spi_device_queue_trans(spi, &t, portMAX_DELAY); // Transmit! // assert(ret==ESP_OK); //Should have had no issues. if (ret != ESP_OK) { printf("spi_device_queue_trans err:ret =%d", ret); } spi_get_result(spi); #else { for (int i = 0; i < len; i++) { SPI_Write(data[i]); } } #endif } void epd_write_cmd(screen_t screen, unsigned char command, bool keep_cs_active) { if (screen == SCREEN_LEFT) { gpio_set_level(PIN_R_CS, 1); gpio_set_level(PIN_L_CS, 0); gpio_set_level(PIN_L_DC, 0); epd_cmd(epd_spi, command, keep_cs_active); gpio_set_level(PIN_R_CS, 1); gpio_set_level(PIN_L_CS, 1); } else if (screen == SCREEN_RIGHT) { gpio_set_level(PIN_L_CS, 1); gpio_set_level(PIN_R_CS, 0); gpio_set_level(PIN_R_DC, 0); epd_cmd(epd_spi, command, keep_cs_active); gpio_set_level(PIN_L_CS, 1); gpio_set_level(PIN_R_CS, 1); } else { ESP_LOGE(LOG_TAG, "cmd err:screen"); } } void epd_write_data(screen_t screen, const uint8_t *data, int len) { if (screen == SCREEN_LEFT) { gpio_set_level(PIN_R_CS, 1); gpio_set_level(PIN_L_CS, 0); gpio_set_level(PIN_L_DC, 1); epd_data(epd_spi, data, len); gpio_set_level(PIN_L_CS, 1); } else if (screen == SCREEN_RIGHT) { gpio_set_level(PIN_L_CS, 1); gpio_set_level(PIN_R_CS, 0); gpio_set_level(PIN_R_DC, 1); epd_data(epd_spi, data, len); gpio_set_level(PIN_R_CS, 1); } else { ESP_LOGE(LOG_TAG, "data err:screen"); } } bool epd_check_status(screen_t screen) { #if 0 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"); } #else int count = 0; unsigned char busy; int64_t t_after_us = 0; int64_t t_before_us = esp_timer_get_time(); // while(1) { //=1 BUSY if (screen == SCREEN_LEFT) { while (1) { busy = gpio_get_level(PIN_L_BUSY); busy = (busy & 0x01); if (busy == 1) { // printf("left lcd idle\r\n"); break; } #if 0 vTaskDelay(10 / portTICK_PERIOD_MS); count ++; if(count >= 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("SCREEN_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); 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("SCREEN_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); 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 << epd_pin_set->sclk_pin) | \ (1ULL << epd_pin_set->sda_pin) | \ (1ULL << epd_pin_set->res_pin) | \ (1ULL << epd_pin_set->dc_pin) | \ (1ULL << epd_pin_set->cs_pin)) #define EPD_IN_PIN_SEL (1ULL << epd_pin_set->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*/