4#include "freertos/FreeRTOS.h"
5#include "freertos/task.h"
6#include "driver/i2s_std.h"
11#if CONFIG_ENABLE_SDM_WAVE_GEN
12#if defined(__has_include)
13#if __has_include("driver/sdm.h") && __has_include("driver/gptimer.h")
14#define WAVE_GEN_HAS_SDM 1
15#include "driver/sdm.h"
16#include "driver/gptimer.h"
19#define WAVE_GEN_HAS_SDM 0
22#define WAVE_GEN_HAS_SDM 1
23#include "driver/sdm.h"
24#include "driver/gptimer.h"
28#define WAVE_GEN_HAS_SDM 0
31static const char *
TAG =
"wave_gen";
33#define I2S_BUFFER_SIZE 1024
34#define DEFAULT_SAMPLE_RATE 44100
35#define I2S_BUFFER_SIZE 1024
36#define DEFAULT_SAMPLE_RATE 44100
37#define PI 3.14159265358979323846f
51#define SDM_LUT_SIZE 256
52#define SDM_CARRIER_HZ (1 * 1000 * 1000)
53#define SDM_UPDATE_HZ (20 * 1000)
54#define SDM_DENSITY_MAX 90
56static sdm_channel_handle_t s_sdm_chan = NULL;
57static gptimer_handle_t s_sdm_timer = NULL;
58static volatile uint32_t s_sdm_phase_acc = 0;
59static uint32_t s_sdm_phase_step = 0;
60static int8_t s_sdm_lut[SDM_LUT_SIZE];
61static bool s_sdm_running =
false;
63static void sdm_build_lut(
float amplitude) {
64 if (amplitude < 0.0f) amplitude = 0.0f;
65 if (amplitude > 1.0f) amplitude = 1.0f;
66 for (
int i = 0; i < SDM_LUT_SIZE; i++) {
67 float phase = (float)i / (
float)SDM_LUT_SIZE;
68 float s = sinf(phase * 2.0f *
PI);
69 int32_t density = (int32_t)lrintf(s * amplitude * (
float)SDM_DENSITY_MAX);
70 if (density > SDM_DENSITY_MAX) density = SDM_DENSITY_MAX;
71 if (density < -SDM_DENSITY_MAX) density = -SDM_DENSITY_MAX;
72 s_sdm_lut[i] = (int8_t)density;
76static bool IRAM_ATTR sdm_timer_cb(gptimer_handle_t timer,
77 const gptimer_alarm_event_data_t *edata,
82 uint32_t phase = s_sdm_phase_acc + s_sdm_phase_step;
83 s_sdm_phase_acc = phase;
84 uint8_t idx = (uint8_t)(phase >> 24);
85 sdm_channel_set_pulse_density(s_sdm_chan, s_sdm_lut[idx]);
89static esp_err_t sdm_init(uint32_t freq_hz) {
94 sdm_config_t config = {
95 .clk_src = SDM_CLK_SRC_DEFAULT,
96 .sample_rate_hz = SDM_CARRIER_HZ,
97 .gpio_num = CONFIG_SDM_GPIO,
103 if (freq_hz < 1) freq_hz = 1;
104 s_sdm_phase_step = (uint32_t)(((uint64_t)freq_hz << 32) / SDM_UPDATE_HZ);
107 gptimer_config_t tcfg = {
108 .clk_src = GPTIMER_CLK_SRC_DEFAULT,
109 .direction = GPTIMER_COUNT_UP,
110 .resolution_hz = SDM_UPDATE_HZ,
114 gptimer_event_callbacks_t cbs = {
115 .on_alarm = sdm_timer_cb,
117 ESP_RETURN_ON_ERROR(gptimer_register_event_callbacks(s_sdm_timer, &cbs, NULL),
TAG,
"Failed to register SDM timer callback");
119 gptimer_alarm_config_t alarm_cfg = {
122 .flags.auto_reload_on_alarm =
true,
124 ESP_RETURN_ON_ERROR(gptimer_set_alarm_action(s_sdm_timer, &alarm_cfg),
TAG,
"Failed to set SDM timer alarm");
131static void sdm_deinit(
void) {
133 gptimer_stop(s_sdm_timer);
134 gptimer_disable(s_sdm_timer);
135 gptimer_del_timer(s_sdm_timer);
139 sdm_channel_disable(s_sdm_chan);
140 sdm_del_channel(s_sdm_chan);
151 int32_t *samples = (int32_t *)malloc(
I2S_BUFFER_SIZE * 2 *
sizeof(int32_t));
153 ESP_LOGE(
TAG,
"Failed to allocate audio buffer");
158 float phase_inc = 0.0f;
169 float sample_val = 0.0f;
176 sample_val = (
s_phase < 0.5f) ? 1.0f : -1.0f;
182 sample_val = 2.0f *
s_phase - 1.0f;
188 int32_t pcm_val = (int32_t)(sample_val *
s_volume * 2147483647.0f);
191 samples[i * 2] = pcm_val;
192 samples[i * 2 + 1] = pcm_val;
204 ESP_LOGW(
TAG,
"I2S Write Failed");
216 ESP_LOGW(
TAG,
"Already initialized");
220 ESP_LOGI(
TAG,
"Initializing I2S Wave Gen (32-bit) on BCK:%d WS:%d DO:%d MCK:%d",
223 i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
226 i2s_std_config_t std_cfg = {
227 .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(config->
sample_rate),
228 .slot_cfg = I2S_STD_PCM_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO),
234 .din = I2S_GPIO_UNUSED,
262 ESP_LOGI(
TAG,
"Wave Gen Started");
275 vTaskDelay(pdMS_TO_TICKS(100));
280 ESP_LOGI(
TAG,
"Wave Gen Stopped");
286 if (freq_hz < 1.0f) freq_hz = 1.0f;
298 if (volume < 0.0f) volume = 0.0f;
299 if (volume > 1.0f) volume = 1.0f;
309 ESP_LOGI(
TAG,
"Starting SDM sine on GPIO %d at %d Hz", CONFIG_SDM_GPIO, CONFIG_SDM_FREQ_HZ);
311 s_sdm_running =
true;
314 return ESP_ERR_NOT_SUPPORTED;
321 if (!s_sdm_running) {
324 s_sdm_running =
false;
328 return ESP_ERR_NOT_SUPPORTED;
#define ESP_RETURN_ON_ERROR(x, log_tag, format,...)
Configuration structure for Wave Generator.
void wave_gen_set_type(wave_type_t type)
Set the waveform type.
void wave_gen_set_freq(float freq_hz)
Set the frequency of the generated wave.
esp_err_t wave_gen_stop(void)
Stop the wave generation task.
esp_err_t wave_gen_init(const wave_gen_config_t *config)
Initialize the Wave Generator component.
esp_err_t wave_gen_sdm_stop(void)
Stop the SDM sine generator.
static wave_type_t s_type
static void wave_gen_task(void *args)
static TaskHandle_t s_wave_task_handle
static uint32_t s_sample_rate
esp_err_t wave_gen_start(void)
Start the wave generation task.
#define DEFAULT_SAMPLE_RATE
esp_err_t wave_gen_sdm_start(void)
Start the SDM sine generator (uses CONFIG_SDM_* settings).
static i2s_chan_handle_t tx_conn_handle
void wave_gen_set_volume(float volume)
Set the output volume/amplitude.
wave_type_t
Waveform types for generation.