feat: Add audio BSP component with welcome sound playback functionality

This commit is contained in:
2026-05-25 15:00:08 +08:00
parent 3bbb886fc1
commit cdb2347e43
9 changed files with 189 additions and 2 deletions
+21
View File
@@ -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)
+1
View File
@@ -5,6 +5,7 @@ idf_component_register(
espressif__esp_lvgl_adapter
port_bsp
lvgl__lvgl
esp_timer
main
INCLUDE_DIRS
"./")
+11
View File
@@ -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
"./")
+125
View File
@@ -0,0 +1,125 @@
#include "audio_bsp.h"
#include <stdint.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_log.h>
#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
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <esp_err.h>
/**
* 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);
+1 -1
View File
@@ -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
"./")
+12 -1
View File
@@ -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
+5
View File
@@ -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"
+3
View File
@@ -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);