Signed-off-by: kevin <kevin@lmve.net>
This commit is contained in:
+2
-2
@@ -3,8 +3,8 @@
|
||||
"idf.openOcdConfigs": [
|
||||
"board/esp32s3-builtin.cfg"
|
||||
],
|
||||
"idf.portWin": "COM9",
|
||||
"idf.currentSetup": "C:\\Users\\wuwen\\esp\\v5.5.2\\esp-idf",
|
||||
"idf.portWin": "COM10",
|
||||
"idf.currentSetup": "C:\\esp\\v5.5.3\\esp-idf",
|
||||
"idf.customExtraVars": {
|
||||
"OPENOCD_SCRIPTS": "C:\\Espressif\\tools\\openocd-esp32\\v0.11.0-esp32-20220411/openocd-esp32/share/openocd/scripts",
|
||||
"IDF_CCACHE_ENABLE": "1",
|
||||
|
||||
@@ -2,34 +2,306 @@
|
||||
|
||||
static const char *TAG = "E-PAPER";
|
||||
|
||||
void epd_gpio_init(void)
|
||||
/********************* 全局变量 *********************/
|
||||
uint8_t epd_buffer[EPD_BUFFER_SIZE] = {0}; // 显存缓冲区
|
||||
|
||||
|
||||
|
||||
// ==================== 底层硬件操作函数 ====================
|
||||
/**
|
||||
* @brief 设置引脚电平
|
||||
*/
|
||||
static void epd_set_pin_level(gpio_num_t pin, uint8_t level)
|
||||
{
|
||||
// 1. 配置CS/DC为输出模式
|
||||
gpio_config_t io_conf = {0};
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << EPD_CS_PIN) | (1ULL << EPD_DC_PIN);
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_set_level(pin, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待busy引脚释放(低电平忙,高电平空闲)
|
||||
*/
|
||||
static void epd_wait_busy(void)
|
||||
{
|
||||
uint32_t busy_cnt = 0;
|
||||
ESP_LOGD(TAG, "waiting epd busy release...");
|
||||
|
||||
while (gpio_get_level(EPD_BUSY_PIN) == 0) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
busy_cnt++;
|
||||
|
||||
// 超时保护(最大等待1000ms)
|
||||
if (busy_cnt > 100) {
|
||||
ESP_LOGE(TAG, "epd busy timeout!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 初始化gpio引脚
|
||||
*/
|
||||
static esp_err_t epd_gpio_init(void)
|
||||
{
|
||||
// 配置输出引脚:cs/dc/rst
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = (1ULL << EPD_CS_PIN) | (1ULL << EPD_DC_PIN),
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// 2. 配置BUSY为输入模式(上拉,防止电平飘移)
|
||||
// 配置输入引脚:busy(上拉)
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << EPD_BUSY_PIN);
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// 3. 初始化引脚默认电平
|
||||
gpio_set_level(EPD_CS_PIN, 1); // CS默认拉高(未选中)
|
||||
gpio_set_level(EPD_DC_PIN, 0); // DC默认拉低(指令模式)
|
||||
// 初始化默认电平
|
||||
epd_set_pin_level(EPD_CS_PIN, 1);
|
||||
epd_set_pin_level(EPD_DC_PIN, 0);
|
||||
|
||||
ESP_LOGI(TAG, "EPD GPIO init success (CS:%d, DC:%d)",
|
||||
EPD_CS_PIN, EPD_DC_PIN);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void epd_init()
|
||||
/**
|
||||
* @brief spi发送单字节
|
||||
*/
|
||||
static esp_err_t epd_spi_send_byte(uint8_t data, uint8_t is_data)
|
||||
{
|
||||
|
||||
// 控制dc引脚(0=指令,1=数据)
|
||||
epd_set_pin_level(EPD_DC_PIN, is_data);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
|
||||
// 拉低cs选中设备
|
||||
epd_set_pin_level(EPD_CS_PIN, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
|
||||
// 同步传输
|
||||
esp_err_t ret = epd_spi_send_sync_fullduplex(&data,NULL,1);
|
||||
|
||||
// 释放cs
|
||||
epd_set_pin_level(EPD_CS_PIN, 1);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "spi send byte failed: %s", esp_err_to_name(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发送指令
|
||||
*/
|
||||
static esp_err_t epd_send_cmd(uint8_t cmd)
|
||||
{
|
||||
return epd_spi_send_byte(cmd, 0); // 0=指令模式
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发送数据
|
||||
*/
|
||||
static esp_err_t epd_send_data(uint8_t data)
|
||||
{
|
||||
return epd_spi_send_byte(data, 1); // 1=数据模式
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 批量发送数据
|
||||
*/
|
||||
static esp_err_t epd_send_data_bulk(const uint8_t *data, size_t len)
|
||||
{
|
||||
if (len == 0 || data == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
||||
epd_set_pin_level(EPD_DC_PIN, 1);
|
||||
epd_set_pin_level(EPD_CS_PIN, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
|
||||
esp_err_t ret = epd_spi_send_sync_fullduplex(data,NULL,len);
|
||||
|
||||
epd_set_pin_level(EPD_CS_PIN, 1);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "spi send bulk failed: %s", esp_err_to_name(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 硬件复位
|
||||
*/
|
||||
static void epd_hw_reset(void)
|
||||
{
|
||||
// epd_set_pin_level(EPD_RST_PIN, 1);
|
||||
// vTaskDelay(pdMS_TO_TICKS(200));
|
||||
// epd_set_pin_level(EPD_RST_PIN, 0);
|
||||
// vTaskDelay(pdMS_TO_TICKS(200));
|
||||
// epd_set_pin_level(EPD_RST_PIN, 1);
|
||||
// vTaskDelay(pdMS_TO_TICKS(200));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 墨水屏软件复位(指令模拟)
|
||||
*/
|
||||
void epd_soft_reset(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "epd soft reset start");
|
||||
|
||||
// 1. 关闭电源,等待忙信号释放
|
||||
epd_send_cmd(POWER_OFF);
|
||||
epd_wait_busy();
|
||||
|
||||
// 2. 进入深度睡眠,清空内部状态
|
||||
epd_send_cmd(DEEP_SLEEP);
|
||||
epd_send_data(0xa5); // 睡眠指令必须跟0xa5
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待睡眠完成
|
||||
|
||||
|
||||
ESP_LOGI(TAG, "epd soft reset done");
|
||||
}
|
||||
|
||||
|
||||
esp_err_t epd_init()
|
||||
{
|
||||
ESP_LOGI(TAG, "init_GPIO");
|
||||
epd_gpio_init();
|
||||
esp_err_t ret = epd_gpio_init();
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
// 2. 硬件复位
|
||||
epd_hw_reset();
|
||||
epd_send_cmd(POWER_ON);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
//epd_soft_reset();
|
||||
epd_wait_busy();
|
||||
|
||||
|
||||
// 3. 发送初始化指令
|
||||
epd_send_cmd(POWER_SETTING);
|
||||
epd_send_data(0x03);
|
||||
epd_send_data(0x00);
|
||||
epd_send_data(0x2b);
|
||||
epd_send_data(0x2b);
|
||||
epd_send_data(0x09);
|
||||
|
||||
epd_send_cmd(BOOSTER_SOFT_START);
|
||||
epd_send_data(0x07);
|
||||
epd_send_data(0x07);
|
||||
epd_send_data(0x17);
|
||||
|
||||
epd_send_cmd(POWER_ON);
|
||||
epd_wait_busy();
|
||||
|
||||
epd_send_cmd(PANEL_SETTING);
|
||||
epd_send_data(0xbf); // 黑白模式
|
||||
epd_send_data(0x0d);
|
||||
|
||||
epd_send_cmd(PLL_CONTROL);
|
||||
epd_send_data(0x3c);
|
||||
|
||||
epd_send_cmd(VCOM_AND_DATA_INTERVAL_SETTING);
|
||||
epd_send_data(0x77);
|
||||
|
||||
epd_send_cmd(TCON_RESOLUTION);
|
||||
epd_send_data(EPD_WIDTH >> 8);
|
||||
epd_send_data(EPD_WIDTH & 0xff);
|
||||
epd_send_data(EPD_HEIGHT >> 8);
|
||||
epd_send_data(EPD_HEIGHT & 0xff);
|
||||
|
||||
epd_send_cmd(VCM_DC_SETTING_REGISTER);
|
||||
epd_send_data(0x12);
|
||||
|
||||
ESP_LOGI(TAG, "epd init success");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清屏(color: 0=黑,1=白)
|
||||
*/
|
||||
esp_err_t epd_clear(uint8_t color)
|
||||
{
|
||||
uint8_t fill_data = color ? 0xff : 0x00;
|
||||
memset(epd_buffer, fill_data, EPD_BUFFER_SIZE);
|
||||
|
||||
// 发送清屏数据
|
||||
epd_send_cmd(DATA_START_TRANSMISSION_1);
|
||||
ESP_LOGI(TAG, "epd clear");
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
epd_send_data_bulk(epd_buffer, EPD_BUFFER_SIZE);
|
||||
ESP_LOGI(TAG, "epd clear sended");
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
|
||||
// 刷新屏幕
|
||||
epd_send_cmd(DISPLAY_REFRESH);
|
||||
epd_wait_busy();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 画点(x:0~249, y:0~121, color:0=黑,1=白)
|
||||
*/
|
||||
void epd_draw_point(uint16_t x, uint16_t y, uint8_t color)
|
||||
{
|
||||
if (x >= EPD_WIDTH || y >= EPD_HEIGHT) {
|
||||
ESP_LOGW(TAG, "point out of range: x=%d, y=%d", x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t index = (x / 8) + y * (EPD_WIDTH / 8);
|
||||
uint8_t bit = 7 - (x % 8);
|
||||
|
||||
if (color) {
|
||||
epd_buffer[index] |= (1 << bit); // 白色置1
|
||||
} else {
|
||||
epd_buffer[index] &= ~(1 << bit); // 黑色置0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 刷新缓冲区到屏幕
|
||||
*/
|
||||
esp_err_t epd_refresh(void)
|
||||
{
|
||||
epd_send_cmd(DATA_START_TRANSMISSION_1);
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
epd_send_data_bulk(epd_buffer, EPD_BUFFER_SIZE);
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
|
||||
epd_send_cmd(DISPLAY_REFRESH);
|
||||
epd_wait_busy();
|
||||
|
||||
ESP_LOGI(TAG, "epd refresh done");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 进入深度睡眠模式(低功耗)
|
||||
*/
|
||||
void epd_sleep(void)
|
||||
{
|
||||
epd_send_cmd(POWER_OFF);
|
||||
epd_wait_busy();
|
||||
|
||||
epd_send_cmd(DEEP_SLEEP);
|
||||
epd_send_data(0xa5); // 睡眠指令必须跟0xa5
|
||||
|
||||
ESP_LOGI(TAG, "epd enter sleep mode");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取epd缓冲区指针
|
||||
*/
|
||||
uint8_t *epd_get_buffer(void)
|
||||
{
|
||||
return epd_buffer;
|
||||
}
|
||||
@@ -14,7 +14,52 @@
|
||||
#define EPD_DC_PIN 35
|
||||
#define EPD_BUSY_PIN 37
|
||||
|
||||
/********************* 屏幕参数定义 *********************/
|
||||
#define EPD_WIDTH 320 // 屏幕宽度
|
||||
#define EPD_HEIGHT 240 // 屏幕高度
|
||||
#define EPD_BUFFER_SIZE ((EPD_WIDTH * EPD_HEIGHT) / 8) // 显存大小(1bit/像素)
|
||||
|
||||
void epd_init();
|
||||
/********************* 指令集定义 *********************/
|
||||
#define PANEL_SETTING 0x00
|
||||
#define POWER_SETTING 0x01
|
||||
#define POWER_OFF 0x02
|
||||
#define POWER_OFF_SEQUENCE_SETTING 0x03
|
||||
#define POWER_ON 0x04
|
||||
#define POWER_ON_MEASURE 0x05
|
||||
#define BOOSTER_SOFT_START 0x06
|
||||
#define DEEP_SLEEP 0x07
|
||||
#define DATA_START_TRANSMISSION_1 0x10
|
||||
#define DATA_STOP 0x11
|
||||
#define DISPLAY_REFRESH 0x12
|
||||
#define DATA_START_TRANSMISSION_2 0x13
|
||||
#define PLL_CONTROL 0x30
|
||||
#define TEMPERATURE_SENSOR_COMMAND 0x40
|
||||
#define TEMPERATURE_SENSOR_CALIBRATION 0x41
|
||||
#define TEMPERATURE_SENSOR_WRITE 0x42
|
||||
#define TEMPERATURE_SENSOR_READ 0x43
|
||||
#define VCOM_AND_DATA_INTERVAL_SETTING 0x50
|
||||
#define LOW_POWER_DETECTION 0x51
|
||||
#define TCON_SETTING 0x60
|
||||
#define TCON_RESOLUTION 0x61
|
||||
#define SOURCE_AND_GATE_START_SETTING 0x62
|
||||
#define GET_STATUS 0x71
|
||||
#define AUTO_MEASURE_VCOM 0x80
|
||||
#define READ_VCOM_VALUE 0x81
|
||||
#define VCM_DC_SETTING_REGISTER 0x82
|
||||
#define PARTIAL_WINDOW 0x90
|
||||
#define PARTIAL_IN 0x91
|
||||
#define PARTIAL_OUT 0x92
|
||||
#define PROGRAM_MODE 0xA0
|
||||
#define ACTIVE_PROGRAM 0xA1
|
||||
#define READ_OTP_DATA 0xA2
|
||||
#define POWER_SAVING 0xE3
|
||||
|
||||
|
||||
esp_err_t epd_init();
|
||||
esp_err_t epd_clear(uint8_t color);
|
||||
void epd_draw_point(uint16_t x, uint16_t y, uint8_t color);
|
||||
esp_err_t epd_refresh(void);
|
||||
void epd_sleep(void);
|
||||
uint8_t *epd_get_buffer(void);
|
||||
|
||||
#endif
|
||||
@@ -59,16 +59,25 @@ void app_main(void)
|
||||
size_t internal_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
size_t internal_total = heap_caps_get_total_size(MALLOC_CAP_INTERNAL);
|
||||
|
||||
ESP_LOGI(TAG,"内部 RAM 总大小:%u KB,可用:%u KB\n", internal_total/1024, internal_free/1024);
|
||||
ESP_LOGI(TAG,"内部 RAM 总大小:%u KB,可用:%u KB", internal_total/1024, internal_free/1024);
|
||||
|
||||
// PSRAM 信息
|
||||
size_t psram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
size_t psram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
|
||||
|
||||
ESP_LOGI(TAG,"PSRAM 总大小:%u KB,可用:%u KB\n", psram_total/1024, psram_free/1024);
|
||||
ESP_LOGI(TAG,"PSRAM 总大小:%u KB,可用:%u KB", psram_total/1024, psram_free/1024);
|
||||
|
||||
spi_init();
|
||||
epd_init();
|
||||
epd_clear(1);
|
||||
// 3. 画测试点(黑色)
|
||||
epd_draw_point(50, 50, 0); // (50,50) 黑点
|
||||
epd_draw_point(50, 60, 0); // (50,60) 黑点
|
||||
epd_draw_point(60, 50, 0); // (60,50) 黑点
|
||||
epd_draw_point(60, 60, 0); // (60,60) 黑点
|
||||
|
||||
// 4. 刷新屏幕
|
||||
epd_refresh();
|
||||
|
||||
|
||||
// 1. 初始化 SPIFFS
|
||||
|
||||
@@ -18,13 +18,13 @@ void spi_init()
|
||||
.sclk_io_num = VSPI_SCLK, // 时钟引脚
|
||||
.quadwp_io_num = -1, // 不使用 QWP
|
||||
.quadhd_io_num = -1, // 不使用 QHD
|
||||
.max_transfer_sz = 4096, // 最大传输大小
|
||||
.max_transfer_sz = 9600, // 最大传输大小
|
||||
// .flags = 0,
|
||||
// .intr_flags = 0,
|
||||
};
|
||||
|
||||
// 2. 初始化 SPI 总线
|
||||
ret = spi_bus_initialize(USE_SPI_HOST, &buscfg, SPI_DMA_DISABLED);
|
||||
ret = spi_bus_initialize(USE_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "IO总线初始化失败");
|
||||
@@ -40,7 +40,7 @@ void spi_init()
|
||||
.address_bits = 0, // 无地址位
|
||||
.dummy_bits = 0,
|
||||
.mode = 0, // SPI 模式 0
|
||||
.clock_speed_hz = 80000000, //
|
||||
.clock_speed_hz = 4000000, //
|
||||
.spics_io_num = -1,
|
||||
.queue_size = 1, // 队列深度,因为有几个设备共用了这个SPI,而有的设备有busy信号,准备整个专门的线程去控制如果有busy信号先跳过这次传输
|
||||
.flags = SPI_DEVICE_NO_DUMMY, // 禁用 dummy 周期
|
||||
@@ -90,7 +90,7 @@ esp_err_t epd_spi_send_sync_fullduplex(const uint8_t *tx_data, uint8_t *rx_data,
|
||||
.length = len * 8, // 传输位数(1字节=8位,收发长度一致)
|
||||
.tx_buffer = tx_data, // 发送缓冲区(NULL则发送0x00)
|
||||
.rx_buffer = rx_data, // 接收缓冲区(NULL则丢弃接收数据)
|
||||
.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA, // 强制使用本地缓冲区
|
||||
//.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA, // 强制使用本地缓冲区
|
||||
// 全双工关键:无需额外flag,只要同时配置tx/rx_buffer即启用全双工
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
|
||||
void spi_init();
|
||||
esp_err_t epd_spi_send_sync_fullduplex(const uint8_t *tx_data, uint8_t *rx_data, size_t len);
|
||||
|
||||
extern spi_device_handle_t spi2;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file. DO NOT EDIT.
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.5.2 Project Configuration
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.5.3 Project Configuration
|
||||
#
|
||||
CONFIG_SOC_ADC_SUPPORTED=y
|
||||
CONFIG_SOC_UART_SUPPORTED=y
|
||||
@@ -370,6 +370,7 @@ CONFIG_SOC_WIFI_HW_TSF=y
|
||||
CONFIG_SOC_WIFI_FTM_SUPPORT=y
|
||||
CONFIG_SOC_WIFI_GCMP_SUPPORT=y
|
||||
CONFIG_SOC_WIFI_WAPI_SUPPORT=y
|
||||
CONFIG_SOC_WIFI_TXOP_SUPPORT=y
|
||||
CONFIG_SOC_WIFI_CSI_SUPPORT=y
|
||||
CONFIG_SOC_WIFI_MESH_SUPPORT=y
|
||||
CONFIG_SOC_WIFI_SUPPORT_VARIABLE_BEACON_WINDOW=y
|
||||
@@ -697,6 +698,7 @@ CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y
|
||||
#
|
||||
# Hardware Settings
|
||||
#
|
||||
CONFIG_ESP_HW_SUPPORT_FUNC_IN_IRAM=y
|
||||
|
||||
#
|
||||
# Chip revision
|
||||
@@ -757,6 +759,8 @@ CONFIG_RTC_CLK_SRC_INT_RC=y
|
||||
# CONFIG_RTC_CLK_SRC_EXT_OSC is not set
|
||||
# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set
|
||||
CONFIG_RTC_CLK_CAL_CYCLES=1024
|
||||
CONFIG_RTC_CLK_FUNC_IN_IRAM=y
|
||||
CONFIG_RTC_TIME_FUNC_IN_IRAM=y
|
||||
# end of RTC Clock Config
|
||||
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user