2025-01-25 15:11:50 +08:00
# include "wifi_board.h"
2025-07-19 22:45:22 +08:00
# include "codecs/es8388_audio_codec.h"
2025-01-25 15:11:50 +08:00
# include "display/lcd_display.h"
# include "application.h"
# include "button.h"
# include "config.h"
# include "i2c_device.h"
# include "led/single_led.h"
2025-06-02 13:51:54 +08:00
# include "esp32_camera.h"
2025-01-25 15:11:50 +08:00
# include <esp_log.h>
# include <esp_lcd_panel_vendor.h>
# include <driver/i2c_master.h>
# include <driver/spi_common.h>
# include <wifi_station.h>
# define TAG "atk_dnesp32s3"
LV_FONT_DECLARE ( font_puhui_20_4 ) ;
LV_FONT_DECLARE ( font_awesome_20_4 ) ;
class XL9555 : public I2cDevice {
public :
XL9555 ( i2c_master_bus_handle_t i2c_bus , uint8_t addr ) : I2cDevice ( i2c_bus , addr ) {
WriteReg ( 0x06 , 0x03 ) ;
WriteReg ( 0x07 , 0xF0 ) ;
}
void SetOutputState ( uint8_t bit , uint8_t level ) {
uint16_t data ;
2025-04-22 10:28:26 +08:00
int index = bit ;
2025-01-25 15:11:50 +08:00
if ( bit < 8 ) {
data = ReadReg ( 0x02 ) ;
} else {
data = ReadReg ( 0x03 ) ;
2025-04-22 10:28:26 +08:00
index - = 8 ;
2025-01-25 15:11:50 +08:00
}
2025-04-22 10:28:26 +08:00
data = ( data & ~ ( 1 < < index ) ) | ( level < < index ) ;
2025-01-25 15:11:50 +08:00
if ( bit < 8 ) {
WriteReg ( 0x02 , data ) ;
} else {
WriteReg ( 0x03 , data ) ;
}
}
} ;
class atk_dnesp32s3 : public WifiBoard {
private :
i2c_master_bus_handle_t i2c_bus_ ;
Button boot_button_ ;
LcdDisplay * display_ ;
XL9555 * xl9555_ ;
2025-06-02 13:51:54 +08:00
Esp32Camera * camera_ ;
2025-01-25 15:11:50 +08:00
2025-01-25 15:17:37 +08:00
void InitializeI2c ( ) {
2025-01-25 15:11:50 +08:00
// 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_ ) ) ;
// Initialize XL9555
xl9555_ = new XL9555 ( i2c_bus_ , 0x20 ) ;
}
// Initialize spi peripheral
2025-01-25 15:17:37 +08:00
void InitializeSpi ( ) {
2025-01-25 15:11:50 +08:00
spi_bus_config_t buscfg = { } ;
buscfg . mosi_io_num = LCD_MOSI_PIN ;
buscfg . miso_io_num = GPIO_NUM_NC ;
buscfg . sclk_io_num = LCD_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 ) ) ;
}
2025-01-25 15:17:37 +08:00
void InitializeButtons ( ) {
boot_button_ . OnClick ( [ this ] ( ) {
2025-01-25 15:11:50 +08:00
auto & app = Application : : GetInstance ( ) ;
2025-01-25 15:17:37 +08:00
if ( app . GetDeviceState ( ) = = kDeviceStateStarting & & ! WifiStation : : GetInstance ( ) . IsConnected ( ) ) {
2025-01-25 15:11:50 +08:00
ResetWifiConfiguration ( ) ;
}
2025-04-04 15:53:50 +08:00
app . ToggleChatState ( ) ;
2025-01-25 15:11:50 +08:00
} ) ;
}
2025-01-25 15:17:37 +08:00
void InitializeSt7789Display ( ) {
2025-01-25 15:11:50 +08:00
esp_lcd_panel_io_handle_t panel_io = nullptr ;
esp_lcd_panel_handle_t panel = nullptr ;
ESP_LOGD ( TAG , " Install panel IO " ) ;
// 液晶屏控制IO初始化
esp_lcd_panel_io_spi_config_t io_config = { } ;
io_config . cs_gpio_num = LCD_CS_PIN ;
io_config . dc_gpio_num = LCD_DC_PIN ;
io_config . spi_mode = 0 ;
io_config . pclk_hz = 20 * 1000 * 1000 ;
io_config . trans_queue_depth = 7 ;
io_config . lcd_cmd_bits = 8 ;
io_config . lcd_param_bits = 8 ;
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 ;
panel_config . data_endian = LCD_RGB_DATA_ENDIAN_BIG ,
esp_lcd_new_panel_st7789 ( panel_io , & panel_config , & panel ) ;
esp_lcd_panel_reset ( panel ) ;
xl9555_ - > SetOutputState ( 8 , 1 ) ;
xl9555_ - > SetOutputState ( 2 , 0 ) ;
esp_lcd_panel_init ( panel ) ;
2025-03-18 20:55:03 +08:00
esp_lcd_panel_invert_color ( panel , DISPLAY_BACKLIGHT_OUTPUT_INVERT ) ;
2025-01-25 15:11:50 +08:00
esp_lcd_panel_swap_xy ( panel , DISPLAY_SWAP_XY ) ;
esp_lcd_panel_mirror ( panel , DISPLAY_MIRROR_X , DISPLAY_MIRROR_Y ) ;
2025-03-05 09:37:13 +08:00
display_ = new SpiLcdDisplay ( panel_io , panel ,
2025-01-25 15:11:50 +08:00
DISPLAY_WIDTH , DISPLAY_HEIGHT , DISPLAY_OFFSET_X , DISPLAY_OFFSET_Y , DISPLAY_MIRROR_X , DISPLAY_MIRROR_Y , DISPLAY_SWAP_XY ,
{
. text_font = & font_puhui_20_4 ,
. icon_font = & font_awesome_20_4 ,
2025-03-18 20:55:03 +08:00
# if CONFIG_USE_WECHAT_MESSAGE_STYLE
. emoji_font = font_emoji_32_init ( ) ,
# else
. emoji_font = DISPLAY_HEIGHT > = 240 ? font_emoji_64_init ( ) : font_emoji_32_init ( ) ,
# endif
2025-01-25 15:11:50 +08:00
} ) ;
}
2025-06-02 13:51:54 +08:00
// 初始化摄像头: ov2640;
// 根据正点原子官方示例参数
void InitializeCamera ( ) {
xl9555_ - > SetOutputState ( OV_PWDN_IO , 0 ) ; // PWDN=低 (上电)
xl9555_ - > SetOutputState ( OV_RESET_IO , 0 ) ; // 确保复位
vTaskDelay ( pdMS_TO_TICKS ( 50 ) ) ; // 延长复位保持时间
xl9555_ - > SetOutputState ( OV_RESET_IO , 1 ) ; // 释放复位
vTaskDelay ( pdMS_TO_TICKS ( 50 ) ) ; // 延长 50ms
camera_config_t config = { } ;
config . pin_pwdn = CAM_PIN_PWDN ; // 实际由 XL9555 控制
config . pin_reset = CAM_PIN_RESET ; // 实际由 XL9555 控制
config . pin_xclk = CAM_PIN_XCLK ;
config . pin_sccb_sda = CAM_PIN_SIOD ;
config . pin_sccb_scl = CAM_PIN_SIOC ;
config . pin_d7 = CAM_PIN_D7 ;
config . pin_d6 = CAM_PIN_D6 ;
config . pin_d5 = CAM_PIN_D5 ;
config . pin_d4 = CAM_PIN_D4 ;
config . pin_d3 = CAM_PIN_D3 ;
config . pin_d2 = CAM_PIN_D2 ;
config . pin_d1 = CAM_PIN_D1 ;
config . pin_d0 = CAM_PIN_D0 ;
config . pin_vsync = CAM_PIN_VSYNC ;
config . pin_href = CAM_PIN_HREF ;
config . pin_pclk = CAM_PIN_PCLK ;
/* XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) */
config . xclk_freq_hz = 24000000 ;
config . ledc_timer = LEDC_TIMER_0 ;
config . ledc_channel = LEDC_CHANNEL_0 ;
config . pixel_format = PIXFORMAT_RGB565 ; /* YUV422,GRAYSCALE,RGB565,JPEG */
config . frame_size = FRAMESIZE_QVGA ; /* QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates */
config . jpeg_quality = 12 ; /* 0-63, for OV series camera sensors, lower number means higher quality */
config . fb_count = 2 ; /* When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode */
config . fb_location = CAMERA_FB_IN_PSRAM ;
config . grab_mode = CAMERA_GRAB_WHEN_EMPTY ;
esp_err_t err = esp_camera_init ( & config ) ; // 测试相机是否存在
if ( err ! = ESP_OK ) {
ESP_LOGE ( TAG , " Camera is not plugged in or not supported, error: %s " , esp_err_to_name ( err ) ) ;
// 如果摄像头初始化失败,设置 camera_ 为 nullptr
camera_ = nullptr ;
return ;
} else
{
esp_camera_deinit ( ) ; // 释放之前的摄像头资源,为正确初始化做准备
camera_ = new Esp32Camera ( config ) ;
}
}
2025-01-25 15:11:50 +08:00
public :
atk_dnesp32s3 ( ) : boot_button_ ( BOOT_BUTTON_GPIO ) {
InitializeI2c ( ) ;
InitializeSpi ( ) ;
InitializeSt7789Display ( ) ;
InitializeButtons ( ) ;
2025-06-02 13:51:54 +08:00
InitializeCamera ( ) ;
2025-01-25 15:11:50 +08:00
}
virtual Led * GetLed ( ) override {
static SingleLed led ( BUILTIN_LED_GPIO ) ;
return & led ;
}
virtual AudioCodec * GetAudioCodec ( ) override {
2025-02-08 13:56:27 +08:00
static Es8388AudioCodec 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 ,
GPIO_NUM_NC ,
AUDIO_CODEC_ES8388_ADDR
) ;
return & audio_codec ;
2025-01-25 15:11:50 +08:00
}
virtual Display * GetDisplay ( ) override {
return display_ ;
}
2025-06-02 13:51:54 +08:00
virtual Camera * GetCamera ( ) override {
return camera_ ;
}
2025-01-25 15:11:50 +08:00
} ;
2025-02-04 23:10:49 +08:00
DECLARE_BOARD ( atk_dnesp32s3 ) ;