diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 2e93df7425..f8dd2db18d 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -111,6 +111,10 @@ elseif(CONFIG_BOARD_TYPE_LILYGO_T_CIRCLE_S3) set(BOARD_TYPE "lilygo-t-circle-s3") elseif(CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3) set(BOARD_TYPE "lilygo-t-cameraplus-s3") +elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA) + set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora") +elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY) + set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora") elseif(CONFIG_BOARD_TYPE_MOVECALL_MOJI_ESP32S3) set(BOARD_TYPE "movecall-moji-esp32s3") elseif(CONFIG_BOARD_TYPE_MOVECALL_CUICAN_ESP32S3) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 67d2a12df0..d27174da43 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -106,6 +106,10 @@ choice BOARD_TYPE bool "LILYGO T-Circle-S3" config BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3 bool "LILYGO T-CameraPlus-S3" + config BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA + bool "LILYGO T-Display-S3-Pro-MVSRLora" + config BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY + bool "LILYGO T-Display-S3-Pro-MVSRLora_No_Battery" config BOARD_TYPE_MOVECALL_MOJI_ESP32S3 bool "Movecall Moji 小智AI衍生版" config BOARD_TYPE_MOVECALL_CUICAN_ESP32S3 diff --git a/main/boards/lilygo-t-display-s3-pro-mvsrlora/README.md b/main/boards/lilygo-t-display-s3-pro-mvsrlora/README.md new file mode 100644 index 0000000000..c3b8d0eb53 --- /dev/null +++ b/main/boards/lilygo-t-display-s3-pro-mvsrlora/README.md @@ -0,0 +1,32 @@ +# 编译配置命令 + +**配置编译目标为 ESP32S3:** + +```bash +idf.py set-target esp32s3 +``` + +**打开 menuconfig:** + +```bash +idf.py menuconfig +``` + +**选择板子:** + +``` +Xiaozhi Assistant -> Board Type -> LILYGO T-Display-S3-Pro-MVSRLora +Or +Xiaozhi Assistant -> Board Type -> LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY +``` + + +**编译:** + +```bash +idf.py build +``` + +LILYGO T-Display-S3-Pro +
+LILYGO T-Display-S3-Pro-MVSRLora \ No newline at end of file diff --git a/main/boards/lilygo-t-display-s3-pro-mvsrlora/config.h b/main/boards/lilygo-t-display-s3-pro-mvsrlora/config.h new file mode 100644 index 0000000000..44c0a03f0a --- /dev/null +++ b/main/boards/lilygo-t-display-s3-pro-mvsrlora/config.h @@ -0,0 +1,47 @@ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +#include +#include "pin_config.h" + +#define AUDIO_INPUT_REFERENCE true +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 + +#define AUDIO_MIC_I2S_GPIO_BCLK GPIO_NUM_NC +#define AUDIO_MIC_I2S_GPIO_WS static_cast(MP34DT05TR_LRCLK) +#define AUDIO_MIC_I2S_GPIO_DATA static_cast(MP34DT05TR_DATA) +#define AUDIO_MIC_ENABLE static_cast(MP34DT05TR_EN) + +#define AUDIO_SPKR_I2S_GPIO_BCLK static_cast(MAX98357A_BCLK) +#define AUDIO_SPKR_I2S_GPIO_LRCLK static_cast(MAX98357A_LRCLK) +#define AUDIO_SPKR_I2S_GPIO_DATA static_cast(MAX98357A_DATA) +#define AUDIO_SPKR_ENABLE static_cast(MAX98357A_EN) + +#define TOUCH_I2C_SDA_PIN static_cast(TOUCH_IIC_SDA) +#define TOUCH_I2C_SCL_PIN static_cast(TOUCH_IIC_SCL) + +#define BUILTIN_LED_GPIO GPIO_NUM_NC +#define BOOT_BUTTON_GPIO GPIO_NUM_0 +#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC +#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC + +#define DISPLAY_WIDTH LCD_WIDTH +#define DISPLAY_HEIGHT LCD_HEIGHT +#define DISPLAY_MOSI LCD_MOSI +#define DISPLAY_SCLK LCD_SCLK +#define DISPLAY_DC LCD_DC +#define DISPLAY_RST LCD_RST +#define DISPLAY_CS LCD_CS +#define DISPLAY_BL static_cast(LCD_BL) +#define DISPLAY_MIRROR_X true +#define DISPLAY_MIRROR_Y false +#define DISPLAY_SWAP_XY false + +#define DISPLAY_OFFSET_X 0 +#define DISPLAY_OFFSET_Y 0 + +#define DISPLAY_BACKLIGHT_PIN DISPLAY_BL +#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false + +#endif // _BOARD_CONFIG_H_ diff --git a/main/boards/lilygo-t-display-s3-pro-mvsrlora/config.json b/main/boards/lilygo-t-display-s3-pro-mvsrlora/config.json new file mode 100644 index 0000000000..f7e4505ef2 --- /dev/null +++ b/main/boards/lilygo-t-display-s3-pro-mvsrlora/config.json @@ -0,0 +1,9 @@ +{ + "target": "esp32s3", + "builds": [ + { + "name": "lilygo-t-display-s3-pro-mvsrlora", + "sdkconfig_append": [] + } + ] +} \ No newline at end of file diff --git a/main/boards/lilygo-t-display-s3-pro-mvsrlora/lilygo-t-display-s3-pro-mvsrlora.cc b/main/boards/lilygo-t-display-s3-pro-mvsrlora/lilygo-t-display-s3-pro-mvsrlora.cc new file mode 100644 index 0000000000..b79c35c413 --- /dev/null +++ b/main/boards/lilygo-t-display-s3-pro-mvsrlora/lilygo-t-display-s3-pro-mvsrlora.cc @@ -0,0 +1,305 @@ +#include "wifi_board.h" +#include "tdisplays3promvsrlora_audio_codec.h" +#include "display/lcd_display.h" +#include "application.h" +#include "button.h" +#include "config.h" +#include "power_save_timer.h" +#include "i2c_device.h" +#include "iot/thing_manager.h" + +#include +#include +#include +#include +#include +#include "esp_lcd_st7796.h" + +#define TAG "LilygoTDisplays3ProMVSRLoraBoard" + +LV_FONT_DECLARE(font_puhui_16_4); +LV_FONT_DECLARE(font_awesome_16_4); + +class Cst2xxse : public I2cDevice { +public: + struct TouchPoint_t { + int num = 0; + int x = -1; + int y = -1; + }; + + Cst2xxse(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) { + uint8_t chip_id = ReadReg(0x06); + ESP_LOGI(TAG, "Get cst2xxse chip ID: 0x%02X", chip_id); + read_buffer_ = new uint8_t[6]; + } + + ~Cst2xxse() { + delete[] read_buffer_; + } + + void UpdateTouchPoint() { + ReadRegs(0x00, read_buffer_, 6); + tp_.num = read_buffer_[5] & 0x0F; + tp_.x = (static_cast(read_buffer_[1]) << 4) | (read_buffer_[3] & 0xF0); + tp_.y = (static_cast(read_buffer_[2]) << 4) | (read_buffer_[3] & 0x0F); + // ESP_LOGI(TAG, "Touch num: %d x: %d y: %d", tp_.num,tp_.x,tp_.y); + } + + const TouchPoint_t &GetTouchPoint() { + return tp_; + } + +private: + uint8_t *read_buffer_ = nullptr; + TouchPoint_t tp_; +}; + +class Sy6970 : public I2cDevice { +public: + + Sy6970(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) { + uint8_t chip_id = ReadReg(0x14); + ESP_LOGI(TAG, "Get sy6970 chip ID: 0x%02X", (chip_id & 0B00111000)); + + WriteReg(0x00,0B00001000); // Disable ILIM pin + WriteReg(0x02,0B11011101); // Enable ADC measurement function + WriteReg(0x07,0B10001101); // Disable watchdog timer feeding function + + #ifdef CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY + WriteReg(0x09,0B01100100); // Disable BATFET when battery is not needed + #endif + } +}; + +class LilygoTDisplays3ProMVSRLoraBoard : public WifiBoard { +private: + i2c_master_bus_handle_t i2c_bus_; + Cst2xxse *cst226se_; + Sy6970 *sy6970_; + LcdDisplay *display_; + Button boot_button_; + PowerSaveTimer* power_save_timer_; + + 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(10); + }); + power_save_timer_->OnExitSleepMode([this]() { + auto display = GetDisplay(); + display->SetChatMessage("system", ""); + display->SetEmotion("neutral"); + GetBacklight()->RestoreBrightness(); + }); + power_save_timer_->SetEnabled(true); + } + + void InitI2c(){ + // Initialize I2C peripheral + i2c_master_bus_config_t i2c_bus_config = { + .i2c_port = I2C_NUM_0, + .sda_io_num = TOUCH_I2C_SDA_PIN, + .scl_io_num = TOUCH_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_config, &i2c_bus_)); + } + + void I2cDetect() { + uint8_t address; + printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n"); + for (int i = 0; i < 128; i += 16) { + printf("%02x: ", i); + for (int j = 0; j < 16; j++) { + fflush(stdout); + address = i + j; + esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200)); + if (ret == ESP_OK) { + printf("%02x ", address); + } else if (ret == ESP_ERR_TIMEOUT) { + printf("UU "); + } else { + printf("-- "); + } + } + printf("\r\n"); + } + } + + static void touchpad_daemon(void *param) { + vTaskDelay(pdMS_TO_TICKS(2000)); + auto &board = (LilygoTDisplays3ProMVSRLoraBoard&)Board::GetInstance(); + auto touchpad = board.GetTouchpad(); + bool was_touched = false; + while (1) { + touchpad->UpdateTouchPoint(); + if (touchpad->GetTouchPoint().num > 0){ + // On press + if (!was_touched) { + was_touched = true; + Application::GetInstance().ToggleChatState(); + } + } + // On release + else if (was_touched) { + was_touched = false; + } + vTaskDelay(pdMS_TO_TICKS(50)); + } + vTaskDelete(NULL); + } + + void InitCst226se() { + ESP_LOGI(TAG, "Init Cst2xxse"); + cst226se_ = new Cst2xxse(i2c_bus_, 0x5A); + xTaskCreate(touchpad_daemon, "tp", 4096, NULL, 5, NULL); + } + + void InitSy6970() { + ESP_LOGI(TAG, "Init Sy6970"); + sy6970_ = new Sy6970(i2c_bus_, 0x6A); + } + + void InitSpi() { + spi_bus_config_t buscfg = {}; + buscfg.mosi_io_num = DISPLAY_MOSI; + buscfg.miso_io_num = GPIO_NUM_NC; + buscfg.sclk_io_num = DISPLAY_SCLK; + 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 InitSt7796Display() { + ESP_LOGI(TAG, "Init St7796"); + + esp_lcd_panel_io_handle_t panel_io = nullptr; + esp_lcd_panel_handle_t panel = nullptr; + + ESP_LOGD(TAG, "Install panel IO"); + esp_lcd_panel_io_spi_config_t io_config = {}; + io_config.cs_gpio_num = DISPLAY_CS; + io_config.dc_gpio_num = DISPLAY_DC; + io_config.spi_mode = 0; + 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_LOGD(TAG, "Install LCD driver"); + esp_lcd_panel_dev_config_t panel_config = {}; + panel_config.reset_gpio_num = DISPLAY_RST; + 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_invert_color(panel, true)); + ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, false)); + ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, true, false)); + ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel, 49, 0)); + 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, + { + .text_font = &font_puhui_16_4, + .icon_font = &font_awesome_16_4, + .emoji_font = font_emoji_32_init(), + }); + + gpio_config_t config; + config.pin_bit_mask = BIT64(DISPLAY_BL); + config.mode = GPIO_MODE_OUTPUT; + config.pull_up_en = GPIO_PULLUP_DISABLE; + config.pull_down_en = GPIO_PULLDOWN_ENABLE; + config.intr_type = GPIO_INTR_DISABLE; +#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER + config.hys_ctrl_mode = GPIO_HYS_SOFT_ENABLE; +#endif + gpio_config(&config); + gpio_set_level(DISPLAY_BL, 0); + } + + void InitializeButtons() { + boot_button_.OnClick([this]() { + auto& app = Application::GetInstance(); + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { + ResetWifiConfiguration(); + } + power_save_timer_->WakeUp(); + app.ToggleChatState(); + }); + } + + // 物联网初始化,添加对 AI 可见设备 + void InitializeIot() { + auto &thing_manager = iot::ThingManager::GetInstance(); + thing_manager.AddThing(iot::CreateThing("Speaker")); + thing_manager.AddThing(iot::CreateThing("Screen")); + } + +public: + LilygoTDisplays3ProMVSRLoraBoard() : boot_button_(BOOT_BUTTON_GPIO) { + InitializePowerSaveTimer(); + InitI2c(); + I2cDetect(); + InitCst226se(); + InitSy6970(); + InitSpi(); + InitSt7796Display(); + InitializeButtons(); + InitializeIot(); + GetBacklight()->RestoreBrightness(); + } + + virtual AudioCodec *GetAudioCodec() override { + static Tdisplays3promvsrloraAudioCodec audio_codec( + AUDIO_INPUT_SAMPLE_RATE, + AUDIO_OUTPUT_SAMPLE_RATE, + AUDIO_MIC_I2S_GPIO_BCLK, + AUDIO_MIC_I2S_GPIO_WS, + AUDIO_MIC_I2S_GPIO_DATA, + AUDIO_SPKR_I2S_GPIO_BCLK, + AUDIO_SPKR_I2S_GPIO_LRCLK, + AUDIO_SPKR_I2S_GPIO_DATA, + AUDIO_INPUT_REFERENCE); + return &audio_codec; + } + + virtual Display *GetDisplay() override{ + return display_; + } + + virtual void SetPowerSaveMode(bool enabled) override { + if (!enabled) { + power_save_timer_->WakeUp(); + } + WifiBoard::SetPowerSaveMode(enabled); + } + + virtual Backlight* GetBacklight() override { + static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); + return &backlight; + } + + Cst2xxse *GetTouchpad() { + return cst226se_; + } +}; + +DECLARE_BOARD(LilygoTDisplays3ProMVSRLoraBoard); diff --git a/main/boards/lilygo-t-display-s3-pro-mvsrlora/pin_config.h b/main/boards/lilygo-t-display-s3-pro-mvsrlora/pin_config.h new file mode 100644 index 0000000000..0b952d547a --- /dev/null +++ b/main/boards/lilygo-t-display-s3-pro-mvsrlora/pin_config.h @@ -0,0 +1,80 @@ +/* + * @Description: None + * @Author: None + * @Date: 2023-08-16 14:24:03 + * @LastEditTime: 2025-04-23 11:25:00 + * @License: GPL 3.0 + */ +#pragma once + +// ST7796 +#define LCD_WIDTH 222 +#define LCD_HEIGHT 480 +#define LCD_BL 48 +#define LCD_MOSI 17 +#define LCD_MISO 8 +#define LCD_SCLK 18 +#define LCD_CS 39 +#define LCD_DC 9 +#define LCD_RST 47 + +// IIC +#define IIC_SDA 5 +#define IIC_SCL 6 + +// CST226SE +#define CST226SE_IIC_ADDRESS 0x5A +#define TOUCH_RST 13 +#define TOUCH_INT 21 +#define TOUCH_IIC_SDA IIC_SDA +#define TOUCH_IIC_SCL IIC_SCL + +// SY6970 +#define SY6970_SDA 5 +#define SY6970_SCL 6 +#define SY6970_Address 0x6A +#define SY6970_INT 21 + +// SD +#define SD_CS 14 +#define SD_MISO 8 +#define SD_MOSI 17 +#define SD_SCLK 18 + +// RT9080 +#define RT9080_EN 42 + +// MAX98357A +#define MAX98357A_BCLK 4 +#define MAX98357A_LRCLK 15 +#define MAX98357A_DATA 11 +#define MAX98357A_EN 41 + +// Vibration Motor +#define VIBRATINO_MOTOR_PWM 45 + +// PCF85063 +#define PCF85063_IIC_SDA 5 +#define PCF85063_IIC_SCL 6 +#define PCF85063_INT 21 + +// LR1121 +#define LR1121_BUSY 46 +#define LR1121_INT 40 +#define LR1121_SCLK 18 +#define LR1121_MOSI 17 +#define LR1121_MISO 8 +#define LR1121_CS 7 +#define LR1121_RST 10 + +// ICM20948 +#define ICM20948_ADDRESS 0x28 +#define ICM20948_SDA 5 +#define ICM20948_SCL 6 +#define ICM20948_INT 21 + +// MP34DT05TRF +#define MP34DT05TR_LRCLK 1 +#define MP34DT05TR_DATA 2 +#define MP34DT05TR_EN 3 + diff --git a/main/boards/lilygo-t-display-s3-pro-mvsrlora/tdisplays3promvsrlora_audio_codec.cc b/main/boards/lilygo-t-display-s3-pro-mvsrlora/tdisplays3promvsrlora_audio_codec.cc new file mode 100644 index 0000000000..0beec452dc --- /dev/null +++ b/main/boards/lilygo-t-display-s3-pro-mvsrlora/tdisplays3promvsrlora_audio_codec.cc @@ -0,0 +1,150 @@ +#include "tdisplays3promvsrlora_audio_codec.h" + +#include +#include +#include +#include + +#include "config.h" + +static const char TAG[] = "Tdisplays3promvsrloraAudioCodec"; + +Tdisplays3promvsrloraAudioCodec::Tdisplays3promvsrloraAudioCodec(int input_sample_rate, int output_sample_rate, + gpio_num_t mic_bclk, gpio_num_t mic_ws, gpio_num_t mic_data, + gpio_num_t spkr_bclk, gpio_num_t spkr_lrclk, gpio_num_t spkr_data, + bool input_reference) { + duplex_ = true; // 是否双工 + input_reference_ = input_reference; // 是否使用参考输入,实现回声消除 + input_channels_ = input_reference_ ? 2 : 1; // 输入通道数 + input_sample_rate_ = input_sample_rate; + output_sample_rate_ = output_sample_rate; + + CreateVoiceHardware(mic_bclk, mic_ws, mic_data, spkr_bclk, spkr_lrclk, spkr_data); + + gpio_config_t config_mic_en; + config_mic_en.pin_bit_mask = BIT64(AUDIO_MIC_ENABLE); + config_mic_en.mode = GPIO_MODE_OUTPUT; + config_mic_en.pull_up_en = GPIO_PULLUP_ENABLE; + config_mic_en.pull_down_en = GPIO_PULLDOWN_DISABLE; + config_mic_en.intr_type = GPIO_INTR_DISABLE; +#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER +config_mic_en.hys_ctrl_mode = GPIO_HYS_SOFT_ENABLE; +#endif + gpio_config(&config_mic_en); + gpio_set_level(AUDIO_MIC_ENABLE, 1); + + gpio_config_t config_spkr_en; + config_spkr_en.pin_bit_mask = BIT64(AUDIO_SPKR_ENABLE); + config_spkr_en.mode = GPIO_MODE_OUTPUT; + config_spkr_en.pull_up_en = GPIO_PULLUP_DISABLE; + config_spkr_en.pull_down_en = GPIO_PULLDOWN_ENABLE; + config_spkr_en.intr_type = GPIO_INTR_DISABLE; +#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER +config_spkr_en.hys_ctrl_mode = GPIO_HYS_SOFT_ENABLE; +#endif + gpio_config(&config_spkr_en); + gpio_set_level(AUDIO_SPKR_ENABLE, 0); + + ESP_LOGI(TAG, "Tdisplays3promvsrloraAudioCodec initialized"); +} + +Tdisplays3promvsrloraAudioCodec::~Tdisplays3promvsrloraAudioCodec() { + audio_codec_delete_codec_if(in_codec_if_); + audio_codec_delete_ctrl_if(in_ctrl_if_); + audio_codec_delete_codec_if(out_codec_if_); + audio_codec_delete_ctrl_if(out_ctrl_if_); + audio_codec_delete_gpio_if(gpio_if_); + audio_codec_delete_data_if(data_if_); +} + +void Tdisplays3promvsrloraAudioCodec::CreateVoiceHardware(gpio_num_t mic_bclk, gpio_num_t mic_ws, gpio_num_t mic_data, + gpio_num_t spkr_bclk, gpio_num_t spkr_lrclk, gpio_num_t spkr_data) { + + i2s_chan_config_t mic_chan_config = I2S_CHANNEL_DEFAULT_CONFIG(i2s_port_t(0), I2S_ROLE_MASTER); + mic_chan_config.auto_clear = true; // Auto clear the legacy data in the DMA buffer + i2s_chan_config_t spkr_chan_config = I2S_CHANNEL_DEFAULT_CONFIG(i2s_port_t(1), I2S_ROLE_MASTER); + spkr_chan_config.auto_clear = true; // Auto clear the legacy data in the DMA buffer + + ESP_ERROR_CHECK(i2s_new_channel(&mic_chan_config, NULL, &rx_handle_)); + ESP_ERROR_CHECK(i2s_new_channel(&spkr_chan_config, &tx_handle_, NULL)); + + i2s_pdm_rx_config_t mic_config = { + .clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(static_cast(input_sample_rate_)), + /* The data bit-width of PDM mode is fixed to 16 */ + .slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), + .gpio_cfg = { + .clk = mic_ws, + .din = mic_data, + .invert_flags = { + .clk_inv = false, + }, + }, + }; + + i2s_std_config_t spkr_config = { + .clk_cfg ={ + .sample_rate_hz = static_cast(11025), + .clk_src = I2S_CLK_SRC_DEFAULT, + .mclk_multiple = I2S_MCLK_MULTIPLE_256, + #ifdef I2S_HW_VERSION_2 + .ext_clk_freq_hz = 0, + #endif + }, + .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), + .gpio_cfg ={ + .mclk = I2S_GPIO_UNUSED, + .bclk = spkr_bclk, + .ws = spkr_lrclk, + .dout = spkr_data, + .din = I2S_GPIO_UNUSED, + .invert_flags = { + .mclk_inv = false, + .bclk_inv = false, + .ws_inv = false + } + } + }; + + ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_handle_, &mic_config)); + ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &spkr_config)); + ESP_LOGI(TAG, "Voice hardware created"); +} + +void Tdisplays3promvsrloraAudioCodec::SetOutputVolume(int volume) { + volume_ = volume; + AudioCodec::SetOutputVolume(volume); +} + +void Tdisplays3promvsrloraAudioCodec::EnableInput(bool enable) { + gpio_set_level(AUDIO_MIC_ENABLE, !enable); + AudioCodec::EnableInput(enable); +} + +void Tdisplays3promvsrloraAudioCodec::EnableOutput(bool enable) { + gpio_set_level(AUDIO_SPKR_ENABLE, enable); + AudioCodec::EnableOutput(enable); +} + +int Tdisplays3promvsrloraAudioCodec::Read(int16_t *dest, int samples){ + if (input_enabled_){ + size_t bytes_read; + i2s_channel_read(rx_handle_, dest, samples * sizeof(int16_t), &bytes_read, portMAX_DELAY); + + // ESP_LOGI(TAG, "Left: %d\n", dest[0]); + // ESP_LOGI(TAG,"Right: %d\n", dest[1]); + } + return samples; +} + +int Tdisplays3promvsrloraAudioCodec::Write(const int16_t *data, int samples){ + if (output_enabled_){ + size_t bytes_read; + auto output_data = (int16_t *)malloc(samples * sizeof(int16_t)); + for (size_t i = 0; i < samples; i++){ + output_data[i] = (float)data[i] * (float)(volume_ / 100.0); + } + i2s_channel_write(tx_handle_, output_data, samples * sizeof(int16_t), &bytes_read, portMAX_DELAY); + free(output_data); + } + return samples; +} diff --git a/main/boards/lilygo-t-display-s3-pro-mvsrlora/tdisplays3promvsrlora_audio_codec.h b/main/boards/lilygo-t-display-s3-pro-mvsrlora/tdisplays3promvsrlora_audio_codec.h new file mode 100644 index 0000000000..ac5b42ab87 --- /dev/null +++ b/main/boards/lilygo-t-display-s3-pro-mvsrlora/tdisplays3promvsrlora_audio_codec.h @@ -0,0 +1,37 @@ +#ifndef _TDISPLAYS3PROMVSRLORA_AUDIO_CODEC_H +#define _TDISPLAYS3PROMVSRLORA_AUDIO_CODEC_H + +#include "audio_codecs/audio_codec.h" + +#include +#include + +class Tdisplays3promvsrloraAudioCodec : public AudioCodec { +private: + const audio_codec_data_if_t *data_if_ = nullptr; + const audio_codec_ctrl_if_t *out_ctrl_if_ = nullptr; + const audio_codec_if_t *out_codec_if_ = nullptr; + const audio_codec_ctrl_if_t *in_ctrl_if_ = nullptr; + const audio_codec_if_t *in_codec_if_ = nullptr; + const audio_codec_gpio_if_t *gpio_if_ = nullptr; + + uint32_t volume_ = 70; + + void CreateVoiceHardware(gpio_num_t mic_bclk, gpio_num_t mic_ws, gpio_num_t mic_data,gpio_num_t spkr_bclk, gpio_num_t spkr_lrclk, gpio_num_t spkr_data); + + virtual int Read(int16_t *dest, int samples) override; + virtual int Write(const int16_t *data, int samples) override; + +public: +Tdisplays3promvsrloraAudioCodec(int input_sample_rate, int output_sample_rate, + gpio_num_t mic_bclk, gpio_num_t mic_ws, gpio_num_t mic_data, + gpio_num_t spkr_bclk, gpio_num_t spkr_lrclk, gpio_num_t spkr_data, + bool input_reference); + virtual ~Tdisplays3promvsrloraAudioCodec(); + + virtual void SetOutputVolume(int volume) override; + virtual void EnableInput(bool enable) override; + virtual void EnableOutput(bool enable) override; +}; + +#endif // _BOX_AUDIO_CODEC_H diff --git a/main/idf_component.yml b/main/idf_component.yml index efac5b8e6c..ba5103beff 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -4,6 +4,7 @@ dependencies: espressif/esp_lcd_ili9341: "==1.2.0" espressif/esp_lcd_gc9a01: "^2.0.1" espressif/esp_lcd_st77916: "^1.0.1" + espressif/esp_lcd_st7796: "==1.3.2" espressif/esp_lcd_spd2010: "==1.0.2" espressif/esp_io_expander_tca9554: "==2.0.0" espressif/esp_lcd_panel_io_additions: "^1.0.1"