From cdb2347e43fbdad0d86444a4799114194dd8d7e2 Mon Sep 17 00:00:00 2001 From: furyhawk Date: Mon, 25 May 2026 15:00:08 +0800 Subject: [PATCH] feat: Add audio BSP component with welcome sound playback functionality --- CMakeLists.txt | 21 +++++ components/app_bsp/CMakeLists.txt | 1 + components/audio_bsp/CMakeLists.txt | 11 +++ components/audio_bsp/audio_bsp.cpp | 125 ++++++++++++++++++++++++++++ components/audio_bsp/audio_bsp.h | 10 +++ components/port_bsp/CMakeLists.txt | 2 +- dependencies.lock | 13 ++- main/CMakeLists.txt | 5 ++ main/app/app_main.cpp | 3 + 9 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 components/audio_bsp/CMakeLists.txt create mode 100644 components/audio_bsp/audio_bsp.cpp create mode 100644 components/audio_bsp/audio_bsp.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b3acf05..6df6169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,32 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# Reuse the proven codec_board component for startup audio chime support. +set(EXTRA_COMPONENT_DIRS + "${CMAKE_SOURCE_DIR}/02_Example/07_Audio_Test/components/ExternLib/codec_board") + # ESP-IDF v6 moved i2c_master.h to esp_driver_i2c; expose it for managed components if(EXISTS "$ENV{IDF_PATH}/components/esp_driver_i2c/include/driver/i2c_master.h") idf_build_set_property(INCLUDE_DIRECTORIES "$ENV{IDF_PATH}/components/esp_driver_i2c/include" APPEND) endif() +# ESP-IDF v6 splits more driver headers; keep legacy include resolution for codec stack. +if(EXISTS "$ENV{IDF_PATH}/components/esp_driver_gpio/include/driver/gpio.h") + idf_build_set_property(INCLUDE_DIRECTORIES "$ENV{IDF_PATH}/components/esp_driver_gpio/include" APPEND) +endif() +if(EXISTS "$ENV{IDF_PATH}/components/esp_driver_i2s/include/driver/i2s_std.h") + idf_build_set_property(INCLUDE_DIRECTORIES "$ENV{IDF_PATH}/components/esp_driver_i2s/include" APPEND) +endif() +if(EXISTS "$ENV{IDF_PATH}/components/esp_driver_spi/include/driver/spi_common.h") + idf_build_set_property(INCLUDE_DIRECTORIES "$ENV{IDF_PATH}/components/esp_driver_spi/include" APPEND) +endif() +if(EXISTS "$ENV{IDF_PATH}/components/esp_hal_gpspi/include/hal/spi_types.h") + idf_build_set_property(INCLUDE_DIRECTORIES "$ENV{IDF_PATH}/components/esp_hal_gpspi/include" APPEND) +endif() +if(EXISTS "$ENV{IDF_PATH}/components/esp_hal_i2s/include/hal/i2s_types.h") + idf_build_set_property(INCLUDE_DIRECTORIES "$ENV{IDF_PATH}/components/esp_hal_i2s/include" APPEND) +endif() + # Work around managed-component warnings that are promoted by global -Werror. add_compile_options(-Wno-error=attributes -Wno-error=cpp -Wno-error=missing-field-initializers) diff --git a/components/app_bsp/CMakeLists.txt b/components/app_bsp/CMakeLists.txt index b9496fc..43319fb 100644 --- a/components/app_bsp/CMakeLists.txt +++ b/components/app_bsp/CMakeLists.txt @@ -5,6 +5,7 @@ idf_component_register( espressif__esp_lvgl_adapter port_bsp lvgl__lvgl + esp_timer main INCLUDE_DIRS "./") diff --git a/components/audio_bsp/CMakeLists.txt b/components/audio_bsp/CMakeLists.txt new file mode 100644 index 0000000..b8a826e --- /dev/null +++ b/components/audio_bsp/CMakeLists.txt @@ -0,0 +1,11 @@ +idf_component_register( + SRCS + "audio_bsp.cpp" + REQUIRES + hw_platform + codec_board + espressif__esp_codec_dev + PRIV_REQUIRES + freertos + INCLUDE_DIRS + "./") diff --git a/components/audio_bsp/audio_bsp.cpp b/components/audio_bsp/audio_bsp.cpp new file mode 100644 index 0000000..371d8de --- /dev/null +++ b/components/audio_bsp/audio_bsp.cpp @@ -0,0 +1,125 @@ +#include "audio_bsp.h" + +#include + +#include +#include +#include + +#include "hw_platform.h" + +#if PLATFORM_HAS_AUDIO +#include "codec_board.h" +#include "codec_init.h" +#include "esp_codec_dev.h" +#endif + +#define TAG "audio_bsp" + +#if PLATFORM_HAS_AUDIO +static esp_err_t board_audio_play_square_tone(esp_codec_dev_handle_t speaker, + uint32_t freq_hz, + uint32_t duration_ms, + uint32_t sample_rate_hz) +{ + if(speaker == NULL || freq_hz == 0 || sample_rate_hz == 0) { + return ESP_ERR_INVALID_ARG; + } + + static constexpr uint32_t kChunkFrames = 256; + static constexpr int16_t kAmplitude = 5000; + int16_t pcm[kChunkFrames * 2] = {}; + + uint32_t frames_total = (sample_rate_hz * duration_ms) / 1000U; + if(frames_total == 0) { + return ESP_OK; + } + + uint32_t half_period = sample_rate_hz / (freq_hz * 2U); + if(half_period == 0) { + half_period = 1; + } + + uint32_t frame_index = 0; + while(frame_index < frames_total) { + uint32_t frames_now = frames_total - frame_index; + if(frames_now > kChunkFrames) { + frames_now = kChunkFrames; + } + + for(uint32_t i = 0; i < frames_now; ++i) { + uint32_t phase_block = (frame_index + i) / half_period; + int16_t sample = (phase_block & 1U) ? kAmplitude : (int16_t)-kAmplitude; + pcm[(i * 2U)] = sample; + pcm[(i * 2U) + 1U] = sample; + } + + int write_ret = esp_codec_dev_write(speaker, pcm, frames_now * sizeof(int16_t) * 2U); + if(write_ret != ESP_CODEC_DEV_OK) { + return ESP_FAIL; + } + + frame_index += frames_now; + } + + return ESP_OK; +} +#endif + +esp_err_t BoardAudio_PlayWelcomeSound(void) +{ +#if !PLATFORM_HAS_AUDIO + return ESP_ERR_NOT_SUPPORTED; +#else + set_codec_board_type("C6_AMOLED_2_16"); + + codec_init_cfg_t codec_cfg = {}; + codec_cfg.in_mode = CODEC_I2S_MODE_NONE; + codec_cfg.out_mode = CODEC_I2S_MODE_TDM; + codec_cfg.in_use_tdm = false; + codec_cfg.reuse_dev = false; + + if(init_codec(&codec_cfg) != 0) { + ESP_LOGW(TAG, "Audio codec init failed; skipping welcome sound"); + return ESP_FAIL; + } + + esp_codec_dev_handle_t speaker = get_playback_handle(); + if(speaker == NULL) { + ESP_LOGW(TAG, "No speaker handle available; skipping welcome sound"); + deinit_codec(); + return ESP_ERR_NOT_FOUND; + } + + esp_codec_dev_sample_info_t sample_info = {}; + sample_info.sample_rate = 16000; + sample_info.channel = 2; + sample_info.bits_per_sample = 16; + + if(esp_codec_dev_open(speaker, &sample_info) != ESP_CODEC_DEV_OK) { + ESP_LOGW(TAG, "Failed to open speaker; skipping welcome sound"); + deinit_codec(); + return ESP_FAIL; + } + + esp_codec_dev_set_out_vol(speaker, 75); + + esp_err_t tone_ret = ESP_OK; + if(board_audio_play_square_tone(speaker, 880, 90, sample_info.sample_rate) != ESP_OK) { + tone_ret = ESP_FAIL; + } + vTaskDelay(pdMS_TO_TICKS(10)); + if(board_audio_play_square_tone(speaker, 1175, 90, sample_info.sample_rate) != ESP_OK) { + tone_ret = ESP_FAIL; + } + vTaskDelay(pdMS_TO_TICKS(10)); + if(board_audio_play_square_tone(speaker, 1568, 140, sample_info.sample_rate) != ESP_OK) { + tone_ret = ESP_FAIL; + } + + esp_codec_dev_close(speaker); + deinit_codec(); + + return tone_ret; +#endif +} diff --git a/components/audio_bsp/audio_bsp.h b/components/audio_bsp/audio_bsp.h new file mode 100644 index 0000000..e35e8b4 --- /dev/null +++ b/components/audio_bsp/audio_bsp.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +/** + * Play a short welcome chime during desktop power-up. + * Returns ESP_OK when played, ESP_ERR_NOT_SUPPORTED when audio is unavailable, + * or another error when initialization/playback fails. + */ +esp_err_t BoardAudio_PlayWelcomeSound(void); diff --git a/components/port_bsp/CMakeLists.txt b/components/port_bsp/CMakeLists.txt index 3f41d60..813beb5 100644 --- a/components/port_bsp/CMakeLists.txt +++ b/components/port_bsp/CMakeLists.txt @@ -4,12 +4,12 @@ idf_component_register( "display_bsp.cpp" REQUIRES hw_platform + waveshare__esp_lcd_touch_cst9217 PRIV_REQUIRES driver esp_driver_i2c pmicpower espressif__esp_lcd_sh8601 - waveshare__esp_lcd_touch_cst9217 esp_timer INCLUDE_DIRS "./") diff --git a/dependencies.lock b/dependencies.lock index bf234e3..3e28385 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -33,6 +33,16 @@ dependencies: registry_url: https://components.espressif.com type: service version: 0.5.3 + espressif/esp_codec_dev: + component_hash: 3a1df01ee46d64c55155341bb6f4834db33db7dbd9b637e476e1eab64d01295a + dependencies: + - name: idf + require: private + version: '>=4.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.4.0 espressif/esp_lcd_sh8601: component_hash: 9597cce74af4bae0ec423ee819a2916b995ff3e5bb8d590bdb0a27fa9e715dab dependencies: @@ -292,6 +302,7 @@ dependencies: type: service version: 1.0.1 direct_dependencies: +- espressif/esp_codec_dev - espressif/esp_lcd_sh8601 - espressif/esp_lvgl_adapter - espressif/network_provisioning @@ -300,6 +311,6 @@ direct_dependencies: - waveshare/esp_lcd_touch_cst9217 - waveshare/pcf85063a - waveshare/qmi8658 -manifest_hash: 516a65b37cebe774fee5b9aee6de566de65d59f83ddaf940faac1c9ffd781a0a +manifest_hash: f4b0c1c694d3b31623b46182f2333db8f19aa8982ef96218ec14d864550e5cfa target: esp32c6 version: 3.0.0 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index bf7365f..2908195 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -2,6 +2,11 @@ idf_component_register( SRCS "app/app_main.cpp" "modules/desktop_ui/desktop_ui.cpp" "modules/wifi_provisioning/wifi_provisioning.cpp" + REQUIRES + audio_bsp + app_bsp + pmicpower + nvs_flash INCLUDE_DIRS "." "app" "modules/desktop_ui" diff --git a/main/app/app_main.cpp b/main/app/app_main.cpp index b3b1eea..fe98dcf 100644 --- a/main/app/app_main.cpp +++ b/main/app/app_main.cpp @@ -8,6 +8,7 @@ #include "desktop_ui.h" #include "wifi_provisioning.h" #include "qmi8658.h" +#include "audio_bsp.h" #define TAG "main" @@ -110,6 +111,8 @@ extern "C" void app_main(void) Lvgl_unlock(); } + (void)BoardAudio_PlayWelcomeSound(); + ESP_ERROR_CHECK(WifiProvisioning_Bootstrap()); esp_err_t ret = qmi8658_init(&qmi8658, user_i2cbus.Get_I2cBusHandle(), QMI8658_ADDRESS_HIGH);