Initial commit
This commit is contained in:
56
main/boards/waveshare/esp32-c6-lcd-1.69/README.md
Normal file
56
main/boards/waveshare/esp32-c6-lcd-1.69/README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-C6-Touch-LCD-1.69](https://www.waveshare.net/shop/ESP32-C6-Touch-LCD-1.69.htm)
|
||||
[微雪电子 ESP32-C6-LCD-1.69](https://www.waveshare.net/shop/ESP32-C6-LCD-1.69.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32c6
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-C6-LCD-1.69
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
# 按键操作
|
||||
## BOOT 按键
|
||||
**未连接服务器前单击: 进入配网模式**
|
||||
**连接服务器后单击: 唤醒、打断**
|
||||
|
||||
## PWR 按键
|
||||
**双击:息屏、亮屏**
|
||||
**长按:开关机**
|
||||
54
main/boards/waveshare/esp32-c6-lcd-1.69/config.h
Normal file
54
main/boards/waveshare/esp32-c6-lcd-1.69/config.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_19
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_22
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_20
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_23
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_NC
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
#define PWR_BUTTON_GPIO GPIO_NUM_18
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#define DISPLAY_SPI_MODE 3
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_5
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_2
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_CLK_PIN GPIO_NUM_1
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_3
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_4
|
||||
|
||||
#define BATTERY_EN_PIN GPIO_NUM_15
|
||||
#define BATTERY_ADC_PIN GPIO_NUM_0
|
||||
#define BATTERY_CHARGING_PIN GPIO_NUM_NC
|
||||
|
||||
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 280
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_RGB_ORDER LCD_RGB_ELEMENT_ORDER_RGB
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 20
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_6
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
12
main/boards/waveshare/esp32-c6-lcd-1.69/config.json
Normal file
12
main/boards/waveshare/esp32-c6-lcd-1.69/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-lcd-1.69",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
262
main/boards/waveshare/esp32-c6-lcd-1.69/esp32-c6-lcd-1.69.cc
Normal file
262
main/boards/waveshare/esp32-c6-lcd-1.69/esp32-c6-lcd-1.69.cc
Normal file
@@ -0,0 +1,262 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_timer.h>
|
||||
#include "iot_button.h"
|
||||
#include "power_manager.h"
|
||||
#include "power_save_timer.h"
|
||||
|
||||
#define TAG "waveshare_lcd_1_69"
|
||||
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES * 0.1, 0);
|
||||
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES * 0.1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomButton: public Button {
|
||||
public:
|
||||
void OnPressDownDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_down_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_DOWN, nullptr);
|
||||
}
|
||||
void OnPressUpDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_up_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_UP, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
CustomButton boot_button_;
|
||||
CustomButton pwr_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
LcdDisplay* display_;
|
||||
PowerManager* power_manager_ = nullptr;
|
||||
PowerSaveTimer* power_save_timer_ = nullptr;
|
||||
|
||||
void InitializePowerManager() {
|
||||
power_manager_ = new PowerManager(BATTERY_CHARGING_PIN, BATTERY_ADC_PIN, BATTERY_EN_PIN);
|
||||
power_manager_->PowerON();
|
||||
}
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
power_manager_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = DISPLAY_MISO_PIN;
|
||||
buscfg.sclk_io_num = DISPLAY_CLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = DISPLAY_SPI_MODE;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGI(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
|
||||
display_ = new CustomLcdDisplay(
|
||||
panel_io,
|
||||
panel,
|
||||
DISPLAY_WIDTH,
|
||||
DISPLAY_HEIGHT,
|
||||
DISPLAY_OFFSET_X,
|
||||
DISPLAY_OFFSET_Y,
|
||||
DISPLAY_MIRROR_X,
|
||||
DISPLAY_MIRROR_Y,
|
||||
DISPLAY_SWAP_XY
|
||||
);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
pwr_button_.OnPressUp([this]() {
|
||||
pwr_button_.OnDoubleClick([this]() {
|
||||
static uint8_t brightness_last = 0;
|
||||
auto backlight = Board::GetInstance().GetBacklight();
|
||||
if (backlight->brightness() == 0) {
|
||||
brightness_last = 0;
|
||||
if (brightness_last == 0) {
|
||||
backlight->SetBrightness(50, true);
|
||||
} else {
|
||||
backlight->SetBrightness(brightness_last, true);
|
||||
}
|
||||
} else {
|
||||
brightness_last = backlight->brightness();
|
||||
backlight->SetBrightness(0);
|
||||
}
|
||||
});
|
||||
|
||||
pwr_button_.OnLongPress([this]() {
|
||||
// printf("Power button long press\n");
|
||||
if (power_manager_ != nullptr){
|
||||
power_manager_->PowerOff();
|
||||
}
|
||||
});
|
||||
|
||||
pwr_button_.OnPressUpDel();
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO), pwr_button_(PWR_BUTTON_GPIO) {
|
||||
InitializePowerManager();
|
||||
InitializePowerSaveTimer();
|
||||
InitializeI2c();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeButtons();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = power_manager_->IsCharging();
|
||||
discharging = power_manager_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
level = power_manager_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
174
main/boards/waveshare/esp32-c6-lcd-1.69/power_manager.h
Normal file
174
main/boards/waveshare/esp32-c6-lcd-1.69/power_manager.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
class PowerManager {
|
||||
private:
|
||||
gpio_num_t charging_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_adc_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_power_pin_ = GPIO_NUM_NC;
|
||||
adc_oneshot_unit_handle_t adc_handle_ = NULL;
|
||||
adc_cali_handle_t adc_cali_handle_ = NULL;
|
||||
adc_channel_t adc_channel_;
|
||||
bool do_calibration = false;
|
||||
|
||||
bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle) {
|
||||
adc_cali_handle_t handle = NULL;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
bool calibrated = false;
|
||||
|
||||
if (!calibrated) {
|
||||
ESP_LOGI("PowerManager", "calibration scheme version is %s", "Curve Fitting");
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.chan = channel,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
|
||||
if (ret == ESP_OK) {
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
*out_handle = handle;
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI("PowerManager", "Calibration Success");
|
||||
}
|
||||
else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
|
||||
ESP_LOGW("PowerManager", "eFuse not burnt, skip software calibration");
|
||||
}
|
||||
else {
|
||||
ESP_LOGE("PowerManager", "Invalid arg or no memory");
|
||||
}
|
||||
return calibrated;
|
||||
}
|
||||
|
||||
public:
|
||||
PowerManager(gpio_num_t charging_pin, gpio_num_t bat_adc_pin, gpio_num_t bat_power_pin)
|
||||
: charging_pin_(charging_pin), bat_adc_pin_(bat_adc_pin), bat_power_pin_(bat_power_pin) {
|
||||
// 初始化充电引脚
|
||||
if (charging_pin_ != GPIO_NUM_NC) {
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << charging_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
// 初始化电池使能引脚
|
||||
if (bat_power_pin_ != GPIO_NUM_NC) {
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << bat_power_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
// 初始化adc
|
||||
if (bat_adc_pin_ != GPIO_NUM_NC) {
|
||||
adc_oneshot_unit_init_cfg_t init_config = {};
|
||||
init_config.ulp_mode = ADC_ULP_MODE_DISABLE;
|
||||
init_config.unit_id = ADC_UNIT_1;
|
||||
|
||||
if (bat_adc_pin_ >= GPIO_NUM_0 && bat_adc_pin_ <= GPIO_NUM_6)
|
||||
adc_channel_ = (adc_channel_t)((int)bat_adc_pin_);
|
||||
else
|
||||
return;
|
||||
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle_));
|
||||
adc_oneshot_chan_cfg_t config = {};
|
||||
config.bitwidth = ADC_BITWIDTH_DEFAULT;
|
||||
config.atten = ADC_ATTEN_DB_12;
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle_, adc_channel_, &config));
|
||||
do_calibration = adc_calibration_init(init_config.unit_id, adc_channel_, config.atten, &adc_cali_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
~PowerManager() {
|
||||
if (adc_handle_) {
|
||||
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_));
|
||||
}
|
||||
}
|
||||
|
||||
int GetBatteryLevel(void) {
|
||||
int adc_raw = 0;
|
||||
int voltage_int = 0;
|
||||
const float voltage_float_threshold = 0.1f;
|
||||
float voltage_float = 0.0f;
|
||||
static float last_voltage_float = 0.0f;
|
||||
static int last_battery_level = 0;
|
||||
|
||||
if (adc_handle_ != nullptr) {
|
||||
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, adc_channel_, &adc_raw));
|
||||
if (do_calibration) {
|
||||
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle_, adc_raw, &voltage_int));
|
||||
voltage_float = (voltage_int / 1000.0f) * 3.0;
|
||||
|
||||
if (fabs(voltage_float - last_voltage_float) >= voltage_float_threshold) {
|
||||
last_voltage_float = voltage_float;
|
||||
if (voltage_float < 3.52) {
|
||||
last_battery_level = 1;
|
||||
} else if (voltage_float < 3.64) {
|
||||
last_battery_level = 20;
|
||||
} else if (voltage_float < 3.76) {
|
||||
last_battery_level = 40;
|
||||
} else if (voltage_float < 3.88) {
|
||||
last_battery_level = 60;
|
||||
} else if (voltage_float < 4.0) {
|
||||
last_battery_level = 80;
|
||||
} else {
|
||||
last_battery_level = 100;
|
||||
}
|
||||
}
|
||||
return last_battery_level;
|
||||
}
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
bool IsCharging(void) {
|
||||
if (charging_pin_ != GPIO_NUM_NC) {
|
||||
return gpio_get_level(charging_pin_) == 0 ? true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDischarging(void) {
|
||||
if (charging_pin_ != GPIO_NUM_NC) {
|
||||
return gpio_get_level(charging_pin_) == 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsChargingDone(void) {
|
||||
if (GetBatteryLevel() == 100) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PowerOff(void) {
|
||||
if (bat_power_pin_ != GPIO_NUM_NC) {
|
||||
gpio_set_level(bat_power_pin_, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void PowerON(void) {
|
||||
if (bat_power_pin_ != GPIO_NUM_NC) {
|
||||
gpio_set_level(bat_power_pin_, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
48
main/boards/waveshare/esp32-c6-touch-amoled-1.32/README.md
Normal file
48
main/boards/waveshare/esp32-c6-touch-amoled-1.32/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-C6-Touch-AMOLED-1.32](https://www.waveshare.net/shop/ESP32-C6-Touch-AMOLED-1.32.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32c6
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-C6-Touch-AMOLED-1.32
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
44
main/boards/waveshare/esp32-c6-touch-amoled-1.32/config.h
Normal file
44
main/boards/waveshare/esp32-c6-touch-amoled-1.32/config.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_3
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_6
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_23
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
|
||||
|
||||
#define LCD_CS GPIO_NUM_22
|
||||
#define LCD_PCLK GPIO_NUM_18
|
||||
#define LCD_D0 GPIO_NUM_19
|
||||
#define LCD_D1 GPIO_NUM_20
|
||||
#define LCD_D2 GPIO_NUM_10
|
||||
#define LCD_D3 GPIO_NUM_11
|
||||
#define LCD_RST GPIO_NUM_21
|
||||
|
||||
#define EXAMPLE_LCD_H_RES 466
|
||||
#define EXAMPLE_LCD_V_RES 466
|
||||
|
||||
#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
|
||||
|
||||
#define SYS_POWER_IO_PIN GPIO_NUM_2
|
||||
#define PWR_KEY_GPIO GPIO_NUM_1
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
12
main/boards/waveshare/esp32-c6-touch-amoled-1.32/config.json
Normal file
12
main/boards/waveshare/esp32-c6-touch-amoled-1.32/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-touch-amoled-1.32",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "config.h"
|
||||
#include "wifi_board.h"
|
||||
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "lvgl.h"
|
||||
#include "mcp_server.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "waveshare_c6_amoled_1_32"
|
||||
|
||||
static const sh8601_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
{0xFE, (uint8_t[]) {0x00}, 1, 0},
|
||||
{0xC4, (uint8_t[]) {0x80}, 1, 0},
|
||||
{0x3A, (uint8_t[]) {0x55}, 1, 0}, // 0x55 for RGB565, 0x77 for RGB888
|
||||
{0x35, (uint8_t[]) {0x00}, 1, 0},
|
||||
{0x53, (uint8_t[]) {0x20}, 1, 0},
|
||||
{0x51, (uint8_t[]) {0xFF}, 1, 0}, // Brightness
|
||||
{0x63, (uint8_t[]) {0xFF}, 1, 0},
|
||||
{0x2A, (uint8_t[]) {0x00, 0x06, 0x01, 0xD7}, 4, 0},
|
||||
{0x2B, (uint8_t[]) {0x00, 0x00, 0x01, 0xD1}, 4, 0},
|
||||
{0x11, (uint8_t[]) {0x00}, 0, 100},
|
||||
{0x29, (uint8_t[]) {0x00}, 0, 0},
|
||||
};
|
||||
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
private:
|
||||
esp_lcd_panel_io_handle_t io_handle_;
|
||||
|
||||
public:
|
||||
static void my_draw_event_cb(lv_event_t *e) {
|
||||
lv_area_t *area = (lv_area_t *) lv_event_get_param(e);
|
||||
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
|
||||
// Round area for better performance
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
void SetMIRROR_XY(uint8_t mirror) {
|
||||
uint32_t lcd_cmd = 0x36;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= 0x02 << 24;
|
||||
uint8_t param = mirror;
|
||||
esp_lcd_panel_io_tx_param(io_handle_, lcd_cmd, ¶m, 1);
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle, int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy) :
|
||||
SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy),
|
||||
io_handle_(io_handle) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
SetMIRROR_XY(0xC0); // Rotate 180 degrees - this is safe as it only operates on hardware
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_display_add_event_cb(display_, my_draw_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
lv_obj_invalidate(lv_screen_active());
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
Button pwr_button_;
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
CustomLcdDisplay *display_;
|
||||
lv_indev_t *touch_indev = NULL;
|
||||
i2c_master_dev_handle_t disp_touch_dev_handle = NULL;
|
||||
|
||||
void InitializeI2c() {
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {};
|
||||
i2c_bus_cfg.i2c_port = I2C_NUM_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 SetDispbacklight(uint8_t backlight) {
|
||||
uint32_t lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= 0x02 << 24;
|
||||
uint8_t param = backlight;
|
||||
esp_lcd_panel_io_tx_param(io_handle, lcd_cmd, ¶m, 1);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto &app = Application::GetInstance();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
pwr_button_.OnLongPress([this]() {
|
||||
GetDisplay()->SetChatMessage("system", "OFF");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
gpio_set_level(SYS_POWER_IO_PIN, 0);
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.data0_io_num = LCD_D0;
|
||||
buscfg.data1_io_num = LCD_D1;
|
||||
buscfg.sclk_io_num = LCD_PCLK;
|
||||
buscfg.data2_io_num = LCD_D2;
|
||||
buscfg.data3_io_num = LCD_D3;
|
||||
buscfg.max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = LCD_CS;
|
||||
io_config.dc_gpio_num = -1;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 8;
|
||||
io_config.on_color_trans_done = NULL;
|
||||
io_config.user_ctx = NULL;
|
||||
io_config.lcd_cmd_bits = 32;
|
||||
io_config.lcd_param_bits = 8;
|
||||
io_config.flags.quad_mode = true;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &io_handle));
|
||||
|
||||
sh8601_vendor_config_t vendor_config = {};
|
||||
vendor_config.init_cmds = lcd_init_cmds;
|
||||
vendor_config.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]);
|
||||
vendor_config.flags = {.use_qspi_interface = 1};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = LCD_RST;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = &vendor_config;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(io_handle, &panel_config, &panel_handle));
|
||||
esp_lcd_panel_set_gap(panel_handle, 0x06, 0x00);
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
|
||||
display_ = new CustomLcdDisplay(io_handle, panel_handle, EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.disp.setbacklight", "设置屏幕亮度", PropertyList({Property("level", kPropertyTypeInteger, 0, 255)}), [this](const PropertyList &properties) -> ReturnValue {
|
||||
int level = properties["level"].value<int>();
|
||||
ESP_LOGI("setbacklight", "%d", level);
|
||||
SetDispbacklight(level);
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.disp.network", "重新配网", PropertyList(), [this](const PropertyList &) -> ReturnValue {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void CheckPowerKeyState() {
|
||||
gpio_config_t gpio_conf = {};
|
||||
gpio_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_conf.mode = GPIO_MODE_OUTPUT;
|
||||
gpio_conf.pin_bit_mask = (0x1ULL << SYS_POWER_IO_PIN);
|
||||
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_set_level(SYS_POWER_IO_PIN, 1);
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
} while (!gpio_get_level(PWR_KEY_GPIO));
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() : boot_button_(BOOT_BUTTON_GPIO), pwr_button_(PWR_KEY_GPIO) {
|
||||
CheckPowerKeyState();
|
||||
InitializeI2c();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
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);
|
||||
49
main/boards/waveshare/esp32-c6-touch-amoled-1.43/README.md
Normal file
49
main/boards/waveshare/esp32-c6-touch-amoled-1.43/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-C6-Touch-AMOLED-1.43](https://www.waveshare.net/shop/ESP32-C6-Touch-AMOLED-1.43.htm)
|
||||
[微雪电子 ESP32-C6-Touch-AMOLED-1.43-B](https://www.waveshare.net/shop/ESP32-C6-Touch-AMOLED-1.43-B.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32c6
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-C6-Touch-AMOLED-1.43
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
49
main/boards/waveshare/esp32-c6-touch-amoled-1.43/config.h
Normal file
49
main/boards/waveshare/esp32-c6-touch-amoled-1.43/config.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE false
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_19
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_22
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_20
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_23
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_18
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_Touch_ADDRESS 0x38
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
#define PWR_BUTTON_GPIO GPIO_NUM_2
|
||||
|
||||
#define LCD_CS GPIO_NUM_10
|
||||
#define LCD_PCLK GPIO_NUM_11
|
||||
#define LCD_D0 GPIO_NUM_4
|
||||
#define LCD_D1 GPIO_NUM_5
|
||||
#define LCD_D2 GPIO_NUM_6
|
||||
#define LCD_D3 GPIO_NUM_7
|
||||
#define LCD_RST GPIO_NUM_3
|
||||
#define LCD_LIGHT (-1)
|
||||
|
||||
#define EXAMPLE_LCD_H_RES 466
|
||||
#define EXAMPLE_LCD_V_RES 466
|
||||
|
||||
#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_
|
||||
12
main/boards/waveshare/esp32-c6-touch-amoled-1.43/config.json
Normal file
12
main/boards/waveshare/esp32-c6-touch-amoled-1.43/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-touch-amoled-1.43",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
#include "wifi_board.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
#include "mcp_server.h"
|
||||
#include "lvgl.h"
|
||||
|
||||
#define TAG "waveshare_c6_amoled_1_43"
|
||||
|
||||
static const sh8601_lcd_init_cmd_t lcd_init_cmds[] =
|
||||
{
|
||||
{0x11, (uint8_t []){0x00}, 0, 80},
|
||||
{0xC4, (uint8_t []){0x80}, 1, 0},
|
||||
{0x53, (uint8_t []){0x20}, 1, 1},
|
||||
{0x63, (uint8_t []){0xFF}, 1, 1},
|
||||
{0x51, (uint8_t []){0x00}, 1, 1},
|
||||
{0x29, (uint8_t []){0x00}, 0, 10},
|
||||
{0x51, (uint8_t []){0xFF}, 1, 0},
|
||||
};
|
||||
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
static void MyDrawEventCb(lv_event_t *e) {
|
||||
lv_area_t *area = (lv_area_t *)lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
// round the start of coordinate down to the nearest 2M number
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
// round the end of coordinate up to the nearest 2N+1 number
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_display_add_event_cb(display_, MyDrawEventCb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
Button pwr_button_;
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
CustomLcdDisplay* display_;
|
||||
i2c_master_dev_handle_t disp_touch_dev_handle = NULL;
|
||||
lv_indev_t *touch_indev = NULL; //touch
|
||||
uint8_t pwr_flag = 0;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeTca9554(void) {
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_7 | IO_EXPANDER_PIN_NUM_6, IO_EXPANDER_OUTPUT);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_7 | IO_EXPANDER_PIN_NUM_6, 1);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {
|
||||
.data0_io_num = LCD_D0,
|
||||
.data1_io_num = LCD_D1,
|
||||
.sclk_io_num = LCD_PCLK,
|
||||
.data2_io_num = LCD_D2,
|
||||
.data3_io_num = LCD_D3,
|
||||
.max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(uint16_t),
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
const esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.cs_gpio_num = LCD_CS,
|
||||
.dc_gpio_num = -1,
|
||||
.spi_mode = 0,
|
||||
.pclk_hz = 40 * 1000 * 1000,
|
||||
.trans_queue_depth = 4,
|
||||
.on_color_trans_done = NULL,
|
||||
.user_ctx = NULL,
|
||||
.lcd_cmd_bits = 32,
|
||||
.lcd_param_bits = 8,
|
||||
.flags = {
|
||||
.quad_mode = true,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &io_handle));
|
||||
sh8601_vendor_config_t vendor_config = {
|
||||
.init_cmds = lcd_init_cmds, // Uncomment these line if use custom initialization commands
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]), // sizeof(axs15231b_lcd_init_cmd_t),
|
||||
.flags =
|
||||
{
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
|
||||
.bits_per_pixel = 16, // Implemented by LCD command `3Ah` (16/18)
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(io_handle, &panel_config, &panel_handle));
|
||||
esp_lcd_panel_set_gap(panel_handle,0x06,0x00);
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
display_ = new CustomLcdDisplay(io_handle, panel_handle,
|
||||
EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeButtons() { //接入锂电池时,可长按PWR开机/关机
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
boot_button_.OnPressDown([this]() {
|
||||
Application::GetInstance().StartListening();
|
||||
});
|
||||
|
||||
boot_button_.OnPressUp([this]() {
|
||||
Application::GetInstance().StopListening();
|
||||
});
|
||||
|
||||
pwr_button_.OnLongPress([this]() {
|
||||
if(pwr_flag == 1)
|
||||
{
|
||||
pwr_flag = 0;
|
||||
esp_err_t ret;
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_6, 0);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
});
|
||||
|
||||
pwr_button_.OnPressUp([this]() {
|
||||
if(pwr_flag == 0)
|
||||
{
|
||||
pwr_flag = 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
i2c_device_config_t dev_cfg =
|
||||
{
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = I2C_Touch_ADDRESS,
|
||||
.scl_speed_hz = 300000,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_, &dev_cfg, &disp_touch_dev_handle));
|
||||
|
||||
touch_indev = lv_indev_create();
|
||||
lv_indev_set_type(touch_indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(touch_indev, TouchInputReadCallback);
|
||||
lv_indev_set_user_data(touch_indev, disp_touch_dev_handle);
|
||||
}
|
||||
|
||||
static void TouchInputReadCallback(lv_indev_t * indev, lv_indev_data_t *indevData)
|
||||
{
|
||||
i2c_master_dev_handle_t i2c_dev = (i2c_master_dev_handle_t)lv_indev_get_user_data(indev);
|
||||
uint8_t cmd = 0x02;
|
||||
uint8_t buf[5] = {0};
|
||||
uint16_t tp_x,tp_y;
|
||||
i2c_master_transmit_receive(i2c_dev,&cmd,1,buf,5,1000);
|
||||
if(buf[0])
|
||||
{
|
||||
tp_x = (((uint16_t)buf[1] & 0x0f)<<8) | (uint16_t)buf[2];
|
||||
tp_y = (((uint16_t)buf[3] & 0x0f)<<8) | (uint16_t)buf[4];
|
||||
if(tp_x > EXAMPLE_LCD_H_RES)
|
||||
{tp_x = EXAMPLE_LCD_H_RES;}
|
||||
if(tp_y > EXAMPLE_LCD_V_RES)
|
||||
{tp_y = EXAMPLE_LCD_V_RES;}
|
||||
indevData->point.x = tp_x;
|
||||
indevData->point.y = tp_y;
|
||||
//ESP_LOGI("tp","(%ld,%ld)",indevData->point.x,indevData->point.y);
|
||||
indevData->state = LV_INDEV_STATE_PRESSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
indevData->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeTools()
|
||||
{
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.disp.setbacklight", "设置屏幕亮度", PropertyList({
|
||||
Property("level", kPropertyTypeInteger, 0, 255)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int level = properties["level"].value<int>();
|
||||
ESP_LOGI("setbacklight","%d",level);
|
||||
SetDispbacklight(level);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void SetDispbacklight(uint8_t backlight) {
|
||||
uint32_t lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= 0x02 << 24;
|
||||
uint8_t param = backlight;
|
||||
esp_lcd_panel_io_tx_param(io_handle, lcd_cmd, ¶m,1);
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO),pwr_button_(PWR_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
InitializeTca9554();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
@@ -0,0 +1,4 @@
|
||||
# Waveshare ESP32-C6-Touch-AMOLED-1.8
|
||||
|
||||
|
||||
[ESP32-C6-Touch-AMOLED-1.8](https://www.waveshare.com/esp32-c6-touch-amoled-1.8.htm) ESP32-C6-Touch-AMOLED-1.8 is a high-performance, highly integrated microcontroller development board designed by Waveshare. Tiny size with onboard 1.8inch capacitive AMOLED display, highly integrated power management IC, 6-axis IMU (3-axis accelerometer and 3-axis gyroscope), RTC, low power audio codec IC, and so on, which makes it easy for you to develop and integrate it into the products quickly.
|
||||
41
main/boards/waveshare/esp32-c6-touch-amoled-1.8/config.h
Normal file
41
main/boards/waveshare/esp32-c6-touch-amoled-1.8/config.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_19
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_22
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_20
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_23
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
|
||||
#define EXAMPLE_PIN_NUM_LCD_CS GPIO_NUM_5
|
||||
#define EXAMPLE_PIN_NUM_LCD_PCLK GPIO_NUM_0
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA0 GPIO_NUM_1
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA1 GPIO_NUM_2
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA2 GPIO_NUM_3
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA3 GPIO_NUM_4
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST GPIO_NUM_NC
|
||||
#define DISPLAY_WIDTH 368
|
||||
#define DISPLAY_HEIGHT 448
|
||||
#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
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
12
main/boards/waveshare/esp32-c6-touch-amoled-1.8/config.json
Normal file
12
main/boards/waveshare/esp32-c6-touch-amoled-1.8/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-touch-amoled-1.8",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "axp2101.h"
|
||||
#include "i2c_device.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lcd_touch_ft5x06.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32c6TouchAMOLED1inch8"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
WriteReg(0x93, (3300 - 500) / 100);
|
||||
|
||||
WriteReg(0x90, 0x03);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
};
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x03ULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
static const sh8601_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
{0x11, (uint8_t[]){0x00}, 0, 120},
|
||||
{0x44, (uint8_t[]){0x01, 0xD1}, 2, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x53, (uint8_t[]){0x20}, 1, 10},
|
||||
{0x2A, (uint8_t[]){0x00, 0x00, 0x01, 0x6F}, 4, 0},
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0xBF}, 4, 0},
|
||||
{0x51, (uint8_t[]){0x00}, 1, 10},
|
||||
{0x29, (uint8_t[]){0x00}, 0, 10}
|
||||
};
|
||||
|
||||
// 在waveshare_amoled_1_8类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES * 0.1, 0);
|
||||
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES * 0.1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_lcd_panel_io_handle_t panel_io) : Backlight(), panel_io_(panel_io) {}
|
||||
|
||||
protected:
|
||||
esp_lcd_panel_io_handle_t panel_io_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
DisplayLockGuard lock(display);
|
||||
uint8_t data[1] = {((uint8_t)((255 * brightness) / 100))};
|
||||
int lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
esp_lcd_panel_io_tx_param(panel_io_, lcd_cmd, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32c6TouchAMOLED1inch8 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t codec_i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay* display_;
|
||||
CustomBacklight* backlight_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness();
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
pmic_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &codec_i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeTca9554(void) {
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(codec_i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_5 |IO_EXPANDER_PIN_NUM_7, IO_EXPANDER_OUTPUT);
|
||||
ret |= esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_3, IO_EXPANDER_INPUT);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_5 |IO_EXPANDER_PIN_NUM_7, 1);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_5 |IO_EXPANDER_PIN_NUM_7, 0);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_5 |IO_EXPANDER_PIN_NUM_7, 1);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(codec_i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = EXAMPLE_PIN_NUM_LCD_PCLK;
|
||||
buscfg.data0_io_num = EXAMPLE_PIN_NUM_LCD_DATA0;
|
||||
buscfg.data1_io_num = EXAMPLE_PIN_NUM_LCD_DATA1;
|
||||
buscfg.data2_io_num = EXAMPLE_PIN_NUM_LCD_DATA2;
|
||||
buscfg.data3_io_num = EXAMPLE_PIN_NUM_LCD_DATA3;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
buscfg.flags = SPICOMMON_BUSFLAG_QUAD;
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeSH8601Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = SH8601_PANEL_IO_QSPI_CONFIG(
|
||||
EXAMPLE_PIN_NUM_LCD_CS,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
const sh8601_vendor_config_t vendor_config = {
|
||||
.init_cmds = &vendor_specific_init[0],
|
||||
.init_cmds_size = sizeof(vendor_specific_init) / sizeof(sh8601_lcd_init_cmd_t),
|
||||
.flags ={
|
||||
.use_qspi_interface = 1,
|
||||
}
|
||||
};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.flags.reset_active_high = 1,
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void *)&vendor_config;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(panel_io, &panel_config, &panel));
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, false);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
display_ = new CustomLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(panel_io);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeTouch()
|
||||
{
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = GPIO_NUM_NC,
|
||||
.int_gpio_num = GPIO_NUM_15,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(codec_i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32c6TouchAMOLED1inch8() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
InitializeTca9554();
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeSH8601Display();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(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_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
return backlight_;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32c6TouchAMOLED1inch8);
|
||||
@@ -0,0 +1,4 @@
|
||||
# Waveshare ESP32-C6-Touch-AMOLED-2.06
|
||||
|
||||
|
||||
[ESP32-C6-Touch-AMOLED-2.06](https://www.waveshare.com/esp32-c6-touch-amoled-2.06.htm) is a high-performance wearable watch-shaped development board launched by Waveshare. This product is based on the ESP32-C6 microcontroller and integrates a 2.06-inch capacitive touch high-definition AMOLED screen, a six-axis sensor, RTC, audio codec chip, and power management, among other functional modules. With a custom case, its appearance is consistent with that of a smartwatch, and it is specifically designed for prototype development and functional verification of wearable applications.
|
||||
46
main/boards/waveshare/esp32-c6-touch-amoled-2.06/config.h
Normal file
46
main/boards/waveshare/esp32-c6-touch-amoled-2.06/config.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE false
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_19
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_22
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_20
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_23
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_6
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
|
||||
#define EXAMPLE_PIN_NUM_LCD_CS GPIO_NUM_5
|
||||
#define EXAMPLE_PIN_NUM_LCD_PCLK GPIO_NUM_0
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA0 GPIO_NUM_1
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA1 GPIO_NUM_2
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA2 GPIO_NUM_3
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA3 GPIO_NUM_4
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST GPIO_NUM_11
|
||||
|
||||
#define DISPLAY_WIDTH 410
|
||||
#define DISPLAY_HEIGHT 502
|
||||
|
||||
#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
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
12
main/boards/waveshare/esp32-c6-touch-amoled-2.06/config.json
Normal file
12
main/boards/waveshare/esp32-c6-touch-amoled-2.06/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-touch-amoled-2.06",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "axp2101.h"
|
||||
#include "i2c_device.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32c6TouchAMOLED2inch06"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
WriteReg(0x93, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1(MIC)
|
||||
WriteReg(0x90, 0x03);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x0A); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
};
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x03ULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
static const sh8601_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
// set display to qspi mode
|
||||
{0x11, (uint8_t []){0x00}, 0, 120},
|
||||
{0xC4, (uint8_t []){0x80}, 1, 0},
|
||||
{0x44, (uint8_t []){0x01, 0xD1}, 2, 0},
|
||||
{0x35, (uint8_t []){0x00}, 1, 0},
|
||||
{0x53, (uint8_t []){0x20}, 1, 10},
|
||||
{0x63, (uint8_t []){0xFF}, 1, 10},
|
||||
{0x51, (uint8_t []){0x00}, 1, 10},
|
||||
{0x2A, (uint8_t []){0x00,0x16,0x01,0xAF}, 4, 0},
|
||||
{0x2B, (uint8_t []){0x00,0x00,0x01,0xF5}, 4, 0},
|
||||
{0x29, (uint8_t []){0x00}, 0, 10},
|
||||
{0x51, (uint8_t []){0xFF}, 1, 0},
|
||||
};
|
||||
|
||||
// 在waveshare_amoled_2_06类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
static void rounder_event_cb(lv_event_t* e) {
|
||||
lv_area_t* area = (lv_area_t* )lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
|
||||
// round the start of coordinate down to the nearest 2M number
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
// round the end of coordinate up to the nearest 2N+1 number
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES* 0.1, 0);
|
||||
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES* 0.1, 0);
|
||||
lv_display_add_event_cb(display_, rounder_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_lcd_panel_io_handle_t panel_io) : Backlight(), panel_io_(panel_io) {}
|
||||
|
||||
protected:
|
||||
esp_lcd_panel_io_handle_t panel_io_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
DisplayLockGuard lock(display);
|
||||
uint8_t data[1] = {((uint8_t)((255* brightness) / 100))};
|
||||
int lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
esp_lcd_panel_io_tx_param(panel_io_, lcd_cmd, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32c6TouchAMOLED2inch06 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay* display_;
|
||||
CustomBacklight* backlight_;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20); });
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness(); });
|
||||
power_save_timer_->OnShutdownRequest([this](){
|
||||
pmic_->PowerOff(); });
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = EXAMPLE_PIN_NUM_LCD_PCLK;
|
||||
buscfg.data0_io_num = EXAMPLE_PIN_NUM_LCD_DATA0;
|
||||
buscfg.data1_io_num = EXAMPLE_PIN_NUM_LCD_DATA1;
|
||||
buscfg.data2_io_num = EXAMPLE_PIN_NUM_LCD_DATA2;
|
||||
buscfg.data3_io_num = EXAMPLE_PIN_NUM_LCD_DATA3;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH* DISPLAY_HEIGHT* sizeof(uint16_t);
|
||||
buscfg.flags = SPICOMMON_BUSFLAG_QUAD;
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
boot_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeSH8601Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = SH8601_PANEL_IO_QSPI_CONFIG(
|
||||
EXAMPLE_PIN_NUM_LCD_CS,
|
||||
nullptr,
|
||||
nullptr);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
const sh8601_vendor_config_t vendor_config = {
|
||||
.init_cmds = &vendor_specific_init[0],
|
||||
.init_cmds_size = sizeof(vendor_specific_init) / sizeof(sh8601_lcd_init_cmd_t),
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
}};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void* )&vendor_config;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(panel_io, &panel_config, &panel));
|
||||
esp_lcd_panel_set_gap(panel, 0x16, 0);
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, false);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
display_ = new CustomLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(panel_io);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32c6TouchAMOLED2inch06() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeSH8601Display();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
return backlight_;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool &charging, bool &discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging)
|
||||
{
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32c6TouchAMOLED2inch06);
|
||||
48
main/boards/waveshare/esp32-c6-touch-amoled-2.16/README.md
Normal file
48
main/boards/waveshare/esp32-c6-touch-amoled-2.16/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-C6-Touch-AMOLED-2.16](https://www.waveshare.net/shop/ESP32-C6-Touch-AMOLED-2.16.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32c6
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-C6-Touch-AMOLED-2.16
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
46
main/boards/waveshare/esp32-c6-touch-amoled-2.16/config.h
Normal file
46
main/boards/waveshare/esp32-c6-touch-amoled-2.16/config.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE false
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_19
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_22
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_20
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_23
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
|
||||
|
||||
#define LCD_CS GPIO_NUM_15
|
||||
#define LCD_PCLK GPIO_NUM_0
|
||||
#define LCD_D0 GPIO_NUM_1
|
||||
#define LCD_D1 GPIO_NUM_2
|
||||
#define LCD_D2 GPIO_NUM_3
|
||||
#define LCD_D3 GPIO_NUM_4
|
||||
#define LCD_RST GPIO_NUM_NC
|
||||
|
||||
#define TP_RST_GPIO GPIO_NUM_11
|
||||
#define TP_INT_GPIO GPIO_NUM_5
|
||||
|
||||
#define LCD_H_RES 480
|
||||
#define LCD_V_RES 480
|
||||
|
||||
#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_
|
||||
14
main/boards/waveshare/esp32-c6-touch-amoled-2.16/config.json
Normal file
14
main/boards/waveshare/esp32-c6-touch-amoled-2.16/config.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-touch-amoled-2.16",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y",
|
||||
"CONFIG_USE_DEFAULT_MESSAGE_STYLE=y",
|
||||
"CONFIG_USE_MULTILINE_CHAT_MESSAGE=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "wifi_board.h"
|
||||
|
||||
#include "application.h"
|
||||
#include "axp2101.h"
|
||||
#include "button.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "config.h"
|
||||
#include "i2c_device.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "power_save_timer.h"
|
||||
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <esp_partition.h>
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lcd_touch_cst9217.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32c6TouchAMOLED2inch16"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
WriteReg(0x93, (3300 - 500) / 100);
|
||||
WriteReg(0x94, (3300 - 500) / 100);
|
||||
WriteReg(0x95, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1(MIC)
|
||||
WriteReg(0x90, 0x0F);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x0A); // set Main battery charger current to 400mA ( 0x08-200mA,
|
||||
// 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
|
||||
void Pmic_SetAldo3(bool enable) {
|
||||
uint8_t reg = ReadReg(0x90);
|
||||
if (enable) {
|
||||
reg |= 0x04;
|
||||
} else {
|
||||
reg &= ~0x04;
|
||||
}
|
||||
WriteReg(0x90, reg);
|
||||
}
|
||||
|
||||
void Pmic_SetAldo2(bool enable) {
|
||||
uint8_t reg = ReadReg(0x90);
|
||||
if (enable) {
|
||||
reg |= 0x02;
|
||||
} else {
|
||||
reg &= ~0x02;
|
||||
}
|
||||
WriteReg(0x90, reg);
|
||||
}
|
||||
};
|
||||
|
||||
static const sh8601_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
{0x11, (uint8_t[]){0x00}, 0, 120},
|
||||
{0xC4, (uint8_t[]){0x80}, 1, 0},
|
||||
{0x44, (uint8_t[]){0x01, 0xD1}, 2, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x36, (uint8_t[]){0xA0}, 1, 0},
|
||||
{0x53, (uint8_t[]){0x20}, 1, 10},
|
||||
{0x63, (uint8_t[]){0xFF}, 1, 10},
|
||||
{0x51, (uint8_t[]){0x00}, 1, 10},
|
||||
{0x2A, (uint8_t[]){0x00, 0x16, 0x01, 0xAF}, 4, 0},
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0xF5}, 4, 0},
|
||||
{0x29, (uint8_t[]){0x00}, 0, 10},
|
||||
{0x51, (uint8_t[]){0xFF}, 1, 0},
|
||||
};
|
||||
|
||||
// 在waveshare_amoled_2_16类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
static void rounder_event_cb(lv_event_t* e) {
|
||||
lv_area_t* area = (lv_area_t*)lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
|
||||
// round the start of coordinate down to the nearest 2M number
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
// round the end of coordinate up to the nearest 2N+1 number
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle,
|
||||
int width, int height, int offset_x, int offset_y, bool mirror_x,
|
||||
bool mirror_y, bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x,
|
||||
mirror_y, swap_xy) {}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(top_bar_, 60, 0);
|
||||
lv_obj_set_style_pad_right(top_bar_, 60, 0);
|
||||
lv_display_add_event_cb(display_, rounder_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_lcd_panel_io_handle_t panel_io) : Backlight(), panel_io_(panel_io) {}
|
||||
|
||||
protected:
|
||||
esp_lcd_panel_io_handle_t panel_io_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
DisplayLockGuard lock(display);
|
||||
uint8_t data[1] = {((uint8_t)((255 * brightness) / 100))};
|
||||
int lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= 0x02UL << 24;
|
||||
esp_lcd_panel_io_tx_param(panel_io_, lcd_cmd, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32c6TouchAMOLED2inch16 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay* display_;
|
||||
CustomBacklight* backlight_;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 120, 1200);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness();
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() { pmic_->PowerOff(); });
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.flags =
|
||||
{
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = LCD_PCLK;
|
||||
buscfg.data0_io_num = LCD_D0;
|
||||
buscfg.data1_io_num = LCD_D1;
|
||||
buscfg.data2_io_num = LCD_D2;
|
||||
buscfg.data3_io_num = LCD_D3;
|
||||
buscfg.max_transfer_sz = LCD_H_RES * LCD_V_RES * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
int DisplayPort_DispReset() {
|
||||
pmic_->Pmic_SetAldo3(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
pmic_->Pmic_SetAldo3(0);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
pmic_->Pmic_SetAldo3(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InitializeSH8601Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config =
|
||||
SH8601_PANEL_IO_QSPI_CONFIG(LCD_CS, nullptr, nullptr);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
const sh8601_vendor_config_t vendor_config = {
|
||||
.init_cmds = &vendor_specific_init[0],
|
||||
.init_cmds_size = sizeof(vendor_specific_init) / sizeof(sh8601_lcd_init_cmd_t),
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
}};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = LCD_RST;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void*)&vendor_config;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(DisplayPort_DispReset());
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
display_ = new CustomLcdDisplay(panel_io, panel, LCD_H_RES, LCD_V_RES, DISPLAY_OFFSET_X,
|
||||
DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y,
|
||||
DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(panel_io);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = LCD_H_RES - 1,
|
||||
.y_max = LCD_V_RES - 1,
|
||||
.rst_gpio_num = TP_RST_GPIO,
|
||||
.int_gpio_num = TP_INT_GPIO,
|
||||
.levels =
|
||||
{
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags =
|
||||
{
|
||||
.swap_xy = 1,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 1,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST9217_CONFIG();
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_cst9217(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32c6TouchAMOLED2inch16() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeSH8601Display();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_, 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, AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override { return display_; }
|
||||
|
||||
virtual Backlight* GetBacklight() override { return backlight_; }
|
||||
|
||||
virtual bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32c6TouchAMOLED2inch16);
|
||||
49
main/boards/waveshare/esp32-c6-touch-lcd-1.83/README.md
Normal file
49
main/boards/waveshare/esp32-c6-touch-lcd-1.83/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
# 产品链接
|
||||
微雪电子 ESP32-C6-Touch-LCD-1.83
|
||||
|
||||
(https://www.waveshare.net/shop/ESP32-C6-Touch-LCD-1.83.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32c6
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-C6-Touch-LCD-1.83
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
50
main/boards/waveshare/esp32-c6-touch-lcd-1.83/config.h
Normal file
50
main/boards/waveshare/esp32-c6-touch-lcd-1.83/config.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_19
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_22
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_20
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_23
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_0
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
#define PWR_BUTTON_GPIO GPIO_NUM_18
|
||||
|
||||
#define DISPLAY_SPI_MODE SPI2_HOST
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_5
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_2
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_CLK_PIN GPIO_NUM_1
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_3
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_4
|
||||
|
||||
#define DISPLAY_TOUCH_INT_PIN GPIO_NUM_11
|
||||
#define DISPLAY_TOUCH_RST_PIN GPIO_NUM_NC
|
||||
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 284
|
||||
#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
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_6
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
13
main/boards/waveshare/esp32-c6-touch-lcd-1.83/config.json
Normal file
13
main/boards/waveshare/esp32-c6-touch-lcd-1.83/config.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-touch-lcd-1.83",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "axp2101.h"
|
||||
#include "i2c_device.h"
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lcd_touch_cst816s.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32c6TouchLCD1inch83"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1(MIC)
|
||||
WriteReg(0x90, 0x01);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32c6TouchLCD1inch83 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
Display* display_;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20); });
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness(); });
|
||||
power_save_timer_->OnShutdownRequest([this](){
|
||||
pmic_->PowerOff(); });
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = DISPLAY_CLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH* DISPLAY_HEIGHT* sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(DISPLAY_SPI_MODE, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
boot_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = 24 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(DISPLAY_SPI_MODE, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, true);
|
||||
// esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH - 1,
|
||||
.y_max = DISPLAY_HEIGHT - 1,
|
||||
.rst_gpio_num = DISPLAY_TOUCH_RST_PIN,
|
||||
.int_gpio_num = DISPLAY_TOUCH_INT_PIN,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS,
|
||||
.on_color_trans_done = 0,
|
||||
.user_ctx = 0,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 0,
|
||||
.flags =
|
||||
{
|
||||
.dc_low_on_data = 0,
|
||||
.disable_control_phase = 1,
|
||||
},
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400* 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"Reboot the device and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32c6TouchLCD1inch83() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeDisplay();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool &charging, bool &discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging)
|
||||
{
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32c6TouchLCD1inch83);
|
||||
43
main/boards/waveshare/esp32-p4-nano/README.md
Normal file
43
main/boards/waveshare/esp32-p4-nano/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Waveshare ESP32-P4-NANO
|
||||
|
||||
|
||||
[ESP32-P4-NANO](https://www.waveshare.com/esp32-p4-nano.htm) is a small size and highly integrated development board designed by waveshare electronics based on ESP32-P4 chip
|
||||
|
||||
|
||||
|
||||
## Display Page
|
||||
|
||||
|
||||
### Recommended display screen
|
||||
|
||||
| Product ID | Dependency | tested |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|--------|
|
||||
| [10.1-DSI-TOUCH-A](https://www.waveshare.com/10.1-dsi-touch-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/10.1-dsi-touch-a-1.jpg"> | [waveshare/esp_lcd_jd9365_10_1](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_jd9365_10_1) | ✅ |
|
||||
| [101M-8001280-IPS-CT-K](https://www.waveshare.com/101m-8001280-ips-ct-k.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/101m-8001280-ips-ct-k-1.jpg"> | [waveshare/esp_lcd_jd9365_10_1](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_jd9365_10_1) | ✅ |
|
||||
|
||||
### Common Raspberry adapter screen
|
||||
|
||||
**These displays are supported on [ESP32-P4-NANO BSP](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/bsp/esp32_p4_nano), but not on xiaozhi-esp32**
|
||||
|
||||
<details open>
|
||||
<summary>View full display</summary>
|
||||
|
||||
| Product ID | Dependency | tested |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|--------|
|
||||
| [2.8inch DSI LCD](https://www.waveshare.com/2.8inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/thumbnail/122x122/9df78eab33525d08d6e5fb8d27136e95/2/_/2.8inch-dsi-lcd-3.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [3.4inch DSI LCD (C)](https://www.waveshare.com/3.4inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/3/_/3.4inch-dsi-lcd-c-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [4inch DSI LCD (C)](https://www.waveshare.com/4inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/4/i/4inch-dsi-lcd-c-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [4inch DSI LCD](https://www.waveshare.com/4inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/4/i/4inch-dsi-lcd-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [5inch DSI LCD (D)](https://www.waveshare.com/5inch-dsi-lcd-d.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/5/i/5inch-dsi-lcd-d-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [6.25inch DSI LCD](https://www.waveshare.com/6.25inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/6/_/6.25inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [5inch DSI LCD (C)](https://www.waveshare.com/5inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/5/i/5inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [7inch DSI LCD (C)](https://www.waveshare.com/7inch-dsi-lcd-c-with-case-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/i/7inch-dsi-lcd-c-4.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [7.9inch DSI LCD](https://www.waveshare.com/7.9inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/_/7.9inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [7inch DSI LCD (E)](https://www.waveshare.com/7inch-dsi-lcd-e.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/i/7inch-dsi-lcd-e-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [8inch DSI LCD (C)](https://www.waveshare.com/8inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/8/i/8inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [10.1inch DSI LCD (C)](https://www.waveshare.com/10.1inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/10.1inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [8.8inch DSI LCD](https://www.waveshare.com/8.8inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/8/_/8.8inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [11.9inch DSI LCD](https://www.waveshare.com/11.9inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/1/11.9inch-dsi-lcd-3.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
|
||||
| [7-DSI-TOUCH-A](https://www.waveshare.com/7-dsi-touch-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/-/7-dsi-touch-a-1.jpg"> | [waveshare/esp_lcd_ili9881c](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_ili9881c) | 🕒 |
|
||||
|
||||
</details>
|
||||
44
main/boards/waveshare/esp32-p4-nano/config.h
Normal file
44
main/boards/waveshare/esp32-p4-nano/config.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_12
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_9
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_53
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_35
|
||||
|
||||
#define DISPLAY_WIDTH 800
|
||||
#define DISPLAY_HEIGHT 1280
|
||||
|
||||
#define LCD_BIT_PER_PIXEL (16)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_NC
|
||||
|
||||
#define DELAY_TIME_MS (3000)
|
||||
#define LCD_MIPI_DSI_LANE_NUM (2) // 2 data lanes
|
||||
|
||||
#define MIPI_DSI_PHY_PWR_LDO_CHAN (3)
|
||||
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
16
main/boards/waveshare/esp32-p4-nano/config.json
Normal file
16
main/boards/waveshare/esp32-p4-nano/config.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32p4",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-p4-nano-10.1-a",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
284
main/boards/waveshare/esp32-p4-nano/esp32-p4-nano.cc
Normal file
284
main/boards/waveshare/esp32-p4-nano/esp32-p4-nano.cc
Normal file
@@ -0,0 +1,284 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "display/lcd_display.h"
|
||||
// #include "display/no_display.h"
|
||||
#include "button.h"
|
||||
|
||||
#include "esp_video.h"
|
||||
#include "esp_video_init.h"
|
||||
#include "esp_cam_sensor_xclk.h"
|
||||
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_mipi_dsi.h"
|
||||
#include "esp_ldo_regulator.h"
|
||||
|
||||
#include "esp_lcd_mipi_dsi.h"
|
||||
#include "esp_lcd_jd9365.h"
|
||||
#include "lcd_init_cmds.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include "esp_lcd_touch_gt911.h"
|
||||
#define TAG "WaveshareEsp32p4nano"
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(i2c_master_bus_handle_t i2c_handle)
|
||||
: Backlight(), i2c_handle_(i2c_handle) {}
|
||||
|
||||
protected:
|
||||
i2c_master_bus_handle_t i2c_handle_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
uint8_t i2c_address = 0x45; // 7-bit address
|
||||
uint8_t reg = 0x96;
|
||||
uint8_t data[2] = {reg, brightness};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = i2c_address,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
esp_err_t err = i2c_master_bus_add_device(i2c_handle_, &dev_cfg, &dev_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to add I2C device: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
err = i2c_master_transmit(dev_handle, data, sizeof(data), -1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to transmit brightness: %s", esp_err_to_name(err));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Backlight brightness set to %u", brightness);
|
||||
}
|
||||
|
||||
// i2c_master_bus_rm_device(dev_handle);
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32p4nano : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t codec_i2c_bus_;
|
||||
Button boot_button_;
|
||||
LcdDisplay *display__;
|
||||
EspVideo* camera_ = nullptr;
|
||||
CustomBacklight *backlight_;
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_1,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &codec_i2c_bus_));
|
||||
}
|
||||
|
||||
static esp_err_t bsp_enable_dsi_phy_power(void) {
|
||||
#if MIPI_DSI_PHY_PWR_LDO_CHAN > 0
|
||||
// Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state
|
||||
static esp_ldo_channel_handle_t phy_pwr_chan = NULL;
|
||||
esp_ldo_channel_config_t ldo_cfg = {
|
||||
.chan_id = MIPI_DSI_PHY_PWR_LDO_CHAN,
|
||||
.voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
|
||||
};
|
||||
esp_ldo_acquire_channel(&ldo_cfg, &phy_pwr_chan);
|
||||
ESP_LOGI(TAG, "MIPI DSI PHY Powered on");
|
||||
#endif // BSP_MIPI_DSI_PHY_PWR_LDO_CHAN > 0
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InitializeLCD() {
|
||||
uint8_t chip_addr = 0x45;
|
||||
uint8_t write_cmds[4][2] = {{0x95, 0x11}, {0x95, 0x17}, {0x96, 0x00}, {0x96, 0xFF}};
|
||||
i2c_device_config_t i2c_dev_conf = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = chip_addr,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
i2c_master_dev_handle_t dev_handle = NULL;
|
||||
if (i2c_master_bus_add_device(codec_i2c_bus_, &i2c_dev_conf, &dev_handle) == ESP_OK)
|
||||
{
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
i2c_master_transmit(dev_handle, write_cmds[i], 2, 50);
|
||||
}
|
||||
i2c_master_bus_rm_device(dev_handle);
|
||||
}
|
||||
|
||||
bsp_enable_dsi_phy_power();
|
||||
esp_lcd_panel_io_handle_t io = NULL;
|
||||
esp_lcd_panel_handle_t disp_panel = NULL;
|
||||
|
||||
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
|
||||
esp_lcd_dsi_bus_config_t bus_config = {
|
||||
.bus_id = 0,
|
||||
.num_data_lanes = 2,
|
||||
.lane_bit_rate_mbps = 1500,
|
||||
};
|
||||
esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus);
|
||||
|
||||
ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
|
||||
// we use DBI interface to send LCD commands and parameters
|
||||
esp_lcd_dbi_io_config_t dbi_config = JD9365_PANEL_IO_DBI_CONFIG();
|
||||
esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io);
|
||||
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 80,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = 800,
|
||||
.v_size = 1280,
|
||||
.hsync_pulse_width = 20,
|
||||
.hsync_back_porch = 20,
|
||||
.hsync_front_porch = 40,
|
||||
.vsync_pulse_width = 10,
|
||||
.vsync_back_porch = 4,
|
||||
.vsync_front_porch = 30,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
|
||||
jd9365_vendor_config_t vendor_config = {
|
||||
.init_cmds = lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
.lane_num = 2,
|
||||
},
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
esp_lcd_new_panel_jd9365(io, &lcd_dev_config, &disp_panel);
|
||||
esp_lcd_panel_reset(disp_panel);
|
||||
esp_lcd_panel_init(disp_panel);
|
||||
|
||||
display__ = new MipiLcdDisplay(io, disp_panel, DISPLAY_WIDTH, DISPLAY_HEIGHT,
|
||||
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(codec_i2c_bus_);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
void InitializeTouch()
|
||||
{
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = GPIO_NUM_NC,
|
||||
.int_gpio_num = GPIO_NUM_NC,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 100 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(codec_i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
void InitializeCamera() {
|
||||
esp_video_init_csi_config_t base_csi_config = {
|
||||
.sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = codec_i2c_bus_,
|
||||
.freq = 400000,
|
||||
},
|
||||
.reset_pin = GPIO_NUM_NC,
|
||||
.pwdn_pin = GPIO_NUM_NC,
|
||||
};
|
||||
|
||||
esp_video_init_config_t cam_config = {
|
||||
.csi = &base_csi_config,
|
||||
};
|
||||
|
||||
camera_ = new EspVideo(cam_config);
|
||||
}
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32p4nano() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeCodecI2c();
|
||||
InitializeLCD();
|
||||
InitializeTouch();
|
||||
InitializeCamera();
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
virtual AudioCodec *GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(codec_i2c_bus_, I2C_NUM_1, 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__;
|
||||
}
|
||||
|
||||
virtual Camera* GetCamera() override {
|
||||
return camera_;
|
||||
}
|
||||
|
||||
virtual Backlight *GetBacklight() override {
|
||||
return backlight_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32p4nano);
|
||||
224
main/boards/waveshare/esp32-p4-nano/lcd_init_cmds.h
Normal file
224
main/boards/waveshare/esp32-p4-nano/lcd_init_cmds.h
Normal file
@@ -0,0 +1,224 @@
|
||||
static const jd9365_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
{0xE0, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xE1, (uint8_t[]){0x93}, 1, 0},
|
||||
{0xE2, (uint8_t[]){0x65}, 1, 0},
|
||||
{0xE3, (uint8_t[]){0xF8}, 1, 0},
|
||||
{0x80, (uint8_t[]){0x01}, 1, 0},
|
||||
|
||||
{0xE0, (uint8_t[]){0x01}, 1, 0},
|
||||
{0x00, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x01, (uint8_t[]){0x38}, 1, 0},
|
||||
{0x03, (uint8_t[]){0x10}, 1, 0},
|
||||
{0x04, (uint8_t[]){0x38}, 1, 0},
|
||||
|
||||
{0x0C, (uint8_t[]){0x74}, 1, 0},
|
||||
|
||||
{0x17, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x18, (uint8_t[]){0xAF}, 1, 0},
|
||||
{0x19, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x1A, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x1B, (uint8_t[]){0xAF}, 1, 0},
|
||||
{0x1C, (uint8_t[]){0x00}, 1, 0},
|
||||
|
||||
{0x35, (uint8_t[]){0x26}, 1, 0},
|
||||
|
||||
{0x37, (uint8_t[]){0x09}, 1, 0},
|
||||
|
||||
{0x38, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x39, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x01}, 1, 0},
|
||||
{0x3C, (uint8_t[]){0x78}, 1, 0},
|
||||
{0x3D, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0x3E, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0x3F, (uint8_t[]){0x7F}, 1, 0},
|
||||
|
||||
{0x40, (uint8_t[]){0x06}, 1, 0},
|
||||
{0x41, (uint8_t[]){0xA0}, 1, 0},
|
||||
{0x42, (uint8_t[]){0x81}, 1, 0},
|
||||
{0x43, (uint8_t[]){0x1E}, 1, 0},
|
||||
{0x44, (uint8_t[]){0x0D}, 1, 0},
|
||||
{0x45, (uint8_t[]){0x28}, 1, 0},
|
||||
//{0x4A, (uint8_t[]){0x35}, 1, 0},//bist
|
||||
|
||||
{0x55, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x57, (uint8_t[]){0x69}, 1, 0},
|
||||
{0x59, (uint8_t[]){0x0A}, 1, 0},
|
||||
{0x5A, (uint8_t[]){0x2A}, 1, 0},
|
||||
{0x5B, (uint8_t[]){0x17}, 1, 0},
|
||||
|
||||
{0x5D, (uint8_t[]){0x7F}, 1, 0},
|
||||
{0x5E, (uint8_t[]){0x6A}, 1, 0},
|
||||
{0x5F, (uint8_t[]){0x5B}, 1, 0},
|
||||
{0x60, (uint8_t[]){0x4F}, 1, 0},
|
||||
{0x61, (uint8_t[]){0x4A}, 1, 0},
|
||||
{0x62, (uint8_t[]){0x3D}, 1, 0},
|
||||
{0x63, (uint8_t[]){0x41}, 1, 0},
|
||||
{0x64, (uint8_t[]){0x2A}, 1, 0},
|
||||
{0x65, (uint8_t[]){0x44}, 1, 0},
|
||||
{0x66, (uint8_t[]){0x43}, 1, 0},
|
||||
{0x67, (uint8_t[]){0x44}, 1, 0},
|
||||
{0x68, (uint8_t[]){0x62}, 1, 0},
|
||||
{0x69, (uint8_t[]){0x52}, 1, 0},
|
||||
{0x6A, (uint8_t[]){0x59}, 1, 0},
|
||||
{0x6B, (uint8_t[]){0x4C}, 1, 0},
|
||||
{0x6C, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x6D, (uint8_t[]){0x3A}, 1, 0},
|
||||
{0x6E, (uint8_t[]){0x26}, 1, 0},
|
||||
{0x6F, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x70, (uint8_t[]){0x7F}, 1, 0},
|
||||
{0x71, (uint8_t[]){0x6A}, 1, 0},
|
||||
{0x72, (uint8_t[]){0x5B}, 1, 0},
|
||||
{0x73, (uint8_t[]){0x4F}, 1, 0},
|
||||
{0x74, (uint8_t[]){0x4A}, 1, 0},
|
||||
{0x75, (uint8_t[]){0x3D}, 1, 0},
|
||||
{0x76, (uint8_t[]){0x41}, 1, 0},
|
||||
{0x77, (uint8_t[]){0x2A}, 1, 0},
|
||||
{0x78, (uint8_t[]){0x44}, 1, 0},
|
||||
{0x79, (uint8_t[]){0x43}, 1, 0},
|
||||
{0x7A, (uint8_t[]){0x44}, 1, 0},
|
||||
{0x7B, (uint8_t[]){0x62}, 1, 0},
|
||||
{0x7C, (uint8_t[]){0x52}, 1, 0},
|
||||
{0x7D, (uint8_t[]){0x59}, 1, 0},
|
||||
{0x7E, (uint8_t[]){0x4C}, 1, 0},
|
||||
{0x7F, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x80, (uint8_t[]){0x3A}, 1, 0},
|
||||
{0x81, (uint8_t[]){0x26}, 1, 0},
|
||||
{0x82, (uint8_t[]){0x00}, 1, 0},
|
||||
|
||||
{0xE0, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x00, (uint8_t[]){0x42}, 1, 0},
|
||||
{0x01, (uint8_t[]){0x42}, 1, 0},
|
||||
{0x02, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x03, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x04, (uint8_t[]){0x5E}, 1, 0},
|
||||
{0x05, (uint8_t[]){0x5E}, 1, 0},
|
||||
{0x06, (uint8_t[]){0x5F}, 1, 0},
|
||||
{0x07, (uint8_t[]){0x5F}, 1, 0},
|
||||
{0x08, (uint8_t[]){0x5F}, 1, 0},
|
||||
{0x09, (uint8_t[]){0x57}, 1, 0},
|
||||
{0x0A, (uint8_t[]){0x57}, 1, 0},
|
||||
{0x0B, (uint8_t[]){0x77}, 1, 0},
|
||||
{0x0C, (uint8_t[]){0x77}, 1, 0},
|
||||
{0x0D, (uint8_t[]){0x47}, 1, 0},
|
||||
{0x0E, (uint8_t[]){0x47}, 1, 0},
|
||||
{0x0F, (uint8_t[]){0x45}, 1, 0},
|
||||
{0x10, (uint8_t[]){0x45}, 1, 0},
|
||||
{0x11, (uint8_t[]){0x4B}, 1, 0},
|
||||
{0x12, (uint8_t[]){0x4B}, 1, 0},
|
||||
{0x13, (uint8_t[]){0x49}, 1, 0},
|
||||
{0x14, (uint8_t[]){0x49}, 1, 0},
|
||||
{0x15, (uint8_t[]){0x5F}, 1, 0},
|
||||
|
||||
{0x16, (uint8_t[]){0x41}, 1, 0},
|
||||
{0x17, (uint8_t[]){0x41}, 1, 0},
|
||||
{0x18, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x19, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x1A, (uint8_t[]){0x5E}, 1, 0},
|
||||
{0x1B, (uint8_t[]){0x5E}, 1, 0},
|
||||
{0x1C, (uint8_t[]){0x5F}, 1, 0},
|
||||
{0x1D, (uint8_t[]){0x5F}, 1, 0},
|
||||
{0x1E, (uint8_t[]){0x5F}, 1, 0},
|
||||
{0x1F, (uint8_t[]){0x57}, 1, 0},
|
||||
{0x20, (uint8_t[]){0x57}, 1, 0},
|
||||
{0x21, (uint8_t[]){0x77}, 1, 0},
|
||||
{0x22, (uint8_t[]){0x77}, 1, 0},
|
||||
{0x23, (uint8_t[]){0x46}, 1, 0},
|
||||
{0x24, (uint8_t[]){0x46}, 1, 0},
|
||||
{0x25, (uint8_t[]){0x44}, 1, 0},
|
||||
{0x26, (uint8_t[]){0x44}, 1, 0},
|
||||
{0x27, (uint8_t[]){0x4A}, 1, 0},
|
||||
{0x28, (uint8_t[]){0x4A}, 1, 0},
|
||||
{0x29, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x2A, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x2B, (uint8_t[]){0x5F}, 1, 0},
|
||||
|
||||
{0x2C, (uint8_t[]){0x01}, 1, 0},
|
||||
{0x2D, (uint8_t[]){0x01}, 1, 0},
|
||||
{0x2E, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x2F, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x30, (uint8_t[]){0x1F}, 1, 0},
|
||||
{0x31, (uint8_t[]){0x1F}, 1, 0},
|
||||
{0x32, (uint8_t[]){0x1E}, 1, 0},
|
||||
{0x33, (uint8_t[]){0x1E}, 1, 0},
|
||||
{0x34, (uint8_t[]){0x1F}, 1, 0},
|
||||
{0x35, (uint8_t[]){0x17}, 1, 0},
|
||||
{0x36, (uint8_t[]){0x17}, 1, 0},
|
||||
{0x37, (uint8_t[]){0x37}, 1, 0},
|
||||
{0x38, (uint8_t[]){0x37}, 1, 0},
|
||||
{0x39, (uint8_t[]){0x08}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x08}, 1, 0},
|
||||
{0x3B, (uint8_t[]){0x0A}, 1, 0},
|
||||
{0x3C, (uint8_t[]){0x0A}, 1, 0},
|
||||
{0x3D, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x3E, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x3F, (uint8_t[]){0x06}, 1, 0},
|
||||
{0x40, (uint8_t[]){0x06}, 1, 0},
|
||||
{0x41, (uint8_t[]){0x1F}, 1, 0},
|
||||
|
||||
{0x42, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x43, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x44, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x45, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x46, (uint8_t[]){0x1F}, 1, 0},
|
||||
{0x47, (uint8_t[]){0x1F}, 1, 0},
|
||||
{0x48, (uint8_t[]){0x1E}, 1, 0},
|
||||
{0x49, (uint8_t[]){0x1E}, 1, 0},
|
||||
{0x4A, (uint8_t[]){0x1F}, 1, 0},
|
||||
{0x4B, (uint8_t[]){0x17}, 1, 0},
|
||||
{0x4C, (uint8_t[]){0x17}, 1, 0},
|
||||
{0x4D, (uint8_t[]){0x37}, 1, 0},
|
||||
{0x4E, (uint8_t[]){0x37}, 1, 0},
|
||||
{0x4F, (uint8_t[]){0x09}, 1, 0},
|
||||
{0x50, (uint8_t[]){0x09}, 1, 0},
|
||||
{0x51, (uint8_t[]){0x0B}, 1, 0},
|
||||
{0x52, (uint8_t[]){0x0B}, 1, 0},
|
||||
{0x53, (uint8_t[]){0x05}, 1, 0},
|
||||
{0x54, (uint8_t[]){0x05}, 1, 0},
|
||||
{0x55, (uint8_t[]){0x07}, 1, 0},
|
||||
{0x56, (uint8_t[]){0x07}, 1, 0},
|
||||
{0x57, (uint8_t[]){0x1F}, 1, 0},
|
||||
|
||||
{0x58, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x5B, (uint8_t[]){0x30}, 1, 0},
|
||||
{0x5C, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x5D, (uint8_t[]){0x34}, 1, 0},
|
||||
{0x5E, (uint8_t[]){0x05}, 1, 0},
|
||||
{0x5F, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x63, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x64, (uint8_t[]){0x6A}, 1, 0},
|
||||
{0x67, (uint8_t[]){0x73}, 1, 0},
|
||||
{0x68, (uint8_t[]){0x07}, 1, 0},
|
||||
{0x69, (uint8_t[]){0x08}, 1, 0},
|
||||
{0x6A, (uint8_t[]){0x6A}, 1, 0},
|
||||
{0x6B, (uint8_t[]){0x08}, 1, 0},
|
||||
|
||||
{0x6C, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x6D, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x6E, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x6F, (uint8_t[]){0x88}, 1, 0},
|
||||
|
||||
{0x75, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0x77, (uint8_t[]){0xDD}, 1, 0},
|
||||
{0x78, (uint8_t[]){0x2C}, 1, 0},
|
||||
{0x79, (uint8_t[]){0x15}, 1, 0},
|
||||
{0x7A, (uint8_t[]){0x17}, 1, 0},
|
||||
{0x7D, (uint8_t[]){0x14}, 1, 0},
|
||||
{0x7E, (uint8_t[]){0x82}, 1, 0},
|
||||
|
||||
{0xE0, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x00, (uint8_t[]){0x0E}, 1, 0},
|
||||
{0x02, (uint8_t[]){0xB3}, 1, 0},
|
||||
{0x09, (uint8_t[]){0x61}, 1, 0},
|
||||
{0x0E, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x37, (uint8_t[]){0x58}, 1, 0}, // 全志
|
||||
{0x2B, (uint8_t[]){0x0F}, 1, 0}, // 全志
|
||||
|
||||
{0xE0, (uint8_t[]){0x00}, 1, 0},
|
||||
|
||||
{0xE6, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xE7, (uint8_t[]){0x0C}, 1, 0},
|
||||
|
||||
{0x11, (uint8_t[]){0x00}, 1, 120},
|
||||
|
||||
{0x29, (uint8_t[]){0x00}, 1, 20},
|
||||
};
|
||||
11
main/boards/waveshare/esp32-p4-wifi6-touch-lcd-3.5/README.md
Normal file
11
main/boards/waveshare/esp32-p4-wifi6-touch-lcd-3.5/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Waveshare ESP32-P4-WIFI6-Touch-LCD-3.5
|
||||
|
||||
**ESP32-P4-WIFI6-Touch-LCD-3.5** is the ESP32-P4 +ESP32-C6 screen development board launched by waveshare.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration in `menuconfig`.
|
||||
|
||||
Selection Board Type `Xiaozhi Assistant --> Board Type`
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-3.5
|
||||
|
||||
45
main/boards/waveshare/esp32-p4-wifi6-touch-lcd-3.5/config.h
Normal file
45
main/boards/waveshare/esp32-p4-wifi6-touch-lcd-3.5/config.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_12
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_9
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_53
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_35
|
||||
|
||||
#define DISPLAY_WIDTH (320)
|
||||
#define DISPLAY_HEIGHT (480)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_28
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#define TOUCH_RST_PIN GPIO_NUM_29
|
||||
#define TOUCH_INT_PIN GPIO_NUM_50
|
||||
#define LCD_SPI_MOSI_PIN GPIO_NUM_20
|
||||
#define LCD_SPI_CLK_PIN GPIO_NUM_21
|
||||
#define LCD_SPI_CS_PIN GPIO_NUM_23
|
||||
#define LCD_SPI_DC_PIN GPIO_NUM_26
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32p4",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-3.5",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_5=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "button.h"
|
||||
#include "esp_video.h"
|
||||
#include "esp_video_init.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_lcd_st7796.h"
|
||||
#include "config.h"
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include "esp_lcd_touch_ft5x06.h"
|
||||
|
||||
#define TAG "WaveshareEsp32p4"
|
||||
|
||||
class WaveshareEsp32p4 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
LcdDisplay *display_;
|
||||
EspVideo* camera_ = nullptr;
|
||||
|
||||
|
||||
esp_err_t i2c_device_probe(uint8_t addr) {
|
||||
return i2c_master_probe(i2c_bus_, addr, 100);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_1,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeLCD() {
|
||||
esp_lcd_panel_io_handle_t io = NULL;
|
||||
esp_lcd_panel_handle_t disp_panel = NULL;
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = LCD_SPI_CLK_PIN;
|
||||
buscfg.mosi_io_num = LCD_SPI_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = (DISPLAY_WIDTH * DISPLAY_HEIGHT);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.dc_gpio_num = LCD_SPI_DC_PIN;
|
||||
io_config.cs_gpio_num = LCD_SPI_CS_PIN;
|
||||
io_config.pclk_hz = (80 * 1000 * 1000);
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
io_config.spi_mode = 3;
|
||||
io_config.trans_queue_depth = 10;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI2_HOST, &io_config, &io));
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.color_space = ESP_LCD_COLOR_SPACE_BGR,
|
||||
.bits_per_pixel = 16,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7796(io, &lcd_dev_config, &disp_panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(disp_panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(disp_panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(disp_panel, true));
|
||||
esp_lcd_panel_disp_on_off(disp_panel, true);
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(disp_panel, true, false));
|
||||
display_ = new SpiLcdDisplay(io, disp_panel, DISPLAY_WIDTH, DISPLAY_HEIGHT,
|
||||
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
void InitializeTouch()
|
||||
{
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = TOUCH_RST_PIN,
|
||||
.int_gpio_num = TOUCH_INT_PIN,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 1,
|
||||
.mirror_x = 1,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {};
|
||||
tp_io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS;
|
||||
tp_io_config.control_phase_bytes = 1;
|
||||
tp_io_config.dc_bit_offset = 0;
|
||||
tp_io_config.lcd_cmd_bits = 8;
|
||||
tp_io_config.flags.disable_control_phase = 1;
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
|
||||
lvgl_port_touch_cfg_t touch_cfg = {};
|
||||
touch_cfg.disp = lv_display_get_default();
|
||||
touch_cfg.handle = tp;
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
}
|
||||
void InitializeCamera() {
|
||||
esp_video_init_csi_config_t base_csi_config = {
|
||||
.sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = i2c_bus_,
|
||||
.freq = 400000,
|
||||
},
|
||||
.reset_pin = GPIO_NUM_NC,
|
||||
.pwdn_pin = GPIO_NUM_NC,
|
||||
};
|
||||
|
||||
esp_video_init_config_t cam_config = {
|
||||
.csi = &base_csi_config,
|
||||
};
|
||||
|
||||
camera_ = new EspVideo(cam_config);
|
||||
}
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
auto state = app.GetDeviceState();
|
||||
if (state == kDeviceStateStarting ||
|
||||
state == kDeviceStateConnecting ||
|
||||
state == kDeviceStateWifiConfiguring) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
esp_restart();
|
||||
});
|
||||
Application::GetInstance().StartListening();
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32p4() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeCodecI2c();
|
||||
InitializeLCD();
|
||||
InitializeTouch();
|
||||
InitializeCamera();
|
||||
InitializeButtons();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
I2C_NUM_1,
|
||||
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,
|
||||
true,
|
||||
false);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display *GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Camera* GetCamera() override {
|
||||
return camera_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32p4);
|
||||
18
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/README.md
Normal file
18
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Waveshare ESP32-P4-WIFI6-Touch-LCD
|
||||
|
||||
|
||||
**ESP32-P4-WIFI6-Touch-LCD** series is the ESP32-P4 +ESP32-C6 screen development board launched by waveshare
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration in `menuconfig`.
|
||||
|
||||
Selection Board Type `Xiaozhi Assistant --> Board Type`
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4B
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-7B
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4C
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-7
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-8
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-10.1
|
||||
98
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/config.h
Normal file
98
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/config.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_12
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_9
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_53
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_35
|
||||
|
||||
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
|
||||
#define DISPLAY_WIDTH (720)
|
||||
#define DISPLAY_HEIGHT (720)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (480)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4_3
|
||||
#define DISPLAY_WIDTH (480)
|
||||
#define DISPLAY_HEIGHT (800)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (500)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
|
||||
#define DISPLAY_WIDTH (1024)
|
||||
#define DISPLAY_HEIGHT (600)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_33
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_32
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (900)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C
|
||||
#define DISPLAY_WIDTH (800)
|
||||
#define DISPLAY_HEIGHT (800)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C
|
||||
#define DISPLAY_WIDTH (720)
|
||||
#define DISPLAY_HEIGHT (720)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7
|
||||
#define DISPLAY_WIDTH (720)
|
||||
#define DISPLAY_HEIGHT (1280)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1000)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8
|
||||
#define DISPLAY_WIDTH (800)
|
||||
#define DISPLAY_HEIGHT (1280)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1
|
||||
#define DISPLAY_WIDTH (800)
|
||||
#define DISPLAY_HEIGHT (1280)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
|
||||
#endif
|
||||
|
||||
#define LCD_BIT_PER_PIXEL (16)
|
||||
#define DELAY_TIME_MS (3000)
|
||||
#define LCD_MIPI_DSI_LANE_NUM (2) // 2 data lanes
|
||||
|
||||
#define MIPI_DSI_PHY_PWR_LDO_CHAN (3)
|
||||
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
118
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/config.json
Normal file
118
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/config.json
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32p4",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-4b",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-4.3",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4_3=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-7b",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-3.4c",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-4c",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-7",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-8",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-10.1",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,458 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "display/lcd_display.h"
|
||||
// #include "display/no_display.h"
|
||||
#include "button.h"
|
||||
|
||||
#include "esp_video.h"
|
||||
#include "esp_video_init.h"
|
||||
#include "esp_cam_sensor_xclk.h"
|
||||
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_mipi_dsi.h"
|
||||
#include "esp_ldo_regulator.h"
|
||||
|
||||
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
|
||||
#include "esp_lcd_st7703.h"
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4_3
|
||||
#include "esp_lcd_st7701.h"
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
|
||||
#include "esp_lcd_ek79007.h"
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C \
|
||||
|| CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1
|
||||
#include "esp_lcd_jd9365.h"
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7
|
||||
#include "esp_lcd_ili9881c.h"
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "lcd_init_cmds.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include "esp_lcd_touch_gt911.h"
|
||||
#define TAG "WaveshareEsp32p4"
|
||||
|
||||
class WaveshareEsp32p4 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
LcdDisplay *display_;
|
||||
EspVideo* camera_ = nullptr;
|
||||
|
||||
|
||||
esp_err_t i2c_device_probe(uint8_t addr) {
|
||||
return i2c_master_probe(i2c_bus_, addr, 100);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_1,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
static esp_err_t bsp_enable_dsi_phy_power(void) {
|
||||
#if MIPI_DSI_PHY_PWR_LDO_CHAN > 0
|
||||
// Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state
|
||||
static esp_ldo_channel_handle_t phy_pwr_chan = NULL;
|
||||
esp_ldo_channel_config_t ldo_cfg = {
|
||||
.chan_id = MIPI_DSI_PHY_PWR_LDO_CHAN,
|
||||
.voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
|
||||
};
|
||||
esp_ldo_acquire_channel(&ldo_cfg, &phy_pwr_chan);
|
||||
ESP_LOGI(TAG, "MIPI DSI PHY Powered on");
|
||||
#endif // BSP_MIPI_DSI_PHY_PWR_LDO_CHAN > 0
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InitializeLCD() {
|
||||
bsp_enable_dsi_phy_power();
|
||||
esp_lcd_panel_io_handle_t io = NULL;
|
||||
esp_lcd_panel_handle_t disp_panel = NULL;
|
||||
|
||||
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
|
||||
esp_lcd_dsi_bus_config_t bus_config = {
|
||||
.bus_id = 0,
|
||||
.num_data_lanes = 2,
|
||||
.lane_bit_rate_mbps = LCD_MIPI_DSI_LANE_BITRATE_MBPS,
|
||||
};
|
||||
esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus);
|
||||
|
||||
ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
|
||||
// we use DBI interface to send LCD commands and parameters
|
||||
esp_lcd_dbi_io_config_t dbi_config = {
|
||||
.virtual_channel = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
};
|
||||
esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io);
|
||||
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 46,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = 720,
|
||||
.v_size = 720,
|
||||
.hsync_pulse_width = 20,
|
||||
.hsync_back_porch = 80,
|
||||
.hsync_front_porch = 80,
|
||||
.vsync_pulse_width = 4,
|
||||
.vsync_back_porch = 12,
|
||||
.vsync_front_porch = 30,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
st7703_vendor_config_t vendor_config = {
|
||||
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
},
|
||||
.flags = {
|
||||
.use_mipi_interface = 1,
|
||||
},
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
esp_lcd_new_panel_st7703(io, &lcd_dev_config, &disp_panel);
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4_3
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 30,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = 480,
|
||||
.v_size = 800,
|
||||
.hsync_pulse_width = 12,
|
||||
.hsync_back_porch = 42,
|
||||
.hsync_front_porch = 42,
|
||||
.vsync_pulse_width = 8,
|
||||
.vsync_back_porch = 2,
|
||||
.vsync_front_porch = 60,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
st7701_vendor_config_t vendor_config = {
|
||||
.init_cmds = vendor_specific_init_default,
|
||||
.init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st7701_lcd_init_cmd_t),
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
},
|
||||
.flags = {
|
||||
.use_mipi_interface = 1,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
esp_lcd_new_panel_st7701(io, &lcd_dev_config, &disp_panel);
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 52,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = 1024,
|
||||
.v_size = 600,
|
||||
.hsync_pulse_width = 10,
|
||||
.hsync_back_porch = 160,
|
||||
.hsync_front_porch = 160,
|
||||
.vsync_pulse_width = 1,
|
||||
.vsync_back_porch = 23,
|
||||
.vsync_front_porch = 12,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
ek79007_vendor_config_t vendor_config = {
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
},
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
esp_lcd_new_panel_ek79007(io, &lcd_dev_config, &disp_panel);
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 46,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = DISPLAY_WIDTH,
|
||||
.v_size = DISPLAY_HEIGHT,
|
||||
.hsync_pulse_width = 20,
|
||||
.hsync_back_porch = 20,
|
||||
.hsync_front_porch = 40,
|
||||
.vsync_pulse_width = 4,
|
||||
.vsync_back_porch = 12,
|
||||
.vsync_front_porch = 24,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
jd9365_vendor_config_t vendor_config = {
|
||||
.init_cmds = lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
.lane_num = 2,
|
||||
},
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
esp_lcd_new_panel_jd9365(io, &lcd_dev_config, &disp_panel);
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 52,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = DISPLAY_WIDTH,
|
||||
.v_size = DISPLAY_HEIGHT,
|
||||
.hsync_pulse_width = 20,
|
||||
.hsync_back_porch = 20,
|
||||
.hsync_front_porch = 40,
|
||||
.vsync_pulse_width = 4,
|
||||
.vsync_back_porch = 10,
|
||||
.vsync_front_porch = 30,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
jd9365_vendor_config_t vendor_config = {
|
||||
.init_cmds = lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
.lane_num = 2,
|
||||
},
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
esp_lcd_new_panel_jd9365(io, &lcd_dev_config, &disp_panel);
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 80,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = DISPLAY_WIDTH,
|
||||
.v_size = DISPLAY_HEIGHT,
|
||||
.hsync_pulse_width = 50,
|
||||
.hsync_back_porch = 239,
|
||||
.hsync_front_porch = 33,
|
||||
.vsync_pulse_width = 30,
|
||||
.vsync_back_porch = 20,
|
||||
.vsync_front_porch = 2,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
ili9881c_vendor_config_t vendor_config = {
|
||||
.init_cmds = lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
.lane_num = 2,
|
||||
},
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
esp_lcd_new_panel_ili9881c(io, &lcd_dev_config, &disp_panel);
|
||||
#endif
|
||||
esp_lcd_panel_reset(disp_panel);
|
||||
esp_lcd_panel_init(disp_panel);
|
||||
|
||||
display_ = new MipiLcdDisplay(io, disp_panel, DISPLAY_WIDTH, DISPLAY_HEIGHT,
|
||||
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
void InitializeTouch()
|
||||
{
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = GPIO_NUM_NC,
|
||||
.int_gpio_num = GPIO_NUM_NC,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
if (ESP_OK == i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS)) {
|
||||
ESP_LOGI(TAG, "Touch panel found at address 0x%02X", ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS);
|
||||
} else if (ESP_OK == i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP)) {
|
||||
ESP_LOGI(TAG, "Touch panel found at address 0x%02X", ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP);
|
||||
tp_io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Touch panel not found on I2C bus");
|
||||
ESP_LOGE(TAG, "Tried addresses: 0x%02X and 0x%02X",
|
||||
ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP);
|
||||
return;
|
||||
}
|
||||
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
void InitializeCamera() {
|
||||
esp_video_init_csi_config_t base_csi_config = {
|
||||
.sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = i2c_bus_,
|
||||
.freq = 400000,
|
||||
},
|
||||
.reset_pin = GPIO_NUM_NC,
|
||||
.pwdn_pin = GPIO_NUM_NC,
|
||||
};
|
||||
|
||||
esp_video_init_config_t cam_config = {
|
||||
.csi = &base_csi_config,
|
||||
};
|
||||
|
||||
camera_ = new EspVideo(cam_config);
|
||||
}
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32p4() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeCodecI2c();
|
||||
InitializeLCD();
|
||||
InitializeTouch();
|
||||
InitializeCamera();
|
||||
InitializeButtons();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display *GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Camera* GetCamera() override {
|
||||
return camera_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32p4);
|
||||
1124
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/lcd_init_cmds.h
Normal file
1124
main/boards/waveshare/esp32-p4-wifi6-touch-lcd/lcd_init_cmds.h
Normal file
File diff suppressed because it is too large
Load Diff
3
main/boards/waveshare/esp32-s3-audio-board/README.md
Normal file
3
main/boards/waveshare/esp32-s3-audio-board/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
新增 微雪 开发板: ESP32-S3-AUDIO-Board
|
||||
产品链接:
|
||||
https://www.waveshare.net/shop/ESP32-S3-AUDIO-Board.htm
|
||||
95
main/boards/waveshare/esp32-s3-audio-board/config.h
Normal file
95
main/boards/waveshare/esp32-s3-audio-board/config.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_38
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_12
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_14
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_16
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_10
|
||||
#define I2C_SDA_IO GPIO_NUM_11
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000
|
||||
|
||||
#define DISPLAY_SDA_PIN I2C_SDA_IO
|
||||
#define DISPLAY_SCL_PIN I2C_SCL_IO
|
||||
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_8
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_9
|
||||
#define DISPLAY_SCLK_PIN GPIO_NUM_4
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_3
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_7
|
||||
#define DISPLAY_RESET_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_5
|
||||
|
||||
#define DISPLAY_SPI_SCLK_HZ (20 * 1000 * 1000)
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAMERA_PIN_RESET GPIO_NUM_NC
|
||||
#define CAMERA_PIN_XCLK GPIO_NUM_43
|
||||
#define CAMERA_PIN_SIOD GPIO_NUM_NC
|
||||
#define CAMERA_PIN_SIOC GPIO_NUM_NC
|
||||
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_48
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_47
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_46
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_45
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_39
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_18
|
||||
#define CAMERA_PIN_D1 GPIO_NUM_17
|
||||
#define CAMERA_PIN_D0 GPIO_NUM_2
|
||||
#define CAMERA_PIN_VSYNC GPIO_NUM_21
|
||||
#define CAMERA_PIN_HREF GPIO_NUM_1
|
||||
#define CAMERA_PIN_PCLK GPIO_NUM_44
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_AUDIO_BOARD_LCD_JD9853
|
||||
#define LCD_TYPE_JD9853_SERIAL
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 172
|
||||
|
||||
#define DISPLAY_SWAP_XY true
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AUDIO_BOARD_LCD_ST7789
|
||||
#define LCD_TYPE_ST7789_SERIAL
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 320
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
20
main/boards/waveshare/esp32-s3-audio-board/config.json
Normal file
20
main/boards/waveshare/esp32-s3-audio-board/config.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-audio-board",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=y",
|
||||
"CONFIG_CAMERA_OV2640=y",
|
||||
"CONFIG_CAMERA_OV2640_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV2640_DVP_YUV422_640X480_6FPS=y",
|
||||
"CONFIG_CAMERA_OV2640_DVP_IF_FORMAT_INDEX_DEFAULT=1",
|
||||
"CONFIG_CAMERA_OV5640=y",
|
||||
"CONFIG_CAMERA_OV5640_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV5640_DVP_YUV422_800X600_10FPS=y",
|
||||
"CONFIG_CAMERA_OV5640_DVP_IF_FORMAT_INDEX_DEFAULT=0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_st77916.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp_io_expander_tca95xx_16bit.h"
|
||||
#include "esp_video.h"
|
||||
#include "led/circular_strip.h"
|
||||
#include "esp_lcd_jd9853.h"
|
||||
|
||||
#define TAG "waveshare_s3_audio_board"
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x0BULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
LcdDisplay* display_;
|
||||
EspVideo* camera_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeTca9555(void)
|
||||
{
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca95xx_16bit(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error"); // 打印引脚状态
|
||||
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_8|IO_EXPANDER_PIN_NUM_5|IO_EXPANDER_PIN_NUM_6, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输出
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_8, 1); // 启用喇叭功放
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_5, false); // 复位摄像头
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_6, true);
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = DISPLAY_SCLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeSt7789Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片ST7789
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR));
|
||||
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeJd9853Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片JD9853
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
//ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_jd9853(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, true));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel, 0, 34));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, true, false));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, true));
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = false, // 不初始化新的 SCCB,使用现有的 I2C 总线
|
||||
.i2c_handle = i2c_bus_, // 使用现有的 I2C 总线句柄
|
||||
.freq = 100000, // 100kHz
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = 12000000,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new EspVideo(video_config);
|
||||
|
||||
}
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
InitializeTca9555();
|
||||
InitializeSpi();
|
||||
InitializeButtons();
|
||||
#ifdef LCD_TYPE_JD9853_SERIAL
|
||||
InitializeJd9853Display();
|
||||
#else
|
||||
InitializeSt7789Display();
|
||||
#endif
|
||||
InitializeCamera();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
static CircularStrip led(BUILTIN_LED_GPIO, 6);
|
||||
return &led;
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(i2c_bus_, 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, AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, BACKLIGHT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual Camera* GetCamera() override {
|
||||
return camera_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
460
main/boards/waveshare/esp32-s3-audio-board/esp_lcd_jd9853.c
Normal file
460
main/boards/waveshare/esp32-s3-audio-board/esp_lcd_jd9853.c
Normal file
@@ -0,0 +1,460 @@
|
||||
#include <stdio.h>
|
||||
#include "esp_lcd_jd9853.h"
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
static const char *TAG = "JD9853";
|
||||
|
||||
static esp_err_t panel_jd9853_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_jd9853_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_jd9853_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_jd9853_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data);
|
||||
static esp_err_t panel_jd9853_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||
static esp_err_t panel_jd9853_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_jd9853_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
|
||||
static esp_err_t panel_jd9853_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
|
||||
static esp_err_t panel_jd9853_disp_on_off(esp_lcd_panel_t *panel, bool off);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
esp_lcd_panel_t base;
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
bool reset_level;
|
||||
int x_gap;
|
||||
int y_gap;
|
||||
uint8_t fb_bits_per_pixel;
|
||||
uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register
|
||||
uint8_t colmod_val; // save current value of LCD_CMD_COLMOD register
|
||||
const jd9853_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
} jd9853_panel_t;
|
||||
|
||||
esp_err_t esp_lcd_new_panel_jd9853(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
jd9853_panel_t *jd9853 = NULL;
|
||||
gpio_config_t io_conf = {0};
|
||||
|
||||
ESP_GOTO_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
jd9853 = (jd9853_panel_t *)calloc(1, sizeof(jd9853_panel_t));
|
||||
ESP_GOTO_ON_FALSE(jd9853, ESP_ERR_NO_MEM, err, TAG, "no mem for jd9853 panel");
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0)
|
||||
{
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num;
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
switch (panel_dev_config->color_space)
|
||||
{
|
||||
case ESP_LCD_COLOR_SPACE_RGB:
|
||||
jd9853->madctl_val = 0;
|
||||
break;
|
||||
case ESP_LCD_COLOR_SPACE_BGR:
|
||||
jd9853->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color space");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (panel_dev_config->rgb_endian)
|
||||
{
|
||||
case LCD_RGB_ENDIAN_RGB:
|
||||
jd9853->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ENDIAN_BGR:
|
||||
jd9853->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported rgb endian");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (panel_dev_config->bits_per_pixel)
|
||||
{
|
||||
case 16: // RGB565
|
||||
jd9853->colmod_val = 0x55;
|
||||
jd9853->fb_bits_per_pixel = 16;
|
||||
break;
|
||||
case 18: // RGB666
|
||||
jd9853->colmod_val = 0x66;
|
||||
// each color component (R/G/B) should occupy the 6 high bits of a byte, which means 3 full bytes are required for a pixel
|
||||
jd9853->fb_bits_per_pixel = 24;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
jd9853->io = io;
|
||||
jd9853->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
jd9853->reset_level = panel_dev_config->flags.reset_active_high;
|
||||
if (panel_dev_config->vendor_config)
|
||||
{
|
||||
jd9853->init_cmds = ((jd9853_vendor_config_t *)panel_dev_config->vendor_config)->init_cmds;
|
||||
jd9853->init_cmds_size = ((jd9853_vendor_config_t *)panel_dev_config->vendor_config)->init_cmds_size;
|
||||
}
|
||||
jd9853->base.del = panel_jd9853_del;
|
||||
jd9853->base.reset = panel_jd9853_reset;
|
||||
jd9853->base.init = panel_jd9853_init;
|
||||
jd9853->base.draw_bitmap = panel_jd9853_draw_bitmap;
|
||||
jd9853->base.invert_color = panel_jd9853_invert_color;
|
||||
jd9853->base.set_gap = panel_jd9853_set_gap;
|
||||
jd9853->base.mirror = panel_jd9853_mirror;
|
||||
jd9853->base.swap_xy = panel_jd9853_swap_xy;
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
jd9853->base.disp_off = panel_jd9853_disp_on_off;
|
||||
#else
|
||||
jd9853->base.disp_on_off = panel_jd9853_disp_on_off;
|
||||
#endif
|
||||
*ret_panel = &(jd9853->base);
|
||||
ESP_LOGD(TAG, "new jd9853 panel @%p", jd9853);
|
||||
|
||||
// ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_jd9853_VER_MAJOR, ESP_LCD_jd9853_VER_MINOR,
|
||||
// ESP_LCD_jd9853_VER_PATCH);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (jd9853)
|
||||
{
|
||||
if (panel_dev_config->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(jd9853);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
|
||||
if (jd9853->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_reset_pin(jd9853->reset_gpio_num);
|
||||
}
|
||||
ESP_LOGD(TAG, "del jd9853 panel @%p", jd9853);
|
||||
free(jd9853);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
|
||||
// perform hardware reset
|
||||
if (jd9853->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_set_level(jd9853->reset_gpio_num, jd9853->reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(jd9853->reset_gpio_num, !jd9853->reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
else
|
||||
{ // perform software reset
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // spec, wait at least 5ms before sending new command
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint8_t data[16];
|
||||
uint8_t data_bytes; // Length of data in above data array; 0xFF = end of cmds.
|
||||
} lcd_init_cmd_t;
|
||||
|
||||
// static const jd9853_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
// // {cmd, { data }, data_size, delay_ms}
|
||||
// /* Power contorl B, power control = 0, DC_ENA = 1 */
|
||||
// {0xCF, (uint8_t []){0x00, 0xAA, 0XE0}, 3, 0},
|
||||
// /* Power on sequence control,
|
||||
// * cp1 keeps 1 frame, 1st frame enable
|
||||
// * vcl = 0, ddvdh=3, vgh=1, vgl=2
|
||||
// * DDVDH_ENH=1
|
||||
// */
|
||||
// {0xED, (uint8_t []){0x67, 0x03, 0X12, 0X81}, 4, 0},
|
||||
// /* Driver timing control A,
|
||||
// * non-overlap=default +1
|
||||
// * EQ=default - 1, CR=default
|
||||
// * pre-charge=default - 1
|
||||
// */
|
||||
// {0xE8, (uint8_t []){0x8A, 0x01, 0x78}, 3, 0},
|
||||
// /* Power control A, Vcore=1.6V, DDVDH=5.6V */
|
||||
// {0xCB, (uint8_t []){0x39, 0x2C, 0x00, 0x34, 0x02}, 5, 0},
|
||||
// /* Pump ratio control, DDVDH=2xVCl */
|
||||
// {0xF7, (uint8_t []){0x20}, 1, 0},
|
||||
|
||||
// {0xF7, (uint8_t []){0x20}, 1, 0},
|
||||
// /* Driver timing control, all=0 unit */
|
||||
// {0xEA, (uint8_t []){0x00, 0x00}, 2, 0},
|
||||
// /* Power control 1, GVDD=4.75V */
|
||||
// {0xC0, (uint8_t []){0x23}, 1, 0},
|
||||
// /* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */
|
||||
// {0xC1, (uint8_t []){0x11}, 1, 0},
|
||||
// /* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */
|
||||
// {0xC5, (uint8_t []){0x43, 0x4C}, 2, 0},
|
||||
// /* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */
|
||||
// {0xC7, (uint8_t []){0xA0}, 1, 0},
|
||||
// /* Frame rate control, f=fosc, 70Hz fps */
|
||||
// {0xB1, (uint8_t []){0x00, 0x1B}, 2, 0},
|
||||
// /* Enable 3G, disabled */
|
||||
// {0xF2, (uint8_t []){0x00}, 1, 0},
|
||||
// /* Gamma set, curve 1 */
|
||||
// {0x26, (uint8_t []){0x01}, 1, 0},
|
||||
// /* Positive gamma correction */
|
||||
// {0xE0, (uint8_t []){0x1F, 0x36, 0x36, 0x3A, 0x0C, 0x05, 0x4F, 0X87, 0x3C, 0x08, 0x11, 0x35, 0x19, 0x13, 0x00}, 15, 0},
|
||||
// /* Negative gamma correction */
|
||||
// {0xE1, (uint8_t []){0x00, 0x09, 0x09, 0x05, 0x13, 0x0A, 0x30, 0x78, 0x43, 0x07, 0x0E, 0x0A, 0x26, 0x2C, 0x1F}, 15, 0},
|
||||
// /* Entry mode set, Low vol detect disabled, normal display */
|
||||
// {0xB7, (uint8_t []){0x07}, 1, 0},
|
||||
// /* Display function control */
|
||||
// {0xB6, (uint8_t []){0x08, 0x82, 0x27}, 3, 0},
|
||||
// };
|
||||
|
||||
static const jd9853_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
{0x11, (uint8_t []){ 0x00 }, 0, 120},
|
||||
{0xDF, (uint8_t[]){0x98, 0x53}, 2, 0},
|
||||
{0xDF, (uint8_t[]){0x98, 0x53}, 2, 0},
|
||||
{0xB2, (uint8_t[]){0x23}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x00, 0x47, 0x00, 0x6F}, 4, 0},
|
||||
{0xBB, (uint8_t[]){0x1C, 0x1A, 0x55, 0x73, 0x63, 0xF0}, 6, 0},
|
||||
{0xC0, (uint8_t[]){0x44, 0xA4}, 2, 0},
|
||||
{0xC1, (uint8_t[]){0x16}, 1, 0},
|
||||
{0xC3, (uint8_t[]){0x7D, 0x07, 0x14, 0x06, 0xCF, 0x71, 0x72, 0x77}, 8, 0},
|
||||
{0xC4, (uint8_t[]){0x00, 0x00, 0xA0, 0x79, 0x0B, 0x0A, 0x16, 0x79, 0x0B, 0x0A, 0x16, 0x82}, 12, 0}, // 00=60Hz 06=57Hz 08=51Hz, LN=320 Line
|
||||
{0xC8, (uint8_t[]){0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00, 0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00}, 32, 0}, // SET_R_GAMMA
|
||||
{0xD0, (uint8_t[]){0x04, 0x06, 0x6B, 0x0F, 0x00}, 5, 0},
|
||||
{0xD7, (uint8_t[]){0x00, 0x30}, 2, 0},
|
||||
{0xE6, (uint8_t[]){0x14}, 1, 0},
|
||||
{0xDE, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x03, 0x13, 0xEF, 0x35, 0x35}, 5, 0},
|
||||
{0xC1, (uint8_t[]){0x14, 0x15, 0xC0}, 3, 0},
|
||||
{0xC2, (uint8_t[]){0x06, 0x3A}, 2, 0},
|
||||
{0xC4, (uint8_t[]){0x72, 0x12}, 2, 0},
|
||||
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xDE, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xE5, (uint8_t[]){0x00, 0x02, 0x00}, 3, 0},
|
||||
{0xE5, (uint8_t[]){0x01, 0x02, 0x00}, 3, 0},
|
||||
{0xDE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x05}, 1, 0}, // 06=RGB666;05=RGB565
|
||||
{0x2A, (uint8_t[]){0x00, 0x22, 0x00, 0xCD}, 4, 0}, // Start_X=34, End_X=205
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0x3F}, 4, 0}, // Start_Y=0, End_Y=319
|
||||
{0xDE, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xE5, (uint8_t[]){0x00, 0x02, 0x00}, 3, 0},
|
||||
{0xDE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x29, (uint8_t []){ 0x00 }, 0, 0},
|
||||
};
|
||||
|
||||
static esp_err_t panel_jd9853_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
|
||||
// LCD goes into sleep mode and display will be turned off after power on reset, exit sleep mode first
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SLPOUT, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]){
|
||||
jd9853->madctl_val,
|
||||
},
|
||||
1),
|
||||
TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]){
|
||||
jd9853->colmod_val,
|
||||
},
|
||||
1),
|
||||
TAG, "send command failed");
|
||||
|
||||
const jd9853_lcd_init_cmd_t *init_cmds = NULL;
|
||||
uint16_t init_cmds_size = 0;
|
||||
if (jd9853->init_cmds)
|
||||
{
|
||||
init_cmds = jd9853->init_cmds;
|
||||
init_cmds_size = jd9853->init_cmds_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
init_cmds = vendor_specific_init_default;
|
||||
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(jd9853_lcd_init_cmd_t);
|
||||
}
|
||||
|
||||
bool is_cmd_overwritten = false;
|
||||
for (int i = 0; i < init_cmds_size; i++)
|
||||
{
|
||||
// Check if the command has been used or conflicts with the internal
|
||||
switch (init_cmds[i].cmd)
|
||||
{
|
||||
case LCD_CMD_MADCTL:
|
||||
is_cmd_overwritten = true;
|
||||
jd9853->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
case LCD_CMD_COLMOD:
|
||||
is_cmd_overwritten = true;
|
||||
jd9853->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
default:
|
||||
is_cmd_overwritten = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_cmd_overwritten)
|
||||
{
|
||||
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", init_cmds[i].cmd);
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||
}
|
||||
ESP_LOGD(TAG, "send init commands success");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
|
||||
x_start += jd9853->x_gap;
|
||||
x_end += jd9853->x_gap;
|
||||
y_start += jd9853->y_gap;
|
||||
y_end += jd9853->y_gap;
|
||||
|
||||
// define an area of frame memory where MCU can access
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_CASET, (uint8_t[]){
|
||||
(x_start >> 8) & 0xFF,
|
||||
x_start & 0xFF,
|
||||
((x_end - 1) >> 8) & 0xFF,
|
||||
(x_end - 1) & 0xFF,
|
||||
},
|
||||
4),
|
||||
TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_RASET, (uint8_t[]){
|
||||
(y_start >> 8) & 0xFF,
|
||||
y_start & 0xFF,
|
||||
((y_end - 1) >> 8) & 0xFF,
|
||||
(y_end - 1) & 0xFF,
|
||||
},
|
||||
4),
|
||||
TAG, "send command failed");
|
||||
// transfer frame buffer
|
||||
size_t len = (x_end - x_start) * (y_end - y_start) * jd9853->fb_bits_per_pixel / 8;
|
||||
esp_lcd_panel_io_tx_color(io, LCD_CMD_RAMWR, color_data, len);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
int command = 0;
|
||||
if (invert_color_data)
|
||||
{
|
||||
command = LCD_CMD_INVON;
|
||||
}
|
||||
else
|
||||
{
|
||||
command = LCD_CMD_INVOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
if (mirror_x)
|
||||
{
|
||||
jd9853->madctl_val |= LCD_CMD_MX_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
jd9853->madctl_val &= ~LCD_CMD_MX_BIT;
|
||||
}
|
||||
if (mirror_y)
|
||||
{
|
||||
jd9853->madctl_val |= LCD_CMD_MY_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
jd9853->madctl_val &= ~LCD_CMD_MY_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]){jd9853->madctl_val}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
if (swap_axes)
|
||||
{
|
||||
jd9853->madctl_val |= LCD_CMD_MV_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
jd9853->madctl_val &= ~LCD_CMD_MV_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]){jd9853->madctl_val}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
jd9853->x_gap = x_gap;
|
||||
jd9853->y_gap = y_gap;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
int command = 0;
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
on_off = !on_off;
|
||||
#endif
|
||||
|
||||
if (on_off)
|
||||
{
|
||||
command = LCD_CMD_DISPON;
|
||||
}
|
||||
else
|
||||
{
|
||||
command = LCD_CMD_DISPOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
102
main/boards/waveshare/esp32-s3-audio-board/esp_lcd_jd9853.h
Normal file
102
main/boards/waveshare/esp32-s3-audio-board/esp_lcd_jd9853.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief ESP LCD: jd9853
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/spi_ll.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LCD panel initialization commands.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
int cmd; /*<! The specific LCD command */
|
||||
const void *data; /*<! Buffer that holds the command specific data */
|
||||
size_t data_bytes; /*<! Size of `data` in memory, in bytes */
|
||||
unsigned int delay_ms; /*<! Delay in milliseconds after this command */
|
||||
} jd9853_lcd_init_cmd_t;
|
||||
|
||||
/**
|
||||
* @brief LCD panel vendor configuration.
|
||||
*
|
||||
* @note This structure needs to be passed to the `vendor_config` field in `esp_lcd_panel_dev_config_t`.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const jd9853_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array. Set to NULL if using default commands.
|
||||
* The array should be declared as `static const` and positioned outside the function.
|
||||
* Please refer to `vendor_specific_init_default` in source file.
|
||||
*/
|
||||
uint16_t init_cmds_size; /*<! Number of commands in above array */
|
||||
} jd9853_vendor_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create LCD panel for model jd9853
|
||||
*
|
||||
* @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for initialization sequence code.
|
||||
*
|
||||
* @param[in] io LCD panel IO handle
|
||||
* @param[in] panel_dev_config general panel device configuration
|
||||
* @param[out] ret_panel Returned LCD panel handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_jd9853(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);
|
||||
|
||||
/**
|
||||
* @brief LCD panel bus configuration structure
|
||||
*
|
||||
* @param[in] sclk SPI clock pin number
|
||||
* @param[in] mosi SPI MOSI pin number
|
||||
* @param[in] max_trans_sz Maximum transfer size in bytes
|
||||
*
|
||||
*/
|
||||
#define JD9853_PANEL_BUS_SPI_CONFIG(sclk, mosi, max_trans_sz) \
|
||||
{ \
|
||||
.sclk_io_num = sclk, \
|
||||
.mosi_io_num = mosi, \
|
||||
.miso_io_num = -1, \
|
||||
.quadhd_io_num = -1, \
|
||||
.quadwp_io_num = -1, \
|
||||
.max_transfer_sz = max_trans_sz, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCD panel IO configuration structure
|
||||
*
|
||||
* @param[in] cs SPI chip select pin number
|
||||
* @param[in] dc SPI data/command pin number
|
||||
* @param[in] cb Callback function when SPI transfer is done
|
||||
* @param[in] cb_ctx Callback function context
|
||||
*
|
||||
*/
|
||||
#define JD9853_PANEL_IO_SPI_CONFIG(cs, dc, callback, callback_ctx) \
|
||||
{ \
|
||||
.cs_gpio_num = cs, \
|
||||
.dc_gpio_num = dc, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = 40 * 1000 * 1000, \
|
||||
.trans_queue_depth = 10, \
|
||||
.on_color_trans_done = callback, \
|
||||
.user_ctx = callback_ctx, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
6
main/boards/waveshare/esp32-s3-cam/README.md
Normal file
6
main/boards/waveshare/esp32-s3-cam/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
新增 微雪 开发板: ESP32-S3-CAM-XXXX
|
||||
产品链接:
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-OV5640.htm
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-OV3660.htm
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-GC2145.htm
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-GC0308.htm
|
||||
115
main/boards/waveshare/esp32-s3-cam/config.h
Normal file
115
main/boards/waveshare/esp32-s3-cam/config.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_12
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_14
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_7
|
||||
#define I2C_SDA_IO GPIO_NUM_8
|
||||
|
||||
#define BSP_IO_EXPANDER_I2C_ADDRESS CUSTOM_IO_EXPANDER_I2C_CH32V003_ADDRESS
|
||||
|
||||
#define DISPLAY_SDA_PIN I2C_SDA_IO
|
||||
#define DISPLAY_SCL_PIN I2C_SCL_IO
|
||||
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_2
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_1
|
||||
#define DISPLAY_SCLK_PIN GPIO_NUM_5
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_6
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_3
|
||||
#define DISPLAY_RESET_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SPI_SCLK_HZ (40 * 1000 * 1000)
|
||||
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAMERA_PIN_RESET GPIO_NUM_NC
|
||||
#define CAMERA_PIN_XCLK GPIO_NUM_38
|
||||
#define CAMERA_PIN_SIOD GPIO_NUM_NC
|
||||
#define CAMERA_PIN_SIOC GPIO_NUM_NC
|
||||
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_21
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_39
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_40
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_42
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_46
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_48
|
||||
#define CAMERA_PIN_D1 GPIO_NUM_47
|
||||
#define CAMERA_PIN_D0 GPIO_NUM_45
|
||||
#define CAMERA_PIN_VSYNC GPIO_NUM_17
|
||||
#define CAMERA_PIN_HREF GPIO_NUM_18
|
||||
#define CAMERA_PIN_PCLK GPIO_NUM_41
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_2INCH
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 320
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_2_8INCH
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 320
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_3_5INCH
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 480
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_1_83INCH
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 284
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
38
main/boards/waveshare/esp32-s3-cam/config.json
Normal file
38
main/boards/waveshare/esp32-s3-cam/config.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-cam-2",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_2INCH=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-cam-2.8",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_2_8INCH=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-cam-3.5",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_3_5INCH=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-cam-1.83",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_1_83INCH=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
282
main/boards/waveshare/esp32-s3-cam/esp32-s3-cam-xxxx.cc
Normal file
282
main/boards/waveshare/esp32-s3-cam/esp32-s3-cam-xxxx.cc
Normal file
@@ -0,0 +1,282 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp32_camera.h"
|
||||
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "custom_io_expander_ch32v003.h"
|
||||
#include "esp_lcd_st7796.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
#define TAG "waveshare_s3_cam_xxxx"
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x0BULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
void switch_to_main(void)
|
||||
{
|
||||
const esp_partition_t *factory_part =
|
||||
esp_partition_find_first(ESP_PARTITION_TYPE_APP,
|
||||
ESP_PARTITION_SUBTYPE_APP_FACTORY,
|
||||
NULL);
|
||||
if (!factory_part) {
|
||||
ESP_LOGE("APP_SWITCH", "未找到 factory 分区");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_ota_set_boot_partition(factory_part);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI("APP_SWITCH", "已设置 factory 为启动分区,重启回到主程序");
|
||||
esp_restart();
|
||||
} else {
|
||||
ESP_LOGE("APP_SWITCH", "设置启动分区失败: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_io_expander_handle_t io_handle)
|
||||
: Backlight(), io_handle_(io_handle) {}
|
||||
|
||||
protected:
|
||||
esp_io_expander_handle_t io_handle_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
if (brightness > 100) brightness = 100;
|
||||
int flipped_brightness = 100 - brightness;
|
||||
|
||||
custom_io_expander_set_pwm(io_handle_, flipped_brightness * 255 / 100);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
LcdDisplay* display_;
|
||||
Esp32Camera* camera_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
CustomBacklight *backlight_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)1,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void Initialize_Expander(void)
|
||||
{
|
||||
|
||||
custom_io_expander_new_i2c_ch32v003(i2c_bus_, BSP_IO_EXPANDER_I2C_ADDRESS, &io_expander);
|
||||
esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_6, IO_EXPANDER_OUTPUT);
|
||||
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 , 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 , 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 , 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_6 , 1);
|
||||
|
||||
//custom_io_expander_set_pwm(io_expander,100);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = DISPLAY_SCLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeSt7789Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片ST7789
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel,true));
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(io_expander);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeSt7796Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片ST7789
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7796(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel,true));
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(io_expander);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
boot_button_.OnLongPress([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
switch_to_main();
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
boot_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t camera_config = {
|
||||
.pin_pwdn = CAMERA_PIN_PWDN,
|
||||
.pin_reset = CAMERA_PIN_RESET,
|
||||
.pin_xclk = CAMERA_PIN_XCLK,
|
||||
.pin_sccb_sda = -1, // Use initialized I2C
|
||||
.pin_sccb_scl = -1,
|
||||
.pin_d7 = CAMERA_PIN_D7,
|
||||
.pin_d6 = CAMERA_PIN_D6,
|
||||
.pin_d5 = CAMERA_PIN_D5,
|
||||
.pin_d4 = CAMERA_PIN_D4,
|
||||
.pin_d3 = CAMERA_PIN_D3,
|
||||
.pin_d2 = CAMERA_PIN_D2,
|
||||
.pin_d1 = CAMERA_PIN_D1,
|
||||
.pin_d0 = CAMERA_PIN_D0,
|
||||
.pin_vsync = CAMERA_PIN_VSYNC,
|
||||
.pin_href = CAMERA_PIN_HREF,
|
||||
.pin_pclk = CAMERA_PIN_PCLK,
|
||||
|
||||
.xclk_freq_hz = XCLK_FREQ_HZ,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
|
||||
.pixel_format = PIXFORMAT_RGB565,
|
||||
.frame_size = FRAMESIZE_QVGA,
|
||||
.jpeg_quality = 12,
|
||||
.fb_count = 2,
|
||||
.fb_location = CAMERA_FB_IN_PSRAM,
|
||||
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
|
||||
.sccb_i2c_port = (i2c_port_t)1,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(camera_config);
|
||||
if (camera_ != nullptr) {
|
||||
camera_->SetVFlip(true);
|
||||
}
|
||||
}
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
Initialize_Expander();
|
||||
InitializeSpi();
|
||||
InitializeButtons();
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_2INCH
|
||||
InitializeSt7789Display();
|
||||
#elif CONFIG_BSP_LCD_SIZE_2_8INCH
|
||||
InitializeSt7789Display();
|
||||
#elif CONFIG_BSP_LCD_SIZE_1_83INCH
|
||||
InitializeSt7789Display();
|
||||
#elif CONFIG_BSP_LCD_SIZE_3_5INCH
|
||||
InitializeSt7796Display();
|
||||
#endif
|
||||
|
||||
InitializeCamera();
|
||||
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(i2c_bus_, 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, AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Camera* GetCamera() override {
|
||||
return camera_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
55
main/boards/waveshare/esp32-s3-epaper-1.54/README.md
Normal file
55
main/boards/waveshare/esp32-s3-epaper-1.54/README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-ePaper-1.54](https://www.waveshare.net/shop/ESP32-S3-ePaper-1.54.htm)
|
||||
|
||||
```bash
|
||||
esptool.py flash_id
|
||||
V1: 4MB Flash, 2MB PSRAM
|
||||
V2: 8MB Flash, 8MB PSRAM
|
||||
```
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```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_v2
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```bash
|
||||
python ./scripts/release.py --name esp32-s3-epaper-1.54-v1 waveshare/esp32-s3-epaper-1.54
|
||||
python ./scripts/release.py --name esp32-s3-epaper-1.54-v2 waveshare/esp32-s3-epaper-1.54
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py flash monitor
|
||||
```
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <stdio.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#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(4800));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
23
main/boards/waveshare/esp32-s3-epaper-1.54/board_power_bsp.h
Normal file
23
main/boards/waveshare/esp32-s3-epaper-1.54/board_power_bsp.h
Normal file
@@ -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
|
||||
50
main/boards/waveshare/esp32-s3-epaper-1.54/config.h
Normal file
50
main/boards/waveshare/esp32-s3-epaper-1.54/config.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#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_
|
||||
23
main/boards/waveshare/esp32-s3-epaper-1.54/config.json
Normal file
23
main/boards/waveshare/esp32-s3-epaper-1.54/config.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-epaper-1.54-v2",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\"",
|
||||
"CONFIG_USE_MULTILINE_CHAT_MESSAGE=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-epaper-1.54-v1",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MODE_QUAD=y",
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/4m.csv\"",
|
||||
"CONFIG_USE_MULTILINE_CHAT_MESSAGE=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
403
main/boards/waveshare/esp32-s3-epaper-1.54/custom_lcd_display.cc
Normal file
403
main/boards/waveshare/esp32-s3-epaper-1.54/custom_lcd_display.cc
Normal file
@@ -0,0 +1,403 @@
|
||||
#include <stdio.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <vector>
|
||||
#include <esp_log.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
// Note: SetupUI() should be called by Application::Initialize(), not in constructor
|
||||
// to ensure lvgl objects are created after the display is fully initialized.
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef __CUSTOM_LCD_DISPLAY_H__
|
||||
#define __CUSTOM_LCD_DISPLAY_H__
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#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__
|
||||
@@ -0,0 +1,172 @@
|
||||
#include <stdio.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.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();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
EnterWifiConfigMode();
|
||||
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));
|
||||
}
|
||||
|
||||
uint16_t BatterygetVoltage(void) {
|
||||
static bool initialized = false;
|
||||
static adc_oneshot_unit_handle_t adc_handle;
|
||||
static adc_cali_handle_t cali_handle = NULL;
|
||||
if (!initialized) {
|
||||
adc_oneshot_unit_init_cfg_t init_config = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
};
|
||||
adc_oneshot_new_unit(&init_config, &adc_handle);
|
||||
|
||||
adc_oneshot_chan_cfg_t ch_config = {
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
adc_oneshot_config_channel(adc_handle, ADC_CHANNEL_3, &ch_config);
|
||||
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
if (adc_cali_create_scheme_curve_fitting(&cali_config, &cali_handle) == ESP_OK) {
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
int raw_value = 0;
|
||||
int raw_voltage = 0;
|
||||
int voltage = 0; // mV
|
||||
adc_oneshot_read(adc_handle, ADC_CHANNEL_3, &raw_value);
|
||||
adc_cali_raw_to_voltage(cali_handle, raw_value, &raw_voltage);
|
||||
voltage = raw_voltage * 2;
|
||||
// ESP_LOGI(TAG, "voltage: %dmV", voltage);
|
||||
return (uint16_t)voltage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t BatterygetPercent() {
|
||||
int voltage = 0;
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
voltage += BatterygetVoltage();
|
||||
}
|
||||
|
||||
voltage /= 10;
|
||||
int percent = (-1 * voltage * voltage + 9016 * voltage - 19189000) / 10000;
|
||||
percent = (percent > 100) ? 100 : (percent < 0) ? 0 : percent;
|
||||
// ESP_LOGI(TAG, "voltage: %dmV, percentage: %d%%", voltage, percent);
|
||||
return (uint8_t)percent;
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
charging = false;
|
||||
discharging = !charging;
|
||||
level = (int)BatterygetPercent();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
48
main/boards/waveshare/esp32-s3-epaper-3.97/README.md
Normal file
48
main/boards/waveshare/esp32-s3-epaper-3.97/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-ePaper-3.97](https://www.waveshare.net/shop/ESP32-S3-ePaper-3.97.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-3.97
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
44
main/boards/waveshare/esp32-s3-epaper-3.97/config.h
Normal file
44
main/boards/waveshare/esp32-s3-epaper-3.97/config.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_47
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_14
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_48
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_39
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_41
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_42
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VBAT_PWR_GPIO GPIO_NUM_1
|
||||
|
||||
#define EPD_SPI_NUM SPI3_HOST
|
||||
|
||||
#define EPD_DC_PIN GPIO_NUM_9
|
||||
#define EPD_CS_PIN GPIO_NUM_10
|
||||
#define EPD_SCK_PIN GPIO_NUM_11
|
||||
#define EPD_MOSI_PIN GPIO_NUM_12
|
||||
#define EPD_RST_PIN GPIO_NUM_46
|
||||
#define EPD_BUSY_PIN GPIO_NUM_3
|
||||
|
||||
#define EXAMPLE_LCD_WIDTH 800
|
||||
#define EXAMPLE_LCD_HEIGHT 480
|
||||
|
||||
#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_
|
||||
12
main/boards/waveshare/esp32-s3-epaper-3.97/config.json
Normal file
12
main/boards/waveshare/esp32-s3-epaper-3.97/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-epaper-3.97",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
393
main/boards/waveshare/esp32-s3-epaper-3.97/custom_lcd_display.cc
Normal file
393
main/boards/waveshare/esp32-s3-epaper-3.97/custom_lcd_display.cc
Normal file
@@ -0,0 +1,393 @@
|
||||
#include "custom_lcd_display.h"
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include "board.h"
|
||||
#include "config.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define TAG "CustomEpdDisplay"
|
||||
|
||||
#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)
|
||||
|
||||
void CustomEpdDisplay::lvgl_flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* color_p) {
|
||||
assert(disp != NULL);
|
||||
CustomEpdDisplay* driver = (CustomEpdDisplay*)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);
|
||||
}
|
||||
|
||||
CustomEpdDisplay::CustomEpdDisplay(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_epd_spi_t _epd_spi_data)
|
||||
: LcdDisplay(panel_io, panel, width, height),
|
||||
epd_spi_data(_epd_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(epd_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();
|
||||
ESP_LOGI(TAG, "EPD Clear");
|
||||
EPD_Clear();
|
||||
EPD_Display();
|
||||
|
||||
lvgl_port_unlock();
|
||||
if (display_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to add display");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "ui start");
|
||||
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
CustomEpdDisplay::~CustomEpdDisplay() {}
|
||||
|
||||
void CustomEpdDisplay::spi_gpio_init() {
|
||||
int rst = epd_spi_data.rst;
|
||||
int cs = epd_spi_data.cs;
|
||||
int dc = epd_spi_data.dc;
|
||||
int busy = epd_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 CustomEpdDisplay::spi_port_init() {
|
||||
int mosi = epd_spi_data.mosi;
|
||||
int scl = epd_spi_data.scl;
|
||||
int spi_host = epd_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 = 4096;
|
||||
|
||||
spi_device_interface_config_t devcfg = {};
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.clock_speed_hz = 20 * 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 CustomEpdDisplay::read_busy() {
|
||||
int busy = epd_spi_data.busy;
|
||||
while (gpio_get_level((gpio_num_t)busy) == 1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(5)); // LOW: idle, HIGH: busy
|
||||
}
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::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 CustomEpdDisplay::EPD_SendData(uint8_t data) {
|
||||
set_dc_1();
|
||||
set_cs_0();
|
||||
SPI_SendByte(data);
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_SendCommand(uint8_t command) {
|
||||
set_dc_0();
|
||||
set_cs_0();
|
||||
SPI_SendByte(command);
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::writeBytes(uint8_t* buffer, int len) {
|
||||
set_dc_1();
|
||||
set_cs_0();
|
||||
|
||||
const int MAX_SPI_TRANSFER = 4096;
|
||||
|
||||
int remaining = len;
|
||||
int offset = 0;
|
||||
|
||||
while (remaining > 0) {
|
||||
int chunk_size = (remaining > MAX_SPI_TRANSFER) ? MAX_SPI_TRANSFER : remaining;
|
||||
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.length = 8 * chunk_size;
|
||||
t.tx_buffer = buffer + offset;
|
||||
ret = spi_device_polling_transmit(spi, &t); // Transmit!
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SPI transmit failed at offset %d, chunk %d: %s", offset, chunk_size,
|
||||
esp_err_to_name(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
remaining -= chunk_size;
|
||||
offset += chunk_size;
|
||||
}
|
||||
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::writeBytes(const uint8_t* buffer, int len) {
|
||||
set_dc_1();
|
||||
set_cs_0();
|
||||
|
||||
const int MAX_SPI_TRANSFER = 4096;
|
||||
|
||||
int remaining = len;
|
||||
int offset = 0;
|
||||
|
||||
while (remaining > 0) {
|
||||
int chunk_size = (remaining > MAX_SPI_TRANSFER) ? MAX_SPI_TRANSFER : remaining;
|
||||
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.length = 8 * chunk_size;
|
||||
t.tx_buffer = buffer + offset;
|
||||
ret = spi_device_polling_transmit(spi, &t); // Transmit!
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SPI transmit failed at offset %d, chunk %d: %s", offset, chunk_size,
|
||||
esp_err_to_name(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
remaining -= chunk_size;
|
||||
offset += chunk_size;
|
||||
}
|
||||
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::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 * 8) & 0xFF);
|
||||
EPD_SendData(((Xstart * 8) >> 8) & 0xFF);
|
||||
EPD_SendData((Xend * 8) & 0xFF);
|
||||
EPD_SendData(((Xend * 8) >> 8) & 0xFF);
|
||||
|
||||
EPD_SendCommand(0x45); // SET_RAM_Y_ADDRESS_START_END_POSITION
|
||||
EPD_SendData(Yend & 0xFF);
|
||||
EPD_SendData((Yend >> 8) & 0xFF);
|
||||
EPD_SendData(Ystart & 0xFF);
|
||||
EPD_SendData((Ystart >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_SetCursor(uint16_t Xstart, uint16_t Ystart) {
|
||||
EPD_SendCommand(0x4E);
|
||||
EPD_SendData((Xstart * 8) & 0xFF);
|
||||
EPD_SendData(((Xstart * 8) >> 8) & 0xFF);
|
||||
|
||||
EPD_SendCommand(0x4F);
|
||||
EPD_SendData(Ystart & 0xFF);
|
||||
EPD_SendData((Ystart >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_TurnOnDisplay() {
|
||||
EPD_SendCommand(0x22);
|
||||
EPD_SendData(0xF7);
|
||||
EPD_SendCommand(0x20);
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_TurnOnDisplayPart() {
|
||||
EPD_SendCommand(0x22);
|
||||
EPD_SendData(0xFF);
|
||||
EPD_SendCommand(0x20);
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Init() {
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
set_rst_0();
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
read_busy();
|
||||
EPD_SendCommand(0x12); // SWRESET
|
||||
read_busy();
|
||||
|
||||
EPD_SendCommand(0x18);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SendCommand(0x0C); // Driver output control
|
||||
EPD_SendData(0xAE);
|
||||
EPD_SendData(0xC7);
|
||||
EPD_SendData(0xC3);
|
||||
EPD_SendData(0xC0);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SendCommand(0x01); // Driver output control
|
||||
EPD_SendData((Height - 1) % 256);
|
||||
EPD_SendData((Height - 1) / 256);
|
||||
EPD_SendData(0x02);
|
||||
|
||||
EPD_SendCommand(0x3C); // BorderWavefrom
|
||||
EPD_SendData(0x01);
|
||||
|
||||
EPD_SendCommand(0x11); // data entry mode
|
||||
EPD_SendData(0x01);
|
||||
|
||||
EPD_SendCommand(0x44); // set Ram-X address start/end position
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData((Width - 1) % 256);
|
||||
EPD_SendData((Width - 1) / 256);
|
||||
|
||||
EPD_SendCommand(0x45); // set Ram-Y address start/end position
|
||||
EPD_SendData((Height - 1) % 256);
|
||||
EPD_SendData((Height - 1) / 256);
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
|
||||
EPD_SendCommand(0x4E); // set RAM x address count to 0;
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendCommand(0x4F); // set RAM y address count to 0X199;
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Clear() {
|
||||
int buffer_len = epd_spi_data.buffer_len;
|
||||
memset(buffer, 0xff, buffer_len);
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Display() {
|
||||
int buffer_len = epd_spi_data.buffer_len;
|
||||
EPD_SendCommand(0x24);
|
||||
assert(buffer);
|
||||
writeBytes(buffer, buffer_len);
|
||||
EPD_TurnOnDisplay();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_DisplayPartBaseImage() {
|
||||
int buffer_len = epd_spi_data.buffer_len;
|
||||
EPD_SendCommand(0x24);
|
||||
assert(buffer);
|
||||
writeBytes(buffer, buffer_len);
|
||||
EPD_SendCommand(0x26);
|
||||
writeBytes(buffer, buffer_len);
|
||||
EPD_TurnOnDisplay();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Init_Partial() {
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
set_rst_0();
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
read_busy();
|
||||
|
||||
EPD_SendCommand(0x18);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SendCommand(0x3C);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SetWindows(0, Width - 1, Height - 1, 0);
|
||||
|
||||
EPD_SetCursor(0, Height - 1);
|
||||
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_DisplayPart() {
|
||||
EPD_SendCommand(0x24);
|
||||
assert(buffer);
|
||||
writeBytes(buffer, 48000);
|
||||
EPD_TurnOnDisplayPart();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Sleep() {
|
||||
EPD_SendCommand(0x10); // enter deep sleep
|
||||
EPD_SendData(0x01);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
set_rst_0();
|
||||
set_cs_0();
|
||||
set_dc_0();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::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 * Width / 8 + (x >> 3);
|
||||
uint8_t bit = 7 - (x & 0x07);
|
||||
if (color == DRIVER_COLOR_WHITE) {
|
||||
buffer[index] |= (0x01 << bit);
|
||||
} else {
|
||||
buffer[index] &= ~(0x01 << bit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef __CUSTOM_LCD_DISPLAY_H__
|
||||
#define __CUSTOM_LCD_DISPLAY_H__
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#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_epd_spi_t;
|
||||
|
||||
class CustomEpdDisplay : public LcdDisplay {
|
||||
public:
|
||||
CustomEpdDisplay(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_epd_spi_t _epd_spi_data);
|
||||
~CustomEpdDisplay();
|
||||
|
||||
void EPD_Init(); /* 墨水屏初始化 */
|
||||
void EPD_Clear(); /* 清空屏幕 */
|
||||
void EPD_Display(); /* 刷buffer到墨水屏 */
|
||||
void EPD_Sleep();
|
||||
|
||||
/*快速刷新*/
|
||||
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_epd_spi_t epd_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)epd_spi_data.cs, 1); }
|
||||
void set_cs_0() { gpio_set_level((gpio_num_t)epd_spi_data.cs, 0); }
|
||||
void set_dc_1() { gpio_set_level((gpio_num_t)epd_spi_data.dc, 1); }
|
||||
void set_dc_0() { gpio_set_level((gpio_num_t)epd_spi_data.dc, 0); }
|
||||
void set_rst_1() { gpio_set_level((gpio_num_t)epd_spi_data.rst, 1); }
|
||||
void set_rst_0() { gpio_set_level((gpio_num_t)epd_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_TurnOnDisplay();
|
||||
void EPD_TurnOnDisplayPart();
|
||||
};
|
||||
|
||||
#endif // __CUSTOM_LCD_DISPLAY_H__
|
||||
@@ -0,0 +1,178 @@
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.h>
|
||||
#include <stdio.h>
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "config.h"
|
||||
#include "custom_lcd_display.h"
|
||||
#include "lvgl.h"
|
||||
#include "mcp_server.h"
|
||||
#include "wifi_board.h"
|
||||
|
||||
#include "axp2101.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "i2c_device.h"
|
||||
#include "power_save_timer.h"
|
||||
|
||||
#define TAG "waveshare_epaper_3_97"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
// Set ALDO2 to 3.3V
|
||||
WriteReg(0x93, (3300 - 500) / 100);
|
||||
// Set ALDO3 to 3.3V
|
||||
WriteReg(0x94, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1、ALDO2、ALDO2
|
||||
WriteReg(0x90, 0x07);
|
||||
|
||||
WriteReg(0x64, 0x03); // CV charger voltage setting to 4.2V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA,
|
||||
// 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32s3ePaper3inch97 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
Button pwr_button_;
|
||||
CustomEpdDisplay* display_;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 100, 300);
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
GetDisplay()->SetChatMessage("system", "OFF");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
pmic_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
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();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode
|
||||
// without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
pwr_button_.OnClick([this]() {
|
||||
GetDisplay()->SetChatMessage("system", "OFF");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
pmic_->PowerOff();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeTools() {
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.disp.network", "重新配网", PropertyList(),
|
||||
[this](const PropertyList&) -> ReturnValue {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeEpdDisplay() {
|
||||
custom_epd_spi_t epd_spi_data = {};
|
||||
epd_spi_data.cs = EPD_CS_PIN;
|
||||
epd_spi_data.dc = EPD_DC_PIN;
|
||||
epd_spi_data.rst = EPD_RST_PIN;
|
||||
epd_spi_data.busy = EPD_BUSY_PIN;
|
||||
epd_spi_data.mosi = EPD_MOSI_PIN;
|
||||
epd_spi_data.scl = EPD_SCK_PIN;
|
||||
epd_spi_data.spi_host = EPD_SPI_NUM;
|
||||
epd_spi_data.buffer_len = 48000;
|
||||
display_ = new CustomEpdDisplay(NULL, NULL, EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT,
|
||||
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X,
|
||||
DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY, epd_spi_data);
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32s3ePaper3inch97()
|
||||
: boot_button_(BOOT_BUTTON_GPIO), pwr_button_(VBAT_PWR_GPIO, 1) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
InitializeEpdDisplay();
|
||||
}
|
||||
|
||||
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 bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override { return display_; }
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32s3ePaper3inch97);
|
||||
60
main/boards/waveshare/esp32-s3-lcd-0.85/README.md
Normal file
60
main/boards/waveshare/esp32-s3-lcd-0.85/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-LCD-0.85](https://www.waveshare.net/shop/ESP32-S3-LCD-0.85.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32S3
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-S3-LCD-0.85
|
||||
```
|
||||
|
||||
**修改 flash 大小:**
|
||||
|
||||
```
|
||||
Serial flasher config -> Flash size -> 8 MB
|
||||
```
|
||||
|
||||
**修改分区表:**
|
||||
|
||||
```
|
||||
Partition Table -> Custom partition CSV file -> partitions/v2/8m.csv
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
56
main/boards/waveshare/esp32-s3-lcd-0.85/config.h
Normal file
56
main/boards/waveshare/esp32-s3-lcd-0.85/config.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_8
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_9
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_12
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_42
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_41
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_48
|
||||
#define PWR_BUTTON_GPIO GPIO_NUM_5
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_4
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define DISPLAY_SPI_MODE 3
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_21
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_39
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_CLK_PIN GPIO_NUM_38
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_45
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_40
|
||||
|
||||
#define TOOUCH_INT_PIN GPIO_NUM_48
|
||||
#define TOOUCH_RST_PIN GPIO_NUM_47
|
||||
|
||||
#define BATTERY_EN_PIN GPIO_NUM_2
|
||||
#define BATTERY_ADC_PIN GPIO_NUM_1
|
||||
#define BATTERY_CHARGING_PIN GPIO_NUM_3
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 128
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_RGB_ORDER LCD_RGB_ELEMENT_ORDER_BGR
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
|
||||
#define DISPLAY_OFFSET_X 2
|
||||
#define DISPLAY_OFFSET_Y 1
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_46
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
15
main/boards/waveshare/esp32-s3-lcd-0.85/config.json
Normal file
15
main/boards/waveshare/esp32-s3-lcd-0.85/config.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-lcd-0.85",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
311
main/boards/waveshare/esp32-s3-lcd-0.85/esp32-s3-lcd-0.85.cc
Normal file
311
main/boards/waveshare/esp32-s3-lcd-0.85/esp32-s3-lcd-0.85.cc
Normal file
@@ -0,0 +1,311 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "mcp_server.h"
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_timer.h>
|
||||
#include "power_save_timer.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include <esp_lvgl_port.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "iot_button.h"
|
||||
#include "power_manager.h"
|
||||
#include "led/circular_strip.h"
|
||||
#include "led_strip_control.h"
|
||||
|
||||
#define TAG "waveshare_lcd_0_85"
|
||||
|
||||
|
||||
class CustomButton: public Button{
|
||||
public:
|
||||
void OnPressDownDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_down_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_DOWN, nullptr);
|
||||
}
|
||||
void OnPressUpDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_up_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_UP, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
CustomButton pwr_button_;
|
||||
CustomButton volume_up_button_;
|
||||
CustomButton volume_down_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
CircularStrip* led_strip_;
|
||||
LcdDisplay* display_;
|
||||
PowerManager* power_manager_ = nullptr;
|
||||
PowerSaveTimer* power_save_timer_ = nullptr;
|
||||
|
||||
void InitializePowerManager() {
|
||||
power_manager_ = new PowerManager(BATTERY_CHARGING_PIN, BATTERY_ADC_PIN, BATTERY_EN_PIN);
|
||||
power_manager_->PowerON();
|
||||
}
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
ESP_LOGI(TAG, "Enabling sleep mode");
|
||||
auto display = GetDisplay();
|
||||
display->SetChatMessage("system", "");
|
||||
display->SetEmotion("sleepy");
|
||||
GetBacklight()->SetBrightness(20);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
auto display = GetDisplay();
|
||||
display->SetChatMessage("system", "");
|
||||
display->SetEmotion("neutral");
|
||||
GetBacklight()->RestoreBrightness();
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
power_manager_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = DISPLAY_MISO_PIN;
|
||||
buscfg.sclk_io_num = DISPLAY_CLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLed() {
|
||||
led_strip_ = new CircularStrip(BUILTIN_LED_GPIO, 8);
|
||||
new LedStripControl(led_strip_);
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = DISPLAY_SPI_MODE;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
|
||||
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGI(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
|
||||
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
|
||||
pwr_button_.OnPressUp([this]() {
|
||||
pwr_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
app.ToggleChatState();
|
||||
});
|
||||
pwr_button_.OnLongPress([this]() {
|
||||
printf("Power button long press\n");
|
||||
if (power_manager_ != nullptr){
|
||||
power_manager_->PowerOff();
|
||||
}
|
||||
});
|
||||
|
||||
pwr_button_.OnDoubleClick([this]() {
|
||||
static uint8_t brightness_last = 0;
|
||||
auto backlight = Board::GetInstance().GetBacklight();
|
||||
if (backlight->brightness() == 0) {
|
||||
brightness_last = 0;
|
||||
if (brightness_last == 0) {
|
||||
backlight->SetBrightness(50, true);
|
||||
} else {
|
||||
backlight->SetBrightness(brightness_last, true);
|
||||
}
|
||||
} else {
|
||||
brightness_last = backlight->brightness();
|
||||
backlight->SetBrightness(0);
|
||||
}
|
||||
});
|
||||
pwr_button_.OnMultipleClick([this]() {
|
||||
EnterWifiConfigMode();
|
||||
}, 3);
|
||||
pwr_button_.OnPressUpDel();
|
||||
});
|
||||
|
||||
volume_up_button_.OnClick([this]() {
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
auto volume = codec->output_volume() + 10;
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume/10));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
Board::GetInstance().GetAudioCodec()->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
auto volume = codec->output_volume() - 10;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume/10));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
Board::GetInstance().GetAudioCodec()->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MUTED);
|
||||
});
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
volume_down_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"Reboot the device and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
pwr_button_(PWR_BUTTON_GPIO),
|
||||
volume_up_button_(VOLUME_UP_BUTTON_GPIO),
|
||||
volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) {
|
||||
InitializePowerManager();
|
||||
InitializePowerSaveTimer();
|
||||
InitializeI2c();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeButtons();
|
||||
InitializeLed();
|
||||
InitializeTools();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
true);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
return led_strip_;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = power_manager_->IsCharging();
|
||||
discharging = power_manager_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = power_manager_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
130
main/boards/waveshare/esp32-s3-lcd-0.85/led_strip_control.cc
Normal file
130
main/boards/waveshare/esp32-s3-lcd-0.85/led_strip_control.cc
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "led_strip_control.h"
|
||||
#include "settings.h"
|
||||
#include "mcp_server.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "LedStripControl"
|
||||
|
||||
|
||||
int LedStripControl::LevelToBrightness(int level) const {
|
||||
if (level < 0) level = 0;
|
||||
if (level > 8) level = 8;
|
||||
return (1 << level) - 1; // 2^n - 1
|
||||
}
|
||||
|
||||
StripColor LedStripControl::RGBToColor(int red, int green, int blue) {
|
||||
if (red < 0) red = 0;
|
||||
if (red > 255) red = 255;
|
||||
if (green < 0) green = 0;
|
||||
if (green > 255) green = 255;
|
||||
if (blue < 0) blue = 0;
|
||||
if (blue > 255) blue = 255;
|
||||
return {static_cast<uint8_t>(red), static_cast<uint8_t>(green), static_cast<uint8_t>(blue)};
|
||||
}
|
||||
|
||||
LedStripControl::LedStripControl(CircularStrip* led_strip)
|
||||
: led_strip_(led_strip) {
|
||||
// 从设置中读取亮度等级
|
||||
Settings settings("led_strip");
|
||||
brightness_level_ = settings.GetInt("brightness", 4); // 默认等级4
|
||||
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
||||
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.led_strip.get_brightness",
|
||||
"Get the brightness of the led strip (0-8)",
|
||||
PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||
return brightness_level_;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.set_brightness",
|
||||
"Set the brightness of the led strip (0-8)",
|
||||
PropertyList({
|
||||
Property("level", kPropertyTypeInteger, 0, 8)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int level = properties["level"].value<int>();
|
||||
ESP_LOGI(TAG, "Set LedStrip brightness level to %d", level);
|
||||
brightness_level_ = level;
|
||||
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
||||
|
||||
// 保存设置
|
||||
Settings settings("led_strip", true);
|
||||
settings.SetInt("brightness", brightness_level_);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.set_single_color",
|
||||
"Set the color of a single led.",
|
||||
PropertyList({
|
||||
Property("index", kPropertyTypeInteger, 0, 7),
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int index = properties["index"].value<int>();
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
ESP_LOGI(TAG, "Set led strip single color %d to %d, %d, %d",
|
||||
index, red, green, blue);
|
||||
led_strip_->SetSingleColor(index, RGBToColor(green, red, blue));
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.set_all_color",
|
||||
"Set the color of all leds.",
|
||||
PropertyList({
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
ESP_LOGI(TAG, "Set led strip all color to %d, %d, %d",
|
||||
red, green, blue);
|
||||
led_strip_->SetAllColor(RGBToColor(green, red, blue));
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.blink",
|
||||
"Blink the led strip. (闪烁)",
|
||||
PropertyList({
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255),
|
||||
Property("interval", kPropertyTypeInteger, 0, 1000)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
int interval = properties["interval"].value<int>();
|
||||
ESP_LOGI(TAG, "Blink led strip with color %d, %d, %d, interval %dms",
|
||||
red, green, blue, interval);
|
||||
led_strip_->Blink(RGBToColor(green, red, blue), interval);
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.scroll",
|
||||
"Scroll the led strip. (跑马灯)",
|
||||
PropertyList({
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255),
|
||||
Property("length", kPropertyTypeInteger, 1, 7),
|
||||
Property("interval", kPropertyTypeInteger, 0, 1000)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
int interval = properties["interval"].value<int>();
|
||||
int length = properties["length"].value<int>();
|
||||
ESP_LOGI(TAG, "Scroll led strip with color %d, %d, %d, length %d, interval %dms",
|
||||
red, green, blue, length, interval);
|
||||
StripColor low = RGBToColor(4, 4, 4);
|
||||
StripColor high = RGBToColor(green, red, blue);
|
||||
led_strip_->Scroll(low, high, length, interval);
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
18
main/boards/waveshare/esp32-s3-lcd-0.85/led_strip_control.h
Normal file
18
main/boards/waveshare/esp32-s3-lcd-0.85/led_strip_control.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef LED_STRIP_CONTROL_H
|
||||
#define LED_STRIP_CONTROL_H
|
||||
|
||||
#include "led/circular_strip.h"
|
||||
|
||||
class LedStripControl {
|
||||
private:
|
||||
CircularStrip* led_strip_;
|
||||
int brightness_level_; // 亮度等级 (0-8)
|
||||
|
||||
int LevelToBrightness(int level) const; // 将等级转换为实际亮度值
|
||||
StripColor RGBToColor(int red, int green, int blue);
|
||||
|
||||
public:
|
||||
explicit LedStripControl(CircularStrip* led_strip);
|
||||
};
|
||||
|
||||
#endif // LED_STRIP_CONTROL_H
|
||||
212
main/boards/waveshare/esp32-s3-lcd-0.85/power_manager.h
Normal file
212
main/boards/waveshare/esp32-s3-lcd-0.85/power_manager.h
Normal file
@@ -0,0 +1,212 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class PowerManager
|
||||
{
|
||||
private:
|
||||
gpio_num_t charging_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_adc_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_power_pin_ = GPIO_NUM_NC;
|
||||
adc_oneshot_unit_handle_t adc_handle_ = NULL;
|
||||
adc_cali_handle_t adc_cali_handle_ = NULL;
|
||||
adc_channel_t adc_channel_;
|
||||
bool do_calibration = false;
|
||||
bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
|
||||
{
|
||||
adc_cali_handle_t handle = NULL;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
bool calibrated = false;
|
||||
|
||||
if (!calibrated)
|
||||
{
|
||||
ESP_LOGI("power_manager", "calibration scheme version is %s", "Curve Fitting");
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.chan = channel,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
*out_handle = handle;
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
ESP_LOGI("power_manager", "Calibration Success");
|
||||
}
|
||||
else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated)
|
||||
{
|
||||
ESP_LOGW("power_manager", "eFuse not burnt, skip software calibration");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE("power_manager", "Invalid arg or no memory");
|
||||
}
|
||||
return calibrated;
|
||||
}
|
||||
|
||||
public:
|
||||
PowerManager(gpio_num_t charging_pin, gpio_num_t bat_adc_pin, gpio_num_t bat_power_pin) : charging_pin_(charging_pin),
|
||||
bat_adc_pin_(bat_adc_pin),
|
||||
bat_power_pin_(bat_power_pin)
|
||||
{
|
||||
// 初始化充电引脚
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << charging_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
// 初始化电池使能引脚
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << bat_power_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
// 初始化adc
|
||||
if (bat_adc_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
adc_oneshot_unit_init_cfg_t init_config = {};
|
||||
init_config.ulp_mode = ADC_ULP_MODE_DISABLE;
|
||||
if (bat_adc_pin_ >= GPIO_NUM_1 && bat_adc_pin_ <= GPIO_NUM_10)
|
||||
{
|
||||
init_config.unit_id = ADC_UNIT_1;
|
||||
adc_channel_ = (adc_channel_t)((int)bat_adc_pin_ - 1);
|
||||
}
|
||||
else if (bat_adc_pin_ >= GPIO_NUM_11 && bat_adc_pin_ <= GPIO_NUM_20)
|
||||
{
|
||||
init_config.unit_id = ADC_UNIT_2;
|
||||
adc_channel_ = (adc_channel_t)((int)bat_adc_pin_ - 11);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle_));
|
||||
adc_oneshot_chan_cfg_t config = {};
|
||||
config.bitwidth = ADC_BITWIDTH_DEFAULT;
|
||||
config.atten = ADC_ATTEN_DB_12;
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle_, adc_channel_, &config));
|
||||
do_calibration = adc_calibration_init(init_config.unit_id, adc_channel_, config.atten, &adc_cali_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
~PowerManager()
|
||||
{
|
||||
if (adc_handle_)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_));
|
||||
}
|
||||
// if (adc_cali_handle_)
|
||||
// {
|
||||
// ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(adc_cali_handle_));
|
||||
// }
|
||||
}
|
||||
|
||||
int GetBatteryLevel(void)
|
||||
{
|
||||
|
||||
int adc_raw = 0;
|
||||
int voltage_int = 0;
|
||||
const float voltage_float_threshold = 0.1f;
|
||||
float voltage_float = 0.0f;
|
||||
static float last_voltage_float = 0.0f;
|
||||
|
||||
static int last_battery_level = 0;
|
||||
|
||||
if (adc_handle_ != nullptr)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, adc_channel_, &adc_raw));
|
||||
if (do_calibration)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle_, adc_raw, &voltage_int));
|
||||
voltage_float = (voltage_int / 1000.0f) * 3.0;
|
||||
|
||||
if (fabs(voltage_float - last_voltage_float) >= voltage_float_threshold)
|
||||
{
|
||||
last_voltage_float = voltage_float;
|
||||
if (voltage_float < 3.52) {
|
||||
last_battery_level = 1;
|
||||
} else if (voltage_float < 3.64) {
|
||||
last_battery_level = 20;
|
||||
} else if (voltage_float < 3.76) {
|
||||
last_battery_level = 40;
|
||||
} else if (voltage_float < 3.88) {
|
||||
last_battery_level = 60;
|
||||
} else if (voltage_float < 4.0) {
|
||||
last_battery_level = 80;
|
||||
} else {
|
||||
last_battery_level = 100;
|
||||
}
|
||||
}
|
||||
return last_battery_level;
|
||||
}
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
bool IsCharging(void)
|
||||
{
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
return gpio_get_level(charging_pin_) == 0 ? true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDischarging(void)
|
||||
{
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
return gpio_get_level(charging_pin_) == 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsChargingDone(void)
|
||||
{
|
||||
if (GetBatteryLevel() == 100)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void PowerOff(void)
|
||||
{
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_set_level(bat_power_pin_, 0);
|
||||
}
|
||||
}
|
||||
void PowerON(void)
|
||||
{
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_set_level(bat_power_pin_, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
48
main/boards/waveshare/esp32-s3-rlcd-4.2/README.md
Normal file
48
main/boards/waveshare/esp32-s3-rlcd-4.2/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-RLCD-4.2](https://www.waveshare.net/shop/ESP32-S3-RLCD-4.2.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-RLCD-4.2
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
46
main/boards/waveshare/esp32-s3-rlcd-4.2/config.h
Normal file
46
main/boards/waveshare/esp32-s3-rlcd-4.2/config.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define ESP32_I2C_HOST I2C_NUM_0
|
||||
#define ESP32_LCD_HOST SPI3_HOST
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_16
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_45
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_9
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_8
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_46
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_13
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_14
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
|
||||
#define RLCD_DC_PIN GPIO_NUM_5
|
||||
#define RLCD_CS_PIN GPIO_NUM_40
|
||||
#define RLCD_SCK_PIN GPIO_NUM_11
|
||||
#define RLCD_MOSI_PIN GPIO_NUM_12
|
||||
#define RLCD_RST_PIN GPIO_NUM_41
|
||||
#define RLCD_TE_PIN GPIO_NUM_6
|
||||
|
||||
#define RLCD_WIDTH 400
|
||||
#define RLCD_HEIGHT 300
|
||||
|
||||
#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
|
||||
13
main/boards/waveshare/esp32-s3-rlcd-4.2/config.json
Normal file
13
main/boards/waveshare/esp32-s3-rlcd-4.2/config.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-rlcd-4.2",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
338
main/boards/waveshare/esp32-s3-rlcd-4.2/custom_lcd_display.cc
Normal file
338
main/boards/waveshare/esp32-s3-rlcd-4.2/custom_lcd_display.cc
Normal file
@@ -0,0 +1,338 @@
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include "custom_lcd_display.h"
|
||||
#include "lcd_display.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "settings.h"
|
||||
#include "config.h"
|
||||
#include "board.h"
|
||||
|
||||
void CustomLcdDisplay::Lvgl_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p)
|
||||
{
|
||||
assert(disp != NULL);
|
||||
CustomLcdDisplay *Disp = (CustomLcdDisplay *)lv_display_get_user_data(disp);
|
||||
uint16_t *buffer = (uint16_t *)color_p;
|
||||
for(int y = area->y1; y <= area->y2; y++)
|
||||
{
|
||||
for(int x = area->x1; x <= area->x2; x++)
|
||||
{
|
||||
uint8_t color = (*buffer < 0x7fff) ? ColorBlack : ColorWhite;
|
||||
Disp->RLCD_SetPixel(x,y,color);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
Disp->RLCD_Display();
|
||||
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,
|
||||
spi_display_config_t spiconfig,
|
||||
spi_host_device_t spi_host) : LcdDisplay(panel_io, panel, width, height),
|
||||
mosi_(spiconfig.mosi),
|
||||
scl_(spiconfig.scl),
|
||||
dc_(spiconfig.dc),
|
||||
cs_(spiconfig.cs),
|
||||
rst_(spiconfig.rst),
|
||||
width_(width),
|
||||
height_(height)
|
||||
{
|
||||
ESP_LOGI(TAG, "Initialize SPI");
|
||||
esp_err_t ret;
|
||||
spi_bus_config_t buscfg = {};
|
||||
int transfer = width_ * height_;
|
||||
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 = transfer;
|
||||
ret = spi_bus_initialize(spi_host, &buscfg, SPI_DMA_CH_AUTO);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.dc_gpio_num = dc_;
|
||||
io_config.cs_gpio_num = cs_;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.trans_queue_depth = 7;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)spi_host, &io_config, &io_handle));
|
||||
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_);
|
||||
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));
|
||||
Set_ResetIOLevel(1);
|
||||
|
||||
DisplayLen = transfer >> 3; //(1byte 8ipex)
|
||||
DispBuffer = (uint8_t *) heap_caps_malloc(DisplayLen, MALLOC_CAP_SPIRAM);
|
||||
assert(DispBuffer);
|
||||
PixelIndexLUT = (uint16_t (*)[300])heap_caps_malloc(transfer * sizeof(uint16_t), MALLOC_CAP_SPIRAM);
|
||||
PixelBitLUT = (uint8_t (*)[300])heap_caps_malloc(transfer * sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
assert(PixelIndexLUT);
|
||||
assert(PixelBitLUT);
|
||||
if(width_ == 400) {
|
||||
InitLandscapeLUT();
|
||||
} else {
|
||||
InitPortraitLUT();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
display_ = lv_display_create(width, height); /* 以水平和垂直分辨率(像素)进行基本初始化 */
|
||||
lv_display_set_flush_cb(display_, Lvgl_flush_cb);
|
||||
lv_display_set_user_data(display_, this);
|
||||
size_t lvgl_buffer_size = LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565) * transfer;
|
||||
uint8_t *lvgl_buffer1 = (uint8_t *) heap_caps_malloc(lvgl_buffer_size, MALLOC_CAP_SPIRAM);
|
||||
assert(lvgl_buffer1);
|
||||
lv_display_set_buffers(display_, lvgl_buffer1, NULL, lvgl_buffer_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
ESP_LOGI(TAG, "RLCD init");
|
||||
RLCD_Init();
|
||||
|
||||
lvgl_port_unlock();
|
||||
if (display_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to add display");
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: SetupUI() should be called by Application::Initialize(), not in constructor
|
||||
// to ensure lvgl objects are created after the display is fully initialized.
|
||||
}
|
||||
|
||||
CustomLcdDisplay::~CustomLcdDisplay() {
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::InitPortraitLUT() {
|
||||
uint16_t W4 = width_ >> 2;
|
||||
for (uint16_t y = 0; y < height_; y++)
|
||||
{
|
||||
uint16_t byte_y = y >> 1;
|
||||
uint8_t local_y = y & 1;
|
||||
for (uint16_t x = 0; x < width_; x++)
|
||||
{
|
||||
uint16_t byte_x = x >> 2;
|
||||
uint8_t local_x = x & 3;
|
||||
|
||||
uint32_t index = byte_y * W4 + byte_x;
|
||||
uint8_t bit = 7 - ((local_x << 1) | local_y);
|
||||
|
||||
PixelIndexLUT[x][y] = index;
|
||||
PixelBitLUT [x][y] = (1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::InitLandscapeLUT() {
|
||||
uint16_t H4 = height_ >> 2;
|
||||
for (uint16_t y = 0; y < height_; y++)
|
||||
{
|
||||
uint16_t inv_y = height_ - 1 - y;
|
||||
uint16_t block_y = inv_y >> 2;
|
||||
uint8_t local_y = inv_y & 3;
|
||||
for (uint16_t x = 0; x < width_; x++)
|
||||
{
|
||||
uint16_t byte_x = x >> 1;
|
||||
uint8_t local_x = x & 1;
|
||||
|
||||
uint32_t index = byte_x * H4 + block_y;
|
||||
uint8_t bit = 7 - ((local_y << 1) | local_x);
|
||||
|
||||
PixelIndexLUT[x][y] = index;
|
||||
PixelBitLUT [x][y] = (1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::Set_ResetIOLevel(uint8_t level) {
|
||||
gpio_set_level((gpio_num_t) rst_, level ? 1 : 0);
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_SendCommand(uint8_t Reg) {
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_tx_param(io_handle, Reg, NULL, 0));
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_SendData(uint8_t Data) {
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_tx_param(io_handle, -1, &Data, 1));
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_Sendbuffera(uint8_t *Data, int len) {
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_tx_color(io_handle, -1, Data, len));
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_Reset(void) {
|
||||
Set_ResetIOLevel(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
Set_ResetIOLevel(0);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
Set_ResetIOLevel(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_ColorClear(uint8_t color) {
|
||||
memset(DispBuffer, color, DisplayLen);
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_Init() {
|
||||
RLCD_Reset();
|
||||
|
||||
RLCD_SendCommand(0xD6); // NVM Load Control
|
||||
RLCD_SendData(0x17);
|
||||
RLCD_SendData(0x02);
|
||||
|
||||
RLCD_SendCommand(0xD1); //Booster Enable
|
||||
RLCD_SendData(0x01);
|
||||
|
||||
RLCD_SendCommand(0xC0); //Gate Voltage Control
|
||||
RLCD_SendData(0x11);
|
||||
RLCD_SendData(0x04);
|
||||
|
||||
RLCD_SendCommand(0xC1); //VSHP Setting
|
||||
RLCD_SendData(0x69);
|
||||
RLCD_SendData(0x69);
|
||||
RLCD_SendData(0x69);
|
||||
RLCD_SendData(0x69);
|
||||
|
||||
RLCD_SendCommand(0xC2);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
|
||||
RLCD_SendCommand(0xC4);
|
||||
RLCD_SendData(0x4B);
|
||||
RLCD_SendData(0x4B);
|
||||
RLCD_SendData(0x4B);
|
||||
RLCD_SendData(0x4B);
|
||||
|
||||
RLCD_SendCommand(0xC5);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
|
||||
RLCD_SendCommand(0xD8);
|
||||
RLCD_SendData(0x80);
|
||||
RLCD_SendData(0xE9);
|
||||
|
||||
RLCD_SendCommand(0xB2);
|
||||
RLCD_SendData(0x02);
|
||||
|
||||
RLCD_SendCommand(0xB3);
|
||||
RLCD_SendData(0xE5);
|
||||
RLCD_SendData(0xF6);
|
||||
RLCD_SendData(0x05);
|
||||
RLCD_SendData(0x46);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x76);
|
||||
RLCD_SendData(0x45);
|
||||
|
||||
RLCD_SendCommand(0xB4);
|
||||
RLCD_SendData(0x05);
|
||||
RLCD_SendData(0x46);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x76);
|
||||
RLCD_SendData(0x45);
|
||||
|
||||
RLCD_SendCommand(0x62);
|
||||
RLCD_SendData(0x32);
|
||||
RLCD_SendData(0x03);
|
||||
RLCD_SendData(0x1F);
|
||||
|
||||
RLCD_SendCommand(0xB7);
|
||||
RLCD_SendData(0x13);
|
||||
|
||||
RLCD_SendCommand(0xB0);
|
||||
RLCD_SendData(0x64);
|
||||
|
||||
RLCD_SendCommand(0x11);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
RLCD_SendCommand(0xC9);
|
||||
RLCD_SendData(0x00);
|
||||
|
||||
RLCD_SendCommand(0x36);
|
||||
RLCD_SendData(0x48);
|
||||
|
||||
RLCD_SendCommand(0x3A);
|
||||
RLCD_SendData(0x11);
|
||||
|
||||
RLCD_SendCommand(0xB9);
|
||||
RLCD_SendData(0x20);
|
||||
|
||||
RLCD_SendCommand(0xB8);
|
||||
RLCD_SendData(0x29);
|
||||
|
||||
RLCD_SendCommand(0x21);
|
||||
|
||||
RLCD_SendCommand(0x2A);
|
||||
RLCD_SendData(0x12);
|
||||
RLCD_SendData(0x2A);
|
||||
|
||||
RLCD_SendCommand(0x2B);
|
||||
RLCD_SendData(0x00);
|
||||
RLCD_SendData(0xC7);
|
||||
|
||||
RLCD_SendCommand(0x35);
|
||||
RLCD_SendData(0x00);
|
||||
|
||||
RLCD_SendCommand(0xD0);
|
||||
RLCD_SendData(0xFF);
|
||||
|
||||
RLCD_SendCommand(0x38);
|
||||
RLCD_SendCommand(0x29);
|
||||
|
||||
RLCD_ColorClear(ColorWhite);
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_SetPixel(uint16_t x, uint16_t y, uint8_t color) {
|
||||
uint32_t idx = PixelIndexLUT[x][y];
|
||||
uint8_t mask = PixelBitLUT[x][y];
|
||||
|
||||
uint8_t *p = &DispBuffer[idx];
|
||||
|
||||
if (color)
|
||||
*p |= mask;
|
||||
else
|
||||
*p &= ~mask;
|
||||
}
|
||||
|
||||
void CustomLcdDisplay::RLCD_Display() {
|
||||
RLCD_SendCommand(0x2A); // Column Address Set
|
||||
RLCD_SendData(0x12);
|
||||
RLCD_SendData(0x2A);
|
||||
|
||||
RLCD_SendCommand(0x2B); // Page Address Set
|
||||
RLCD_SendData(0x00);
|
||||
RLCD_SendData(0xC7);
|
||||
|
||||
RLCD_SendCommand(0x2c); // Page Address Set
|
||||
|
||||
RLCD_Sendbuffera(DispBuffer,DisplayLen);
|
||||
}
|
||||
57
main/boards/waveshare/esp32-s3-rlcd-4.2/custom_lcd_display.h
Normal file
57
main/boards/waveshare/esp32-s3-rlcd-4.2/custom_lcd_display.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef __CUSTOM_LCD_DISPLAY_H__
|
||||
#define __CUSTOM_LCD_DISPLAY_H__
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include "lcd_display.h"
|
||||
|
||||
enum ColorSelection {
|
||||
ColorBlack = 0,
|
||||
ColorWhite = 0xff
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t mosi;
|
||||
uint8_t scl;
|
||||
uint8_t dc;
|
||||
uint8_t cs;
|
||||
uint8_t rst;
|
||||
} spi_display_config_t;
|
||||
|
||||
class CustomLcdDisplay : public LcdDisplay {
|
||||
private:
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
uint32_t i2c_data_pdMS_TICKS = 0;
|
||||
uint32_t i2c_done_pdMS_TICKS = 0;
|
||||
const char *TAG = "CustomDisplay";
|
||||
int mosi_;
|
||||
int scl_;
|
||||
int dc_;
|
||||
int cs_;
|
||||
int rst_;
|
||||
int width_;
|
||||
int height_;
|
||||
uint8_t *DispBuffer = NULL;
|
||||
int DisplayLen;
|
||||
uint16_t (*PixelIndexLUT)[300];
|
||||
uint8_t (*PixelBitLUT )[300];
|
||||
void InitPortraitLUT();
|
||||
void InitLandscapeLUT();
|
||||
void Set_ResetIOLevel(uint8_t level);
|
||||
void RLCD_SendCommand(uint8_t Reg);
|
||||
void RLCD_SendData(uint8_t Data);
|
||||
void RLCD_Sendbuffera(uint8_t *Data, int len);
|
||||
void RLCD_Reset(void);
|
||||
static void Lvgl_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p);
|
||||
|
||||
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,spi_display_config_t spiconfig,spi_host_device_t spi_host = SPI3_HOST);
|
||||
~CustomLcdDisplay();
|
||||
void RLCD_Init();
|
||||
void RLCD_ColorClear(uint8_t color);
|
||||
void RLCD_Display();
|
||||
void RLCD_SetPixel(uint16_t x, uint16_t y, uint8_t color);
|
||||
};
|
||||
|
||||
#endif
|
||||
170
main/boards/waveshare/esp32-s3-rlcd-4.2/waveshare-s3-rlcd-4.2.cc
Normal file
170
main/boards/waveshare/esp32-s3-rlcd-4.2/waveshare-s3-rlcd-4.2.cc
Normal file
@@ -0,0 +1,170 @@
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <esp_log.h>
|
||||
#include "custom_lcd_display.h"
|
||||
#include "wifi_board.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "wifi_station.h"
|
||||
#include "mcp_server.h"
|
||||
#include "lvgl.h"
|
||||
#include "custom_lcd_display.h"
|
||||
|
||||
#define TAG "waveshare_rlcd_4_2"
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay *display_;
|
||||
adc_oneshot_unit_handle_t adc1_handle;
|
||||
adc_cali_handle_t cali_handle;
|
||||
bool vbat_status = 0;
|
||||
|
||||
void InitializeI2c() {
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {};
|
||||
i2c_bus_cfg.i2c_port = ESP32_I2C_HOST;
|
||||
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) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
boot_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeTools() {
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.disp.network", "重新配网", PropertyList(),
|
||||
[this](const PropertyList&) -> ReturnValue {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
spi_display_config_t spi_config = {};
|
||||
spi_config.mosi = RLCD_MOSI_PIN;
|
||||
spi_config.scl = RLCD_SCK_PIN;
|
||||
spi_config.dc = RLCD_DC_PIN;
|
||||
spi_config.cs = RLCD_CS_PIN;
|
||||
spi_config.rst = RLCD_RST_PIN;
|
||||
display_ = new CustomLcdDisplay(NULL, NULL, RLCD_WIDTH,RLCD_HEIGHT,DISPLAY_OFFSET_X,DISPLAY_OFFSET_Y,DISPLAY_MIRROR_X,DISPLAY_MIRROR_Y,DISPLAY_SWAP_XY,spi_config);
|
||||
}
|
||||
|
||||
uint16_t BatterygetVoltage(void) {
|
||||
static bool initialized = false;
|
||||
static adc_oneshot_unit_handle_t adc_handle;
|
||||
static adc_cali_handle_t cali_handle = NULL;
|
||||
if (!initialized) {
|
||||
adc_oneshot_unit_init_cfg_t init_config = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
};
|
||||
adc_oneshot_new_unit(&init_config, &adc_handle);
|
||||
|
||||
adc_oneshot_chan_cfg_t ch_config = {
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
adc_oneshot_config_channel(adc_handle, ADC_CHANNEL_3, &ch_config);
|
||||
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
if (adc_cali_create_scheme_curve_fitting(&cali_config, &cali_handle) == ESP_OK) {
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
int raw_value = 0;
|
||||
int raw_voltage = 0;
|
||||
int voltage = 0; // mV
|
||||
adc_oneshot_read(adc_handle, ADC_CHANNEL_3, &raw_value);
|
||||
adc_cali_raw_to_voltage(cali_handle, raw_value, &raw_voltage);
|
||||
voltage = raw_voltage * 3;
|
||||
// ESP_LOGI(TAG, "voltage: %dmV", voltage);
|
||||
return (uint16_t)voltage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t BatterygetPercent() {
|
||||
int voltage = 0;
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
voltage += BatterygetVoltage();
|
||||
}
|
||||
|
||||
voltage /= 10;
|
||||
int percent = (-1 * voltage * voltage + 9016 * voltage - 19189000) / 10000;
|
||||
percent = (percent > 100) ? 100 : (percent < 0) ? 0 : percent;
|
||||
// ESP_LOGI(TAG, "voltage: %dmV, percentage: %d%%", voltage, percent);
|
||||
return (uint8_t)percent;
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
InitializeLcdDisplay();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
charging = false;
|
||||
discharging = !charging;
|
||||
level = (int)BatterygetPercent();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
48
main/boards/waveshare/esp32-s3-touch-amoled-1.32/README.md
Normal file
48
main/boards/waveshare/esp32-s3-touch-amoled-1.32/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-Touch-AMOLED-1.32](https://www.waveshare.net/shop/ESP32-S3-Touch-AMOLED-1.32.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-Touch-AMOLED-1.32
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
47
main/boards/waveshare/esp32-s3-touch-amoled-1.32/config.h
Normal file
47
main/boards/waveshare/esp32-s3-touch-amoled-1.32/config.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_38
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_41
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_39
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_40
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_42
|
||||
|
||||
#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 PWR_BUTTON_GPIO GPIO_NUM_17
|
||||
#define PWR_EN_GPIO GPIO_NUM_18
|
||||
|
||||
|
||||
/*disp-qspi-lcd*/
|
||||
#define LCD_CS GPIO_NUM_10
|
||||
#define LCD_PCLK GPIO_NUM_11
|
||||
#define LCD_D0 GPIO_NUM_12
|
||||
#define LCD_D1 GPIO_NUM_13
|
||||
#define LCD_D2 GPIO_NUM_14
|
||||
#define LCD_D3 GPIO_NUM_15
|
||||
#define LCD_RST GPIO_NUM_8
|
||||
#define LCD_LIGHT (-1)
|
||||
|
||||
#define EXAMPLE_LCD_H_RES 466
|
||||
#define EXAMPLE_LCD_V_RES 466
|
||||
|
||||
#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_
|
||||
13
main/boards/waveshare/esp32-s3-touch-amoled-1.32/config.json
Normal file
13
main/boards/waveshare/esp32-s3-touch-amoled-1.32/config.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-amoled-1.32",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "config.h"
|
||||
#include "wifi_board.h"
|
||||
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "lvgl.h"
|
||||
#include "mcp_server.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "waveshare_s3_amoled_1_32"
|
||||
|
||||
static const sh8601_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
{0xFE, (uint8_t[]) {0x00}, 1, 0},
|
||||
{0xC4, (uint8_t[]) {0x80}, 1, 0},
|
||||
{0x3A, (uint8_t[]) {0x55}, 1, 0}, // 0x55 for RGB565, 0x77 for RGB888
|
||||
{0x35, (uint8_t[]) {0x00}, 1, 0},
|
||||
{0x53, (uint8_t[]) {0x20}, 1, 0},
|
||||
{0x51, (uint8_t[]) {0xFF}, 1, 0}, // Brightness
|
||||
{0x63, (uint8_t[]) {0xFF}, 1, 0},
|
||||
{0x2A, (uint8_t[]) {0x00, 0x06, 0x01, 0xD7}, 4, 0},
|
||||
{0x2B, (uint8_t[]) {0x00, 0x00, 0x01, 0xD1}, 4, 0},
|
||||
{0x11, (uint8_t[]) {0x00}, 0, 100},
|
||||
{0x29, (uint8_t[]) {0x00}, 0, 0},
|
||||
};
|
||||
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
private:
|
||||
esp_lcd_panel_io_handle_t io_handle_;
|
||||
|
||||
public:
|
||||
static void my_draw_event_cb(lv_event_t *e) {
|
||||
lv_area_t *area = (lv_area_t *) lv_event_get_param(e);
|
||||
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
|
||||
// Round area for better performance
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
void SetMIRROR_XY(uint8_t mirror) {
|
||||
uint32_t lcd_cmd = 0x36;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= 0x02 << 24;
|
||||
uint8_t param = mirror;
|
||||
esp_lcd_panel_io_tx_param(io_handle_, lcd_cmd, ¶m, 1);
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle, int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy) :
|
||||
SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy),
|
||||
io_handle_(io_handle) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
SetMIRROR_XY(0xC0); // Rotate 180 degrees - this is safe as it only operates on hardware
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_display_add_event_cb(display_, my_draw_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
lv_obj_invalidate(lv_screen_active());
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
Button pwr_button_;
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
CustomLcdDisplay *display_;
|
||||
lv_indev_t *touch_indev = NULL;
|
||||
i2c_master_dev_handle_t disp_touch_dev_handle = NULL;
|
||||
|
||||
void InitializeI2c() {
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {};
|
||||
i2c_bus_cfg.i2c_port = I2C_NUM_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 SetDispbacklight(uint8_t backlight) {
|
||||
uint32_t lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= 0x02 << 24;
|
||||
uint8_t param = backlight;
|
||||
esp_lcd_panel_io_tx_param(io_handle, lcd_cmd, ¶m, 1);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto &app = Application::GetInstance();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
pwr_button_.OnLongPress([this]() {
|
||||
GetDisplay()->SetChatMessage("system", "OFF");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
gpio_set_level(PWR_EN_GPIO, 0);
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.data0_io_num = LCD_D0;
|
||||
buscfg.data1_io_num = LCD_D1;
|
||||
buscfg.sclk_io_num = LCD_PCLK;
|
||||
buscfg.data2_io_num = LCD_D2;
|
||||
buscfg.data3_io_num = LCD_D3;
|
||||
buscfg.max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = LCD_CS;
|
||||
io_config.dc_gpio_num = -1;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 8;
|
||||
io_config.on_color_trans_done = NULL;
|
||||
io_config.user_ctx = NULL;
|
||||
io_config.lcd_cmd_bits = 32;
|
||||
io_config.lcd_param_bits = 8;
|
||||
io_config.flags.quad_mode = true;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &io_handle));
|
||||
|
||||
sh8601_vendor_config_t vendor_config = {};
|
||||
vendor_config.init_cmds = lcd_init_cmds;
|
||||
vendor_config.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]);
|
||||
vendor_config.flags.use_qspi_interface = 1;
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = LCD_RST;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = &vendor_config;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(io_handle, &panel_config, &panel_handle));
|
||||
esp_lcd_panel_set_gap(panel_handle, 0x06, 0x00);
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
|
||||
display_ = new CustomLcdDisplay(io_handle, panel_handle, EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.disp.setbacklight", "设置屏幕亮度", PropertyList({Property("level", kPropertyTypeInteger, 0, 255)}), [this](const PropertyList &properties) -> ReturnValue {
|
||||
int level = properties["level"].value<int>();
|
||||
ESP_LOGI("setbacklight", "%d", level);
|
||||
SetDispbacklight(level);
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.disp.network", "重新配网", PropertyList(), [this](const PropertyList &) -> ReturnValue {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void CheckPowerKeyState() {
|
||||
gpio_config_t gpio_conf = {};
|
||||
gpio_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_conf.mode = GPIO_MODE_OUTPUT;
|
||||
gpio_conf.pin_bit_mask = (0x1ULL << PWR_EN_GPIO);
|
||||
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_set_level(PWR_EN_GPIO, 1);
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
} while (!gpio_get_level(PWR_BUTTON_GPIO));
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() : boot_button_(BOOT_BUTTON_GPIO), pwr_button_(PWR_BUTTON_GPIO) {
|
||||
CheckPowerKeyState();
|
||||
InitializeI2c();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
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);
|
||||
15
main/boards/waveshare/esp32-s3-touch-amoled-1.75/README.md
Normal file
15
main/boards/waveshare/esp32-s3-touch-amoled-1.75/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Waveshare ESP32-S3-Touch-AMOLED-1.75
|
||||
|
||||
|
||||
[ESP32-S3-Touch-AMOLED-1.75](https://www.waveshare.com/esp32-s3-touch-amoled-1.75.htm) ESP32-S3-Touch-AMOLED-1.75 is a high performance, highly integrated microcontroller development board designed by Waveshare.\
|
||||
In the smaller form, the 1.75-inch capacitive HD AMOLED screen, highly integrated power management chip, six-axis sensor (three-axis accelerometer and three-axis gyroscope), RTC, low-power audio codec chip and echo cancellation circuit are mounted on the board, which is convenient for development and embedding into the product.
|
||||
|
||||
|
||||
## images
|
||||
|
||||
| [ESP32-S3-Touch-AMOLED-1.75](https://www.waveshare.com/esp32-s3-touch-amoled-1.75.htm) |
|
||||
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <img style="width: 150px; height: auto; display: block; margin: 0 auto;" src= "https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/e/s/esp32-s3-touch-amoled-1.75-1.jpg"> |
|
||||
| <img style="width: 150px; height: auto; display: block; margin: 0 auto;" src= "https://www.waveshare.com/media/catalog/product/cache/1/image/560x560/9df78eab33525d08d6e5fb8d27136e95/e/s/esp32-s3-touch-amoled-1.75-b-3.jpg"> |
|
||||
| <img style="width: 150px; height: auto; display: block; margin: 0 auto;" src= "https://www.waveshare.com/media/catalog/product/cache/1/image/560x560/9df78eab33525d08d6e5fb8d27136e95/e/s/esp32-s3-touch-amoled-1.75-b-1.jpg"> |
|
||||
|
||||
57
main/boards/waveshare/esp32-s3-touch-amoled-1.75/config.h
Normal file
57
main/boards/waveshare/esp32-s3-touch-amoled-1.75/config.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_42
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_45
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_9
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_8
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST GPIO_NUM_39
|
||||
#define PIN_NUM_TOUCH_RST GPIO_NUM_40
|
||||
#define PIN_NUM_TOUCH_INT GPIO_NUM_11
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75C
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_16
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_45
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_9
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_8
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST GPIO_NUM_1
|
||||
#define PIN_NUM_TOUCH_RST GPIO_NUM_2
|
||||
#define PIN_NUM_TOUCH_INT GPIO_NUM_11
|
||||
#endif
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_46
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_15
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_14
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define EXAMPLE_PIN_NUM_LCD_CS GPIO_NUM_12
|
||||
#define EXAMPLE_PIN_NUM_LCD_PCLK GPIO_NUM_38
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA0 GPIO_NUM_4
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA1 GPIO_NUM_5
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA2 GPIO_NUM_6
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA3 GPIO_NUM_7
|
||||
|
||||
#define DISPLAY_WIDTH 466
|
||||
#define DISPLAY_HEIGHT 466
|
||||
#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
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
22
main/boards/waveshare/esp32-s3-touch-amoled-1.75/config.json
Normal file
22
main/boards/waveshare/esp32-s3-touch-amoled-1.75/config.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-amoled-1.75",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-touch-amoled-1.75c",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75C=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_co5300.h"
|
||||
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "axp2101.h"
|
||||
#include "i2c_device.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lcd_touch_cst9217.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32s3TouchAMOLED1inch75"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1(MIC)
|
||||
WriteReg(0x90, 0x01);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
};
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x03ULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
static const co5300_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
// set display to qspi mode
|
||||
{0xFE, (uint8_t[]){0x20}, 1, 0},
|
||||
{0x19, (uint8_t[]){0x10}, 1, 0},
|
||||
{0x1C, (uint8_t[]){0xA0}, 1, 0},
|
||||
|
||||
{0xFE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xC4, (uint8_t[]){0x80}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x55}, 1, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x53, (uint8_t[]){0x20}, 1, 0},
|
||||
{0x51, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0x63, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0x2A, (uint8_t[]){0x00, 0x06, 0x01, 0xD7}, 4, 0},
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0xD1}, 4, 600},
|
||||
{0x11, NULL, 0, 600},
|
||||
{0x29, NULL, 0, 0},
|
||||
};
|
||||
|
||||
// 在waveshare_amoled_1_75类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
static void rounder_event_cb(lv_event_t* e) {
|
||||
lv_area_t* area = (lv_area_t* )lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
|
||||
// round the start of coordinate down to the nearest 2M number
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
// round the end of coordinate up to the nearest 2N+1 number
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES* 0.1, 0);
|
||||
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES* 0.1, 0);
|
||||
lv_display_add_event_cb(display_, rounder_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_lcd_panel_io_handle_t panel_io) : Backlight(), panel_io_(panel_io) {}
|
||||
|
||||
protected:
|
||||
esp_lcd_panel_io_handle_t panel_io_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
DisplayLockGuard lock(display);
|
||||
uint8_t data[1] = {((uint8_t)((255* brightness) / 100))};
|
||||
int lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
esp_lcd_panel_io_tx_param(panel_io_, lcd_cmd, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32s3TouchAMOLED1inch75 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay* display_;
|
||||
CustomBacklight* backlight_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20); });
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness(); });
|
||||
power_save_timer_->OnShutdownRequest([this](){
|
||||
pmic_->PowerOff(); });
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeTca9554(void) {
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if (ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_4, IO_EXPANDER_INPUT);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = EXAMPLE_PIN_NUM_LCD_PCLK;
|
||||
buscfg.data0_io_num = EXAMPLE_PIN_NUM_LCD_DATA0;
|
||||
buscfg.data1_io_num = EXAMPLE_PIN_NUM_LCD_DATA1;
|
||||
buscfg.data2_io_num = EXAMPLE_PIN_NUM_LCD_DATA2;
|
||||
buscfg.data3_io_num = EXAMPLE_PIN_NUM_LCD_DATA3;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH* DISPLAY_HEIGHT* sizeof(uint16_t);
|
||||
buscfg.flags = SPICOMMON_BUSFLAG_QUAD;
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
boot_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = CO5300_PANEL_IO_QSPI_CONFIG(
|
||||
EXAMPLE_PIN_NUM_LCD_CS,
|
||||
nullptr,
|
||||
nullptr);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
const co5300_vendor_config_t vendor_config = {
|
||||
.init_cmds = &vendor_specific_init[0],
|
||||
.init_cmds_size = sizeof(vendor_specific_init) / sizeof(co5300_lcd_init_cmd_t),
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
}};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void* )&vendor_config;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_co5300(panel_io, &panel_config, &panel));
|
||||
esp_lcd_panel_set_gap(panel, 0x06, 0);
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, false);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
display_ = new CustomLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(panel_io);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH - 1,
|
||||
.y_max = DISPLAY_HEIGHT - 1,
|
||||
.rst_gpio_num = PIN_NUM_TOUCH_RST,
|
||||
.int_gpio_num = PIN_NUM_TOUCH_INT,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 1,
|
||||
.mirror_y = 1,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST9217_CONFIG();
|
||||
tp_io_config.scl_speed_hz = 400* 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_cst9217(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32s3TouchAMOLED1inch75() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75
|
||||
InitializeTca9554();
|
||||
#endif
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeDisplay();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
return backlight_;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool &charging, bool &discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging)
|
||||
{
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32s3TouchAMOLED1inch75);
|
||||
41
main/boards/waveshare/esp32-s3-touch-amoled-1.8/config.h
Normal file
41
main/boards/waveshare/esp32-s3-touch-amoled-1.8/config.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_16
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_45
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_9
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_8
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_46
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_15
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_14
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define EXAMPLE_PIN_NUM_LCD_CS GPIO_NUM_12
|
||||
#define EXAMPLE_PIN_NUM_LCD_PCLK GPIO_NUM_11
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA0 GPIO_NUM_4
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA1 GPIO_NUM_5
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA2 GPIO_NUM_6
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA3 GPIO_NUM_7
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST GPIO_NUM_NC
|
||||
#define DISPLAY_WIDTH 368
|
||||
#define DISPLAY_HEIGHT 448
|
||||
#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
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
12
main/boards/waveshare/esp32-s3-touch-amoled-1.8/config.json
Normal file
12
main/boards/waveshare/esp32-s3-touch-amoled-1.8/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-amoled-1.8",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "axp2101.h"
|
||||
#include "i2c_device.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lcd_touch_ft5x06.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32s3TouchAMOLED1inch8"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1(MIC)
|
||||
WriteReg(0x90, 0x01);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
};
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x03ULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
static const sh8601_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
{0x11, (uint8_t[]){0x00}, 0, 120},
|
||||
{0x44, (uint8_t[]){0x01, 0xD1}, 2, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x53, (uint8_t[]){0x20}, 1, 10},
|
||||
{0x2A, (uint8_t[]){0x00, 0x00, 0x01, 0x6F}, 4, 0},
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0xBF}, 4, 0},
|
||||
{0x51, (uint8_t[]){0x00}, 1, 10},
|
||||
{0x29, (uint8_t[]){0x00}, 0, 10}
|
||||
};
|
||||
|
||||
// 在waveshare_amoled_1_8类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES * 0.1, 0);
|
||||
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES * 0.1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_lcd_panel_io_handle_t panel_io) : Backlight(), panel_io_(panel_io) {}
|
||||
|
||||
protected:
|
||||
esp_lcd_panel_io_handle_t panel_io_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
DisplayLockGuard lock(display);
|
||||
uint8_t data[1] = {((uint8_t)((255 * brightness) / 100))};
|
||||
int lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
esp_lcd_panel_io_tx_param(panel_io_, lcd_cmd, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32s3TouchAMOLED1inch8 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t codec_i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay* display_;
|
||||
CustomBacklight* backlight_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness();
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
pmic_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &codec_i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeTca9554(void) {
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(codec_i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 |IO_EXPANDER_PIN_NUM_2, IO_EXPANDER_OUTPUT);
|
||||
ret |= esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_4, IO_EXPANDER_INPUT);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1|IO_EXPANDER_PIN_NUM_2, 1);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1|IO_EXPANDER_PIN_NUM_2, 0);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1|IO_EXPANDER_PIN_NUM_2, 1);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(codec_i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = GPIO_NUM_11;
|
||||
buscfg.data0_io_num = GPIO_NUM_4;
|
||||
buscfg.data1_io_num = GPIO_NUM_5;
|
||||
buscfg.data2_io_num = GPIO_NUM_6;
|
||||
buscfg.data3_io_num = GPIO_NUM_7;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
buscfg.flags = SPICOMMON_BUSFLAG_QUAD;
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeSH8601Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = SH8601_PANEL_IO_QSPI_CONFIG(
|
||||
EXAMPLE_PIN_NUM_LCD_CS,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
const sh8601_vendor_config_t vendor_config = {
|
||||
.init_cmds = &vendor_specific_init[0],
|
||||
.init_cmds_size = sizeof(vendor_specific_init) / sizeof(sh8601_lcd_init_cmd_t),
|
||||
.flags ={
|
||||
.use_qspi_interface = 1,
|
||||
}
|
||||
};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.flags.reset_active_high = 1,
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void *)&vendor_config;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(panel_io, &panel_config, &panel));
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, false);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
display_ = new CustomLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(panel_io);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeTouch()
|
||||
{
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = GPIO_NUM_NC,
|
||||
.int_gpio_num = GPIO_NUM_21,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(codec_i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32s3TouchAMOLED1inch8() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
InitializeTca9554();
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeSH8601Display();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(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_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
return backlight_;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32s3TouchAMOLED1inch8);
|
||||
11
main/boards/waveshare/esp32-s3-touch-amoled-2.06/README.md
Normal file
11
main/boards/waveshare/esp32-s3-touch-amoled-2.06/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Waveshare ESP32-S3-Touch-AMOLED-2.06
|
||||
|
||||
|
||||
[ESP32-S3-Touch-AMOLED-2.06](https://www.waveshare.com/esp32-s3-touch-amoled-2.06.htm) is a high-performance, wearable watch-style development board designed by Waveshare. Based on the ESP32-S3R8 microcontroller, it integrates a 2.06inch AMOLED capacitive touch display, 6-axis IMU, RTC chip, audio codec chip, power management IC, and so on. Comes with a custom-designed case with a smartwatch-like appearance, making it ideal for prototyping and functional verification of wearable applications.
|
||||
|
||||
## images
|
||||
|
||||
| [ESP32-S3-Touch-AMOLED-2.06](https://www.waveshare.com/esp32-s3-touch-amoled-2.06.htm) |
|
||||
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <img style="width: 150px; height: auto; display: block; margin: 0 auto;" src= "https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/e/s/esp32-s3-touch-amoled-2.06-1.jpg"> |
|
||||
|
||||
43
main/boards/waveshare/esp32-s3-touch-amoled-2.06/config.h
Normal file
43
main/boards/waveshare/esp32-s3-touch-amoled-2.06/config.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_16
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_45
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_41
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_42
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_40
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_46
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_15
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_14
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define EXAMPLE_PIN_NUM_LCD_CS GPIO_NUM_12
|
||||
#define EXAMPLE_PIN_NUM_LCD_PCLK GPIO_NUM_11
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA0 GPIO_NUM_4
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA1 GPIO_NUM_5
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA2 GPIO_NUM_6
|
||||
#define EXAMPLE_PIN_NUM_LCD_DATA3 GPIO_NUM_7
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST GPIO_NUM_8
|
||||
#define DISPLAY_WIDTH 410
|
||||
#define DISPLAY_HEIGHT 502
|
||||
#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
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
13
main/boards/waveshare/esp32-s3-touch-amoled-2.06/config.json
Normal file
13
main/boards/waveshare/esp32-s3-touch-amoled-2.06/config.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-amoled-2.06",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "axp2101.h"
|
||||
#include "i2c_device.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lcd_touch_ft5x06.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32s3TouchAMOLED2inch06"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
WriteReg(0x93, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1(MIC)
|
||||
WriteReg(0x90, 0x03);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x0A); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
};
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x03ULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
static const sh8601_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
// set display to qspi mode
|
||||
{0x11, (uint8_t []){0x00}, 0, 120},
|
||||
{0xC4, (uint8_t []){0x80}, 1, 0},
|
||||
{0x44, (uint8_t []){0x01, 0xD1}, 2, 0},
|
||||
{0x35, (uint8_t []){0x00}, 1, 0},
|
||||
{0x53, (uint8_t []){0x20}, 1, 10},
|
||||
{0x63, (uint8_t []){0xFF}, 1, 10},
|
||||
{0x51, (uint8_t []){0x00}, 1, 10},
|
||||
{0x2A, (uint8_t []){0x00,0x16,0x01,0xAF}, 4, 0},
|
||||
{0x2B, (uint8_t []){0x00,0x00,0x01,0xF5}, 4, 0},
|
||||
{0x29, (uint8_t []){0x00}, 0, 10},
|
||||
{0x51, (uint8_t []){0xFF}, 1, 0},
|
||||
};
|
||||
|
||||
// 在waveshare_amoled_2_06类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
static void rounder_event_cb(lv_event_t* e) {
|
||||
lv_area_t* area = (lv_area_t* )lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
|
||||
// round the start of coordinate down to the nearest 2M number
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
// round the end of coordinate up to the nearest 2N+1 number
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES* 0.1, 0);
|
||||
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES* 0.1, 0);
|
||||
lv_display_add_event_cb(display_, rounder_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_lcd_panel_io_handle_t panel_io) : Backlight(), panel_io_(panel_io) {}
|
||||
|
||||
protected:
|
||||
esp_lcd_panel_io_handle_t panel_io_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
DisplayLockGuard lock(display);
|
||||
uint8_t data[1] = {((uint8_t)((255* brightness) / 100))};
|
||||
int lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
esp_lcd_panel_io_tx_param(panel_io_, lcd_cmd, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32s3TouchAMOLED2inch06 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay* display_;
|
||||
CustomBacklight* backlight_;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20); });
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness(); });
|
||||
power_save_timer_->OnShutdownRequest([this](){
|
||||
pmic_->PowerOff(); });
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = EXAMPLE_PIN_NUM_LCD_PCLK;
|
||||
buscfg.data0_io_num = EXAMPLE_PIN_NUM_LCD_DATA0;
|
||||
buscfg.data1_io_num = EXAMPLE_PIN_NUM_LCD_DATA1;
|
||||
buscfg.data2_io_num = EXAMPLE_PIN_NUM_LCD_DATA2;
|
||||
buscfg.data3_io_num = EXAMPLE_PIN_NUM_LCD_DATA3;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH* DISPLAY_HEIGHT* sizeof(uint16_t);
|
||||
buscfg.flags = SPICOMMON_BUSFLAG_QUAD;
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
boot_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeSH8601Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = SH8601_PANEL_IO_QSPI_CONFIG(
|
||||
EXAMPLE_PIN_NUM_LCD_CS,
|
||||
nullptr,
|
||||
nullptr);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
const sh8601_vendor_config_t vendor_config = {
|
||||
.init_cmds = &vendor_specific_init[0],
|
||||
.init_cmds_size = sizeof(vendor_specific_init) / sizeof(sh8601_lcd_init_cmd_t),
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
}};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void* )&vendor_config;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(panel_io, &panel_config, &panel));
|
||||
esp_lcd_panel_set_gap(panel, 0x16, 0);
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, false);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
display_ = new CustomLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(panel_io);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH - 1,
|
||||
.y_max = DISPLAY_HEIGHT - 1,
|
||||
.rst_gpio_num = GPIO_NUM_9,
|
||||
.int_gpio_num = GPIO_NUM_38,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400* 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32s3TouchAMOLED2inch06() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeSH8601Display();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
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,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
return backlight_;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool &charging, bool &discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging)
|
||||
{
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32s3TouchAMOLED2inch06);
|
||||
4
main/boards/waveshare/esp32-s3-touch-lcd-1.46/README.md
Normal file
4
main/boards/waveshare/esp32-s3-touch-lcd-1.46/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
新增 微雪 开发板: ESP32-S3-Touch-LCD-1.46、ESP32-S3-Touch-LCD-1.46B
|
||||
产品链接:
|
||||
https://www.waveshare.net/shop/ESP32-S3-Touch-LCD-1.46.htm
|
||||
https://www.waveshare.net/shop/ESP32-S3-Touch-LCD-1.46B.htm
|
||||
70
main/boards/waveshare/esp32-s3-touch-lcd-1.46/config.h
Normal file
70
main/boards/waveshare/esp32-s3-touch-lcd-1.46/config.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define PWR_BUTTON_GPIO GPIO_NUM_6
|
||||
#define PWR_Control_PIN GPIO_NUM_7
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_2
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_15
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_39
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_47
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_48
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_38
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_10
|
||||
#define I2C_SDA_IO GPIO_NUM_11
|
||||
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
|
||||
#define DISPLAY_WIDTH 412
|
||||
#define DISPLAY_HEIGHT 412
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define QSPI_LCD_H_RES (412)
|
||||
#define QSPI_LCD_V_RES (412)
|
||||
#define QSPI_LCD_BIT_PER_PIXEL (16)
|
||||
|
||||
#define QSPI_LCD_HOST SPI2_HOST
|
||||
#define QSPI_PIN_NUM_LCD_PCLK GPIO_NUM_40
|
||||
#define QSPI_PIN_NUM_LCD_CS GPIO_NUM_21
|
||||
#define QSPI_PIN_NUM_LCD_DATA0 GPIO_NUM_46
|
||||
#define QSPI_PIN_NUM_LCD_DATA1 GPIO_NUM_45
|
||||
#define QSPI_PIN_NUM_LCD_DATA2 GPIO_NUM_42
|
||||
#define QSPI_PIN_NUM_LCD_DATA3 GPIO_NUM_41
|
||||
#define QSPI_PIN_NUM_LCD_RST GPIO_NUM_NC
|
||||
#define QSPI_PIN_NUM_LCD_BL GPIO_NUM_5
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define TP_PORT (I2C_NUM_1)
|
||||
#define TP_PIN_NUM_SDA (I2C_SDA_IO)
|
||||
#define TP_PIN_NUM_SCL (I2C_SCL_IO)
|
||||
#define TP_PIN_NUM_RST (GPIO_NUM_NC)
|
||||
#define TP_PIN_NUM_INT (GPIO_NUM_4)
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN QSPI_PIN_NUM_LCD_BL
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#define TAIJIPI_SPD2010_PANEL_BUS_QSPI_CONFIG(sclk, d0, d1, d2, d3, max_trans_sz) \
|
||||
{ \
|
||||
.data0_io_num = d0, \
|
||||
.data1_io_num = d1, \
|
||||
.sclk_io_num = sclk, \
|
||||
.data2_io_num = d2, \
|
||||
.data3_io_num = d3, \
|
||||
.max_transfer_sz = max_trans_sz, \
|
||||
}
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
10
main/boards/waveshare/esp32-s3-touch-lcd-1.46/config.json
Normal file
10
main/boards/waveshare/esp32-s3-touch-lcd-1.46/config.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-lcd-1.46",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/no_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_spd2010.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
#include "lcd_display.h"
|
||||
#include <iot_button.h>
|
||||
|
||||
#define TAG "waveshare_lcd_1_46"
|
||||
|
||||
// 在waveshare_lcd_1_46类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
static void rounder_event_cb(lv_event_t * e) {
|
||||
lv_area_t * area = (lv_area_t *)lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
|
||||
area->x1 = (x1 >> 2) << 2; // round the start of coordinate down to the nearest 4M number
|
||||
area->x2 = ((x2 >> 2) << 2) + 3; // round the end of coordinate up to the nearest 4N+3 number
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: SpiLcdDisplay(io_handle, panel_handle,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
|
||||
// Note: UI customization should be done in SetupUI(), not in constructor
|
||||
// to ensure lvgl objects are created before accessing them
|
||||
}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_display_add_event_cb(display_, rounder_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
LcdDisplay* display_;
|
||||
button_handle_t boot_btn, pwr_btn;
|
||||
button_driver_t* boot_btn_driver_ = nullptr;
|
||||
button_driver_t* pwr_btn_driver_ = nullptr;
|
||||
static CustomBoard* instance_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeTca9554(void) {
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
|
||||
// uint32_t input_level_mask = 0;
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_INPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输入
|
||||
// ret = esp_io_expander_get_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, &input_level_mask); // 获取引脚 EXIO0 和 EXIO1 的电平状态,存放在 input_level_mask 中
|
||||
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO2 和 EXIO3 模式为输出
|
||||
// ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, 1); // 将引脚电平设置为 1
|
||||
// ret = esp_io_expander_print_state(io_expander); // 打印引脚状态
|
||||
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输出
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
|
||||
const spi_bus_config_t bus_config = TAIJIPI_SPD2010_PANEL_BUS_QSPI_CONFIG(QSPI_PIN_NUM_LCD_PCLK,
|
||||
QSPI_PIN_NUM_LCD_DATA0,
|
||||
QSPI_PIN_NUM_LCD_DATA1,
|
||||
QSPI_PIN_NUM_LCD_DATA2,
|
||||
QSPI_PIN_NUM_LCD_DATA3,
|
||||
QSPI_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(QSPI_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeSpd2010Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
|
||||
const esp_lcd_panel_io_spi_config_t io_config = SPD2010_PANEL_IO_QSPI_CONFIG(QSPI_PIN_NUM_LCD_CS, NULL, NULL);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)QSPI_LCD_HOST, &io_config, &panel_io));
|
||||
|
||||
ESP_LOGI(TAG, "Install SPD2010 panel driver");
|
||||
|
||||
spd2010_vendor_config_t vendor_config = {
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = QSPI_PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
|
||||
.bits_per_pixel = QSPI_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18)
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_spd2010(panel_io, &panel_config, &panel));
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
display_ = new CustomLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeButtonsCustom() {
|
||||
gpio_reset_pin(BOOT_BUTTON_GPIO);
|
||||
gpio_set_direction(BOOT_BUTTON_GPIO, GPIO_MODE_INPUT);
|
||||
gpio_reset_pin(PWR_BUTTON_GPIO);
|
||||
gpio_set_direction(PWR_BUTTON_GPIO, GPIO_MODE_INPUT);
|
||||
gpio_reset_pin(PWR_Control_PIN);
|
||||
gpio_set_direction(PWR_Control_PIN, GPIO_MODE_OUTPUT);
|
||||
// gpio_set_level(PWR_Control_PIN, false);
|
||||
gpio_set_level(PWR_Control_PIN, true);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
instance_ = this;
|
||||
InitializeButtonsCustom();
|
||||
|
||||
// Boot Button
|
||||
button_config_t boot_btn_config = {
|
||||
.long_press_time = 2000,
|
||||
.short_press_time = 0
|
||||
};
|
||||
boot_btn_driver_ = (button_driver_t*)calloc(1, sizeof(button_driver_t));
|
||||
boot_btn_driver_->enable_power_save = false;
|
||||
boot_btn_driver_->get_key_level = [](button_driver_t *button_driver) -> uint8_t {
|
||||
return !gpio_get_level(BOOT_BUTTON_GPIO);
|
||||
};
|
||||
ESP_ERROR_CHECK(iot_button_create(&boot_btn_config, boot_btn_driver_, &boot_btn));
|
||||
iot_button_register_cb(boot_btn, BUTTON_SINGLE_CLICK, nullptr, [](void* button_handle, void* usr_data) {
|
||||
auto self = static_cast<CustomBoard*>(usr_data);
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
self->EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
}, this);
|
||||
iot_button_register_cb(boot_btn, BUTTON_LONG_PRESS_START, nullptr, [](void* button_handle, void* usr_data) {
|
||||
// 长按无处理
|
||||
}, this);
|
||||
|
||||
// Power Button
|
||||
button_config_t pwr_btn_config = {
|
||||
.long_press_time = 5000,
|
||||
.short_press_time = 0
|
||||
};
|
||||
pwr_btn_driver_ = (button_driver_t*)calloc(1, sizeof(button_driver_t));
|
||||
pwr_btn_driver_->enable_power_save = false;
|
||||
pwr_btn_driver_->get_key_level = [](button_driver_t *button_driver) -> uint8_t {
|
||||
return !gpio_get_level(PWR_BUTTON_GPIO);
|
||||
};
|
||||
ESP_ERROR_CHECK(iot_button_create(&pwr_btn_config, pwr_btn_driver_, &pwr_btn));
|
||||
iot_button_register_cb(pwr_btn, BUTTON_SINGLE_CLICK, nullptr, [](void* button_handle, void* usr_data) {
|
||||
// 短按无处理
|
||||
}, this);
|
||||
iot_button_register_cb(pwr_btn, BUTTON_LONG_PRESS_START, nullptr, [](void* button_handle, void* usr_data) {
|
||||
auto self = static_cast<CustomBoard*>(usr_data);
|
||||
if(self->GetBacklight()->brightness() > 0) {
|
||||
self->GetBacklight()->SetBrightness(0);
|
||||
gpio_set_level(PWR_Control_PIN, false);
|
||||
}
|
||||
else {
|
||||
self->GetBacklight()->RestoreBrightness();
|
||||
gpio_set_level(PWR_Control_PIN, true);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() {
|
||||
InitializeI2c();
|
||||
InitializeTca9554();
|
||||
InitializeSpi();
|
||||
InitializeSpd2010Display();
|
||||
InitializeButtons();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, I2S_STD_SLOT_LEFT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN, I2S_STD_SLOT_RIGHT); // I2S_STD_SLOT_LEFT / I2S_STD_SLOT_RIGHT / I2S_STD_SLOT_BOTH
|
||||
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
|
||||
CustomBoard* CustomBoard::instance_ = nullptr;
|
||||
49
main/boards/waveshare/esp32-s3-touch-lcd-1.54/README.md
Normal file
49
main/boards/waveshare/esp32-s3-touch-lcd-1.54/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-Touch-LCD-1.54](https://www.waveshare.net/shop/ESP32-S3-Touch-LCD-1.54.htm)
|
||||
[微雪电子 ESP32-S3-LCD-1.54](https://www.waveshare.net/shop/ESP32-S3-LCD-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-Touch-LCD-1.54
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user