From 7f332f120c0aaee7f5f63e6bef189ccd4fb8e217 Mon Sep 17 00:00:00 2001 From: Tomato Me <55608753+DrayxR3X@users.noreply.github.com> Date: Sat, 15 Nov 2025 13:01:12 +0800 Subject: [PATCH] Add support for Waveshare ESP32-S3-ePaper-1.54 board (#1375) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add support for Waveshare ESP32-S3-ePaper-1.54 board * 根据审核,做对应的修改 * fix:优化格式,主要是对头文件引用进行修改 --------- Co-authored-by: Tomato Me <55608753+wurongmin@users.noreply.github.com> --- main/CMakeLists.txt | 4 + main/Kconfig.projbuild | 3 + .../boards/waveshare-s3-epaper-1.54/README.md | 48 +++ .../board_power_bsp.cc | 58 +++ .../board_power_bsp.h | 23 + main/boards/waveshare-s3-epaper-1.54/config.h | 50 +++ .../waveshare-s3-epaper-1.54/config.json | 12 + .../custom_lcd_display.cc | 404 ++++++++++++++++++ .../custom_lcd_display.h | 75 ++++ .../waveshare-s3-epaper-1.54.cc | 110 +++++ 10 files changed, 787 insertions(+) create mode 100644 main/boards/waveshare-s3-epaper-1.54/README.md create mode 100644 main/boards/waveshare-s3-epaper-1.54/board_power_bsp.cc create mode 100644 main/boards/waveshare-s3-epaper-1.54/board_power_bsp.h create mode 100644 main/boards/waveshare-s3-epaper-1.54/config.h create mode 100644 main/boards/waveshare-s3-epaper-1.54/config.json create mode 100644 main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.cc create mode 100644 main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.h create mode 100644 main/boards/waveshare-s3-epaper-1.54/waveshare-s3-epaper-1.54.cc diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 79b71d1d..133db258 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -264,6 +264,10 @@ elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B) set(BUILTIN_TEXT_FONT font_puhui_basic_16_4) set(BUILTIN_ICON_FONT font_awesome_16_4) set(DEFAULT_EMOJI_COLLECTION twemoji_32) +elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_ePaper_1_54) + set(BOARD_TYPE "waveshare-s3-epaper-1.54") + set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_ICON_FONT font_awesome_20_4) elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49) set(BOARD_TYPE "waveshare-s3-touch-lcd-3.49") set(LVGL_TEXT_FONT font_puhui_basic_30_4) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index afaad371..8ff6a494 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -282,6 +282,9 @@ choice BOARD_TYPE config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5 bool "Waveshare ESP32-S3-Touch-LCD-3.5" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_WAVESHARE_S3_ePaper_1_54 + bool "Waveshare ESP32-S3-ePaper-1.54" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B bool "Waveshare ESP32-S3-Touch-LCD-3.5B" depends on IDF_TARGET_ESP32S3 diff --git a/main/boards/waveshare-s3-epaper-1.54/README.md b/main/boards/waveshare-s3-epaper-1.54/README.md new file mode 100644 index 00000000..db9ac2ab --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/README.md @@ -0,0 +1,48 @@ +# 产品链接 + +[微雪电子 ESP32-S3-ePaper-1.54](https://www.waveshare.net/shop/ESP32-S3-ePaper-1.54.htm) + +# 编译配置命令 + +**克隆工程** + +```bash +git clone https://github.com/78/xiaozhi-esp32.git +``` + +**进入工程** + +```bash +cd xiaozhi-esp32 +``` + +**配置编译目标为 ESP32S3** + +```bash +idf.py set-target esp32s3 +``` + +**打开 menuconfig** + +```bash +idf.py menuconfig +``` + +**选择板子** + +```bash +Xiaozhi Assistant -> Board Type -> Waveshare ESP32-S3-ePaper-1.54 +``` + +**编译** + +```ba +idf.py build +``` + +**下载并打开串口终端** + +```bash +idf.py build flash monitor +``` + diff --git a/main/boards/waveshare-s3-epaper-1.54/board_power_bsp.cc b/main/boards/waveshare-s3-epaper-1.54/board_power_bsp.cc new file mode 100644 index 00000000..93eb9f7a --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/board_power_bsp.cc @@ -0,0 +1,58 @@ +#include +#include +#include +#include "board_power_bsp.h" + +void BoardPowerBsp::PowerLedTask(void *arg) { + gpio_config_t gpio_conf = {}; + gpio_conf.intr_type = GPIO_INTR_DISABLE; + gpio_conf.mode = GPIO_MODE_OUTPUT; + gpio_conf.pin_bit_mask = (0x1ULL << GPIO_NUM_3); + gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE; + ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf)); + for (;;) { + gpio_set_level(GPIO_NUM_3, 0); + vTaskDelay(pdMS_TO_TICKS(200)); + gpio_set_level(GPIO_NUM_3, 1); + vTaskDelay(pdMS_TO_TICKS(200)); + } +} + +BoardPowerBsp::BoardPowerBsp(int epdPowerPin, int audioPowerPin, int vbatPowerPin) : epdPowerPin_(epdPowerPin), audioPowerPin_(audioPowerPin), vbatPowerPin_(vbatPowerPin) { + gpio_config_t gpio_conf = {}; + gpio_conf.intr_type = GPIO_INTR_DISABLE; + gpio_conf.mode = GPIO_MODE_OUTPUT; + gpio_conf.pin_bit_mask = (0x1ULL << epdPowerPin_) | (0x1ULL << audioPowerPin_) | (0x1ULL << vbatPowerPin_); + gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE; + ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf)); + xTaskCreatePinnedToCore(PowerLedTask, "PowerLedTask", 3 * 1024, NULL, 2, NULL, 0); +} + +BoardPowerBsp::~BoardPowerBsp() { +} + +void BoardPowerBsp::PowerEpdOn() { + gpio_set_level((gpio_num_t) epdPowerPin_, 0); +} + +void BoardPowerBsp::PowerEpdOff() { + gpio_set_level((gpio_num_t) epdPowerPin_, 1); +} + +void BoardPowerBsp::PowerAudioOn() { + gpio_set_level((gpio_num_t) audioPowerPin_, 0); +} + +void BoardPowerBsp::PowerAudioOff() { + gpio_set_level((gpio_num_t) audioPowerPin_, 1); +} + +void BoardPowerBsp::VbatPowerOn() { + gpio_set_level((gpio_num_t) vbatPowerPin_, 1); +} + +void BoardPowerBsp::VbatPowerOff() { + gpio_set_level((gpio_num_t) vbatPowerPin_, 0); +} \ No newline at end of file diff --git a/main/boards/waveshare-s3-epaper-1.54/board_power_bsp.h b/main/boards/waveshare-s3-epaper-1.54/board_power_bsp.h new file mode 100644 index 00000000..1301168e --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/board_power_bsp.h @@ -0,0 +1,23 @@ +#ifndef __BOARD_POWER_BSP_H__ +#define __BOARD_POWER_BSP_H__ + +class BoardPowerBsp { +private: + const int epdPowerPin_; + const int audioPowerPin_; + const int vbatPowerPin_; + + static void PowerLedTask(void *arg); + +public: + BoardPowerBsp(int epdPowerPin, int audioPowerPin, int vbatPowerPin); + ~BoardPowerBsp(); + void PowerEpdOn(); + void PowerEpdOff(); + void PowerAudioOn(); + void PowerAudioOff(); + void VbatPowerOn(); + void VbatPowerOff(); +}; + +#endif \ No newline at end of file diff --git a/main/boards/waveshare-s3-epaper-1.54/config.h b/main/boards/waveshare-s3-epaper-1.54/config.h new file mode 100644 index 00000000..898f0ed4 --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/config.h @@ -0,0 +1,50 @@ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +#include + +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 + +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_14 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_38 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_15 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_16 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_45 + +#define AUDIO_CODEC_PA_PIN GPIO_NUM_46 +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_47 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_48 +#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR + +#define BOOT_BUTTON_GPIO GPIO_NUM_0 +#define VBAT_PWR_GPIO GPIO_NUM_18 + +/*EPD port Init*/ +#define EPD_SPI_NUM SPI3_HOST + +#define EPD_DC_PIN GPIO_NUM_10 +#define EPD_CS_PIN GPIO_NUM_11 +#define EPD_SCK_PIN GPIO_NUM_12 +#define EPD_MOSI_PIN GPIO_NUM_13 +#define EPD_RST_PIN GPIO_NUM_9 +#define EPD_BUSY_PIN GPIO_NUM_8 + +#define EXAMPLE_LCD_WIDTH 200 +#define EXAMPLE_LCD_HEIGHT 200 + +/*DEV POWER init*/ +#define EPD_PWR_PIN GPIO_NUM_6 +#define Audio_PWR_PIN GPIO_NUM_42 +#define VBAT_PWR_PIN GPIO_NUM_17 + +#define DISPLAY_MIRROR_X false +#define DISPLAY_MIRROR_Y false +#define DISPLAY_SWAP_XY false + +#define DISPLAY_OFFSET_X 0 +#define DISPLAY_OFFSET_Y 0 + + + +#endif // _BOARD_CONFIG_H_ diff --git a/main/boards/waveshare-s3-epaper-1.54/config.json b/main/boards/waveshare-s3-epaper-1.54/config.json new file mode 100644 index 00000000..6bd70209 --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/config.json @@ -0,0 +1,12 @@ +{ + "target": "esp32s3", + "builds": [ + { + "name": "waveshare-s3-epaper-1.54", + "sdkconfig_append": [ + "CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=partitions/v2/8m.csv", + "CONFIG_ESPTOOLPY_FLASHSIZE=8MB" + ] + } + ] +} \ No newline at end of file diff --git a/main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.cc b/main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.cc new file mode 100644 index 00000000..1169c9ef --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.cc @@ -0,0 +1,404 @@ +#include +#include +#include +#include +#include +#include "custom_lcd_display.h" +#include "board.h" +#include "config.h" +#include "esp_lvgl_port.h" +#include "settings.h" + +#define TAG "CustomLcdDisplay" + +#define BYTES_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565)) +#define BUFF_SIZE (EXAMPLE_LCD_WIDTH * EXAMPLE_LCD_HEIGHT * BYTES_PER_PIXEL) + +const uint8_t WF_Full_1IN54[159] = +{ + 0x80,0x48,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x40,0x48,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x80,0x48,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x40,0x48,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xA,0x0,0x0,0x0,0x0,0x0,0x0, + 0x8,0x1,0x0,0x8,0x1,0x0,0x2, + 0xA,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, + 0x22,0x17,0x41,0x0,0x32,0x20 +}; + +const uint8_t WF_PARTIAL_1IN54_0[159] = +{ + 0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xF,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1,0x1,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, + 0x02,0x17,0x41,0xB0,0x32,0x28, +}; + +void CustomLcdDisplay::lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *color_p) { + assert(disp != NULL); + CustomLcdDisplay *driver = (CustomLcdDisplay *) lv_display_get_user_data(disp); + uint16_t *buffer = (uint16_t *) color_p; + driver->EPD_Clear(); + for (int y = area->y1; y <= area->y2; y++) { + for (int x = area->x1; x <= area->x2; x++) { + uint8_t color = (*buffer < 0x7fff) ? DRIVER_COLOR_BLACK : DRIVER_COLOR_WHITE; + driver->EPD_DrawColorPixel(x, y, color); + buffer++; + } + } + driver->EPD_DisplayPart(); + lv_disp_flush_ready(disp); +} + +CustomLcdDisplay::CustomLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, + int width, int height, int offset_x, int offset_y, + bool mirror_x, bool mirror_y, bool swap_xy, custom_lcd_spi_t _lcd_spi_data) : + LcdDisplay(panel_io, panel, width, height), + lcd_spi_data(_lcd_spi_data), + Width(width), Height(height) { + + ESP_LOGI(TAG, "Initialize SPI"); + spi_port_init(); + spi_gpio_init(); + + ESP_LOGI(TAG, "Initialize LVGL library"); + lv_init(); + + lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG(); + port_cfg.task_priority = 2; + port_cfg.timer_period_ms = 50; + lvgl_port_init(&port_cfg); + lvgl_port_lock(0); + + buffer = (uint8_t *) heap_caps_malloc(lcd_spi_data.buffer_len, MALLOC_CAP_SPIRAM); + assert(buffer); + display_ = lv_display_create(width, height); /* 以水平和垂直分辨率(像素)进行基本初始化 */ + lv_display_set_flush_cb(display_, lvgl_flush_cb); + lv_display_set_user_data(display_, this); + + uint8_t *buffer_1 = NULL; + buffer_1 = (uint8_t *) heap_caps_malloc(BUFF_SIZE, MALLOC_CAP_SPIRAM); + assert(buffer_1); + lv_display_set_buffers(display_, buffer_1, NULL, BUFF_SIZE, LV_DISPLAY_RENDER_MODE_FULL); + + ESP_LOGI(TAG, "EPD init"); + EPD_Init(); + EPD_Clear(); + EPD_Display(); + EPD_DisplayPartBaseImage(); + EPD_Init_Partial(); // 局部刷新初始化 + + lvgl_port_unlock(); + if (display_ == nullptr) { + ESP_LOGE(TAG, "Failed to add display"); + return; + } + + ESP_LOGI(TAG, "ui start"); + + SetupUI(); +} + +CustomLcdDisplay::~CustomLcdDisplay() { + +} + +void CustomLcdDisplay::spi_gpio_init() { + int rst = lcd_spi_data.rst; + int cs = lcd_spi_data.cs; + int dc = lcd_spi_data.dc; + int busy = lcd_spi_data.busy; + + gpio_config_t gpio_conf = {}; + gpio_conf.intr_type = GPIO_INTR_DISABLE; + gpio_conf.mode = GPIO_MODE_OUTPUT; + gpio_conf.pin_bit_mask = (0x1ULL << rst) | (0x1ULL << dc) | (0x1ULL << cs); + gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE; + ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf)); + + gpio_conf.mode = GPIO_MODE_INPUT; + gpio_conf.pin_bit_mask = (0x1ULL << busy); + ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf)); + + set_rst_1(); +} + +void CustomLcdDisplay::spi_port_init() { + int mosi = lcd_spi_data.mosi; + int scl = lcd_spi_data.scl; + int spi_host = lcd_spi_data.spi_host; + esp_err_t ret; + spi_bus_config_t buscfg = {}; + buscfg.miso_io_num = -1; + buscfg.mosi_io_num = mosi; + buscfg.sclk_io_num = scl; + buscfg.quadwp_io_num = -1; + buscfg.quadhd_io_num = -1; + buscfg.max_transfer_sz = Width * Height; + + spi_device_interface_config_t devcfg = {}; + devcfg.spics_io_num = -1; + devcfg.clock_speed_hz = 40 * 1000 * 1000; // Clock out at 10 MHz + devcfg.mode = 0; // SPI mode 0 + devcfg.queue_size = 7; // We want to be able to queue 7 transactions at a time + + ret = spi_bus_initialize((spi_host_device_t) spi_host, &buscfg, SPI_DMA_CH_AUTO); + ESP_ERROR_CHECK(ret); + ret = spi_bus_add_device((spi_host_device_t) spi_host, &devcfg, &spi); + ESP_ERROR_CHECK(ret); +} + +void CustomLcdDisplay::read_busy() { + int busy = lcd_spi_data.busy; + while (gpio_get_level((gpio_num_t) busy) == 1) { + vTaskDelay(pdMS_TO_TICKS(5)); // LOW: idle, HIGH: busy + } +} + +void CustomLcdDisplay::SPI_SendByte(uint8_t data) { + esp_err_t ret; + spi_transaction_t t; + memset(&t, 0, sizeof(t)); + t.length = 8; + t.tx_buffer = &data; + ret = spi_device_polling_transmit(spi, &t); // Transmit! + assert(ret == ESP_OK); // Should have had no issues. +} + +void CustomLcdDisplay::EPD_SendData(uint8_t data) { + set_dc_1(); + set_cs_0(); + SPI_SendByte(data); + set_cs_1(); +} + +void CustomLcdDisplay::EPD_SendCommand(uint8_t command) { + set_dc_0(); + set_cs_0(); + SPI_SendByte(command); + set_cs_1(); +} + +void CustomLcdDisplay::writeBytes(uint8_t *buffer, int len) { + set_dc_1(); + set_cs_0(); + esp_err_t ret; + spi_transaction_t t; + memset(&t, 0, sizeof(t)); + t.length = 8 * len; + t.tx_buffer = buffer; + ret = spi_device_polling_transmit(spi, &t); // Transmit! + assert(ret == ESP_OK); + set_cs_1(); +} + +void CustomLcdDisplay::writeBytes(const uint8_t *buffer, int len) { + set_dc_1(); + set_cs_0(); + esp_err_t ret; + spi_transaction_t t; + memset(&t, 0, sizeof(t)); + t.length = 8 * len; + t.tx_buffer = buffer; + ret = spi_device_polling_transmit(spi, &t); // Transmit! + assert(ret == ESP_OK); + set_cs_1(); +} + +void CustomLcdDisplay::EPD_SetWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend) { + EPD_SendCommand(0x44); // SET_RAM_X_ADDRESS_START_END_POSITION + EPD_SendData((Xstart >> 3) & 0xFF); + EPD_SendData((Xend >> 3) & 0xFF); + + EPD_SendCommand(0x45); // SET_RAM_Y_ADDRESS_START_END_POSITION + EPD_SendData(Ystart & 0xFF); + EPD_SendData((Ystart >> 8) & 0xFF); + EPD_SendData(Yend & 0xFF); + EPD_SendData((Yend >> 8) & 0xFF); +} + +void CustomLcdDisplay::EPD_SetCursor(uint16_t Xstart, uint16_t Ystart) { + EPD_SendCommand(0x4E); // SET_RAM_X_ADDRESS_COUNTER + EPD_SendData(Xstart & 0xFF); + + EPD_SendCommand(0x4F); // SET_RAM_Y_ADDRESS_COUNTER + EPD_SendData(Ystart & 0xFF); + EPD_SendData((Ystart >> 8) & 0xFF); +} + +void CustomLcdDisplay::EPD_SetLut(const uint8_t *lut) { + EPD_SendCommand(0x32); + writeBytes(lut, 153); + read_busy(); + + EPD_SendCommand(0x3f); + EPD_SendData(lut[153]); + + EPD_SendCommand(0x03); + EPD_SendData(lut[154]); + + EPD_SendCommand(0x04); + EPD_SendData(lut[155]); + EPD_SendData(lut[156]); + EPD_SendData(lut[157]); + + EPD_SendCommand(0x2c); + EPD_SendData(lut[158]); +} + +void CustomLcdDisplay::EPD_TurnOnDisplay() { + EPD_SendCommand(0x22); + EPD_SendData(0xc7); + EPD_SendCommand(0x20); + read_busy(); +} + +void CustomLcdDisplay::EPD_TurnOnDisplayPart() { + EPD_SendCommand(0x22); + EPD_SendData(0xcf); + EPD_SendCommand(0x20); + read_busy(); +} + +void CustomLcdDisplay::EPD_Init() { + set_rst_1(); + vTaskDelay(pdMS_TO_TICKS(50)); + set_rst_0(); + vTaskDelay(pdMS_TO_TICKS(20)); + set_rst_1(); + vTaskDelay(pdMS_TO_TICKS(50)); + + read_busy(); + EPD_SendCommand(0x12); // SWRESET + read_busy(); + + EPD_SendCommand(0x01); // Driver output control + EPD_SendData(0xC7); + EPD_SendData(0x00); + EPD_SendData(0x01); + + EPD_SendCommand(0x11); // data entry mode + EPD_SendData(0x01); + + EPD_SetWindows(0, Width - 1, Height - 1, 0); + + EPD_SendCommand(0x3C); // BorderWavefrom + EPD_SendData(0x01); + + EPD_SendCommand(0x18); + EPD_SendData(0x80); + + EPD_SendCommand(0x22); // Load Temperature and waveform setting. + EPD_SendData(0XB1); + EPD_SendCommand(0x20); + + EPD_SetCursor(0, Height - 1); + read_busy(); + + EPD_SetLut(WF_Full_1IN54); +} + +void CustomLcdDisplay::EPD_Clear() { + int buffer_len = lcd_spi_data.buffer_len; + memset(buffer, 0xff, buffer_len); +} + +void CustomLcdDisplay::EPD_Display() { + int buffer_len = lcd_spi_data.buffer_len; + EPD_SendCommand(0x24); + assert(buffer); + writeBytes(buffer, buffer_len); + EPD_TurnOnDisplay(); +} + +void CustomLcdDisplay::EPD_DisplayPartBaseImage() { + int buffer_len = lcd_spi_data.buffer_len; + EPD_SendCommand(0x24); + assert(buffer); + writeBytes(buffer, buffer_len); + EPD_SendCommand(0x26); + writeBytes(buffer, buffer_len); + EPD_TurnOnDisplay(); +} + +void CustomLcdDisplay::EPD_Init_Partial() { + set_rst_1(); + vTaskDelay(pdMS_TO_TICKS(50)); + set_rst_0(); + vTaskDelay(pdMS_TO_TICKS(20)); + set_rst_1(); + vTaskDelay(pdMS_TO_TICKS(50)); + + read_busy(); + + EPD_SetLut(WF_PARTIAL_1IN54_0); + + EPD_SendCommand(0x37); + EPD_SendData(0x00); + EPD_SendData(0x00); + EPD_SendData(0x00); + EPD_SendData(0x00); + EPD_SendData(0x00); + EPD_SendData(0x40); + EPD_SendData(0x00); + EPD_SendData(0x00); + EPD_SendData(0x00); + EPD_SendData(0x00); + + EPD_SendCommand(0x3C); // BorderWavefrom + EPD_SendData(0x80); + + EPD_SendCommand(0x22); + EPD_SendData(0xc0); + EPD_SendCommand(0x20); + read_busy(); +} + +void CustomLcdDisplay::EPD_DisplayPart() { + EPD_SendCommand(0x24); + assert(buffer); + writeBytes(buffer, 5000); + EPD_TurnOnDisplayPart(); +} + +void CustomLcdDisplay::EPD_DrawColorPixel(uint16_t x, uint16_t y, uint8_t color) { + if (x >= Width || y >= Height) { + ESP_LOGE("EPD", "Out of bounds pixel: (%d,%d)", x, y); + return; + } + + uint16_t index = y * 25 + (x >> 3); + uint8_t bit = 7 - (x & 0x07); + if (color == DRIVER_COLOR_WHITE) { + buffer[index] |= (0x01 << bit); + } else { + buffer[index] &= ~(0x01 << bit); + } +} diff --git a/main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.h b/main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.h new file mode 100644 index 00000000..7a8f03ee --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/custom_lcd_display.h @@ -0,0 +1,75 @@ +#ifndef __CUSTOM_LCD_DISPLAY_H__ +#define __CUSTOM_LCD_DISPLAY_H__ + +#include +#include "lcd_display.h" + +/* Display color */ +typedef enum { + DRIVER_COLOR_WHITE = 0xff, + DRIVER_COLOR_BLACK = 0x00, + FONT_BACKGROUND = DRIVER_COLOR_WHITE, +}COLOR_IMAGE; + +typedef struct { + uint8_t cs; + uint8_t dc; + uint8_t rst; + uint8_t busy; + uint8_t mosi; + uint8_t scl; + int spi_host; + int buffer_len; +}custom_lcd_spi_t; + + +class CustomLcdDisplay : public LcdDisplay { +public: + CustomLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, + int width, int height, int offset_x, int offset_y, + bool mirror_x, bool mirror_y, bool swap_xy,custom_lcd_spi_t _lcd_spi_data); + ~CustomLcdDisplay(); + + void EPD_Init(); /* 墨水屏初始化 */ + void EPD_Clear(); /* 清空屏幕 */ + void EPD_Display(); /* 刷buffer到墨水屏 */ + + /*快速刷新*/ + void EPD_DisplayPartBaseImage(); + void EPD_Init_Partial(); + void EPD_DisplayPart(); + void EPD_DrawColorPixel(uint16_t x, uint16_t y,uint8_t color); + +private: + const custom_lcd_spi_t lcd_spi_data; + const int Width; + const int Height; + spi_device_handle_t spi; + uint8_t *buffer = NULL; + + static void lvgl_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p); + + void spi_gpio_init(); + void spi_port_init(); + void read_busy(); + + void set_cs_1(){gpio_set_level((gpio_num_t)lcd_spi_data.cs,1);} + void set_cs_0(){gpio_set_level((gpio_num_t)lcd_spi_data.cs,0);} + void set_dc_1(){gpio_set_level((gpio_num_t)lcd_spi_data.dc,1);} + void set_dc_0(){gpio_set_level((gpio_num_t)lcd_spi_data.dc,0);} + void set_rst_1(){gpio_set_level((gpio_num_t)lcd_spi_data.rst,1);} + void set_rst_0(){gpio_set_level((gpio_num_t)lcd_spi_data.rst,0);} + + void SPI_SendByte(uint8_t data); + void EPD_SendData(uint8_t data); + void EPD_SendCommand(uint8_t command); + void writeBytes(uint8_t *buffer,int len); + void writeBytes(const uint8_t *buffer, int len); + void EPD_SetWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend); + void EPD_SetCursor(uint16_t Xstart, uint16_t Ystart); + void EPD_SetLut(const uint8_t *lut); + void EPD_TurnOnDisplay(); + void EPD_TurnOnDisplayPart(); +}; + +#endif // __CUSTOM_LCD_DISPLAY_H__ \ No newline at end of file diff --git a/main/boards/waveshare-s3-epaper-1.54/waveshare-s3-epaper-1.54.cc b/main/boards/waveshare-s3-epaper-1.54/waveshare-s3-epaper-1.54.cc new file mode 100644 index 00000000..633c7b36 --- /dev/null +++ b/main/boards/waveshare-s3-epaper-1.54/waveshare-s3-epaper-1.54.cc @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include "wifi_station.h" +#include "application.h" +#include "button.h" +#include "codecs/es8311_audio_codec.h" +#include "config.h" +#include "wifi_board.h" +#include "board_power_bsp.h" +#include "custom_lcd_display.h" +#include "lvgl.h" +#include "mcp_server.h" + +#define TAG "waveshare_epaper_1_54" + +class CustomBoard : public WifiBoard { + private: + i2c_master_bus_handle_t i2c_bus_; + Button boot_button_; + Button pwr_button_; + CustomLcdDisplay *display_; + BoardPowerBsp *power_; + adc_oneshot_unit_handle_t adc1_handle; + adc_cali_handle_t cali_handle; + + void InitializeI2c() { + i2c_master_bus_config_t i2c_bus_cfg = {}; + i2c_bus_cfg.i2c_port = (i2c_port_t) 0; + i2c_bus_cfg.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN; + i2c_bus_cfg.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN; + i2c_bus_cfg.clk_source = I2C_CLK_SRC_DEFAULT; + i2c_bus_cfg.glitch_ignore_cnt = 7; + i2c_bus_cfg.intr_priority = 0; + i2c_bus_cfg.trans_queue_depth = 0; + i2c_bus_cfg.flags.enable_internal_pullup = 1; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_)); + } + + void InitializeButtons() { + boot_button_.OnClick([this]() { + auto &app = Application::GetInstance(); + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { + ResetWifiConfiguration(); + } + app.ToggleChatState(); + }); + + pwr_button_.OnLongPress([this]() { + GetDisplay()->SetChatMessage("system", "OFF"); + vTaskDelay(pdMS_TO_TICKS(1000)); + power_->PowerAudioOff(); + power_->PowerEpdOff(); + power_->VbatPowerOff(); + }); + } + + void InitializeTools() { + auto &mcp_server = McpServer::GetInstance(); + mcp_server.AddTool("self.disp.network", "重新配网", PropertyList(), [this](const PropertyList &) -> ReturnValue { + ResetWifiConfiguration(); + return true; + }); + } + + void InitializeLcdDisplay() { + custom_lcd_spi_t lcd_spi_data = {}; + lcd_spi_data.cs = EPD_CS_PIN; + lcd_spi_data.dc = EPD_DC_PIN; + lcd_spi_data.rst = EPD_RST_PIN; + lcd_spi_data.busy = EPD_BUSY_PIN; + lcd_spi_data.mosi = EPD_MOSI_PIN; + lcd_spi_data.scl = EPD_SCK_PIN; + lcd_spi_data.spi_host = EPD_SPI_NUM; + lcd_spi_data.buffer_len = 5000; + display_ = new CustomLcdDisplay(NULL, NULL, EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY, lcd_spi_data); + } + + void Power_Init() { + power_ = new BoardPowerBsp(EPD_PWR_PIN, Audio_PWR_PIN, VBAT_PWR_PIN); + power_->VbatPowerOn(); + power_->PowerAudioOn(); + power_->PowerEpdOn(); + do { + vTaskDelay(pdMS_TO_TICKS(10)); + } while (!gpio_get_level(VBAT_PWR_GPIO)); + } + + public: + CustomBoard() : boot_button_(BOOT_BUTTON_GPIO), pwr_button_(VBAT_PWR_GPIO) { + Power_Init(); + InitializeI2c(); + InitializeButtons(); + InitializeTools(); + InitializeLcdDisplay(); + } + + virtual AudioCodec *GetAudioCodec() override { + static Es8311AudioCodec audio_codec(i2c_bus_, I2C_NUM_0, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE, AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN, AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR); + return &audio_codec; + } + + virtual Display *GetDisplay() override { + return display_; + } +}; + +DECLARE_BOARD(CustomBoard); \ No newline at end of file