ESP-IDF Firmware
Firmware architecture and call graph
Loading...
Searching...
No Matches
wave_gen.c File Reference
#include <math.h>
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "esp_log.h"
#include "esp_check.h"
#include "wave_gen.h"
Include dependency graph for wave_gen.c:

Go to the source code of this file.

Macros

#define WAVE_GEN_HAS_SDM   0
#define I2S_BUFFER_SIZE   1024
#define DEFAULT_SAMPLE_RATE   44100
#define I2S_BUFFER_SIZE   1024
#define DEFAULT_SAMPLE_RATE   44100
#define PI   3.14159265358979323846f

Functions

static void wave_gen_task (void *args)
esp_err_t wave_gen_init (const wave_gen_config_t *config)
 Initialize the Wave Generator component.
esp_err_t wave_gen_start (void)
 Start the wave generation task.
esp_err_t wave_gen_stop (void)
 Stop the wave generation task.
void wave_gen_set_freq (float freq_hz)
 Set the frequency of the generated wave.
void wave_gen_set_type (wave_type_t type)
 Set the waveform type.
void wave_gen_set_volume (float volume)
 Set the output volume/amplitude.
esp_err_t wave_gen_sdm_start (void)
 Start the SDM sine generator (uses CONFIG_SDM_* settings).
esp_err_t wave_gen_sdm_stop (void)
 Stop the SDM sine generator.

Variables

static const char * TAG = "wave_gen"
static i2s_chan_handle_t tx_conn_handle = NULL
static TaskHandle_t s_wave_task_handle = NULL
static bool s_running = false
static float s_frequency = 440.0f
static float s_volume = 0.5f
static wave_type_t s_type = WAVE_TYPE_SINE
static uint32_t s_sample_rate = 44100
static float s_phase = 0.0f

Macro Definition Documentation

◆ DEFAULT_SAMPLE_RATE [1/2]

#define DEFAULT_SAMPLE_RATE   44100

Definition at line 34 of file wave_gen.c.

◆ DEFAULT_SAMPLE_RATE [2/2]

#define DEFAULT_SAMPLE_RATE   44100

Definition at line 34 of file wave_gen.c.

◆ I2S_BUFFER_SIZE [1/2]

#define I2S_BUFFER_SIZE   1024

Definition at line 33 of file wave_gen.c.

◆ I2S_BUFFER_SIZE [2/2]

#define I2S_BUFFER_SIZE   1024

Definition at line 33 of file wave_gen.c.

Referenced by wave_gen_task().

◆ PI

#define PI   3.14159265358979323846f

Definition at line 37 of file wave_gen.c.

Referenced by wave_gen_task().

◆ WAVE_GEN_HAS_SDM

#define WAVE_GEN_HAS_SDM   0

Definition at line 28 of file wave_gen.c.

Function Documentation

◆ wave_gen_init()

esp_err_t wave_gen_init ( const wave_gen_config_t * config)

Initialize the Wave Generator component.

Parameters
configPointer to configuration structure
Returns
esp_err_t ESP_OK on success

Definition at line 213 of file wave_gen.c.

214{
215 if (tx_conn_handle) {
216 ESP_LOGW(TAG, "Already initialized");
217 return ESP_OK;
218 }
219
220 ESP_LOGI(TAG, "Initializing I2S Wave Gen (32-bit) on BCK:%d WS:%d DO:%d MCK:%d",
221 config->bck_io_num, config->ws_io_num, config->data_out_num, config->mck_io_num);
222
223 i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
224 ESP_RETURN_ON_ERROR(i2s_new_channel(&chan_cfg, &tx_conn_handle, NULL), TAG, "Failed to create I2S channel");
225
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),
229 .gpio_cfg = {
230 .mclk = config->mck_io_num, // Can be I2S_GPIO_UNUSED (-1)
231 .bclk = config->bck_io_num,
232 .ws = config->ws_io_num,
233 .dout = config->data_out_num,
234 .din = I2S_GPIO_UNUSED,
235 .invert_flags = {
236 .mclk_inv = false,
237 .bclk_inv = false,
238 .ws_inv = false,
239 },
240 },
241 };
242
243 // Some PCM5102 modules benefit from MCLK being enabled if wired,
244 // but often they generate it internally from BCK if MCLK is floating/grounded.
245 // The driver will handle pin configuration.
246
247 ESP_RETURN_ON_ERROR(i2s_channel_init_std_mode(tx_conn_handle, &std_cfg), TAG, "Failed to init I2S std mode");
248
249 s_sample_rate = config->sample_rate;
250 return ESP_OK;
251}
#define ESP_RETURN_ON_ERROR(x, log_tag, format,...)
#define ESP_OK
Definition esp_err.h:23
static const char * TAG
Definition main/main.c:31
uint32_t sample_rate
Definition wave_gen.h:27
static uint32_t s_sample_rate
Definition wave_gen.c:47
static i2s_chan_handle_t tx_conn_handle
Definition wave_gen.c:39

References wave_gen_config_t::bck_io_num, wave_gen_config_t::data_out_num, ESP_OK, ESP_RETURN_ON_ERROR, wave_gen_config_t::mck_io_num, s_sample_rate, wave_gen_config_t::sample_rate, TAG, tx_conn_handle, and wave_gen_config_t::ws_io_num.

Referenced by app_main().

Here is the caller graph for this function:

◆ wave_gen_sdm_start()

esp_err_t wave_gen_sdm_start ( void )

Start the SDM sine generator (uses CONFIG_SDM_* settings).

Returns
esp_err_t ESP_OK on success

Definition at line 303 of file wave_gen.c.

304{
305#if WAVE_GEN_HAS_SDM
306 if (s_sdm_running) {
307 return ESP_OK;
308 }
309 ESP_LOGI(TAG, "Starting SDM sine on GPIO %d at %d Hz", CONFIG_SDM_GPIO, CONFIG_SDM_FREQ_HZ);
310 ESP_RETURN_ON_ERROR(sdm_init((uint32_t)CONFIG_SDM_FREQ_HZ), TAG, "SDM init failed");
311 s_sdm_running = true;
312 return ESP_OK;
313#else
314 return ESP_ERR_NOT_SUPPORTED;
315#endif
316}

References ESP_OK, ESP_RETURN_ON_ERROR, and TAG.

Referenced by app_main().

Here is the caller graph for this function:

◆ wave_gen_sdm_stop()

esp_err_t wave_gen_sdm_stop ( void )

Stop the SDM sine generator.

Returns
esp_err_t ESP_OK on success

Definition at line 318 of file wave_gen.c.

319{
320#if WAVE_GEN_HAS_SDM
321 if (!s_sdm_running) {
322 return ESP_OK;
323 }
324 s_sdm_running = false;
325 sdm_deinit();
326 return ESP_OK;
327#else
328 return ESP_ERR_NOT_SUPPORTED;
329#endif
330}

References ESP_OK.

◆ wave_gen_set_freq()

void wave_gen_set_freq ( float freq_hz)

Set the frequency of the generated wave.

Parameters
freq_hzFrequency in Hertz

Definition at line 284 of file wave_gen.c.

285{
286 if (freq_hz < 1.0f) freq_hz = 1.0f;
287 if (freq_hz > (float)s_sample_rate / 2.0f) freq_hz = (float)s_sample_rate / 2.0f;
288 s_frequency = freq_hz;
289}
static float s_frequency
Definition wave_gen.c:44

References s_frequency, and s_sample_rate.

◆ wave_gen_set_type()

void wave_gen_set_type ( wave_type_t type)

Set the waveform type.

Parameters
typeOne of wave_type_t

Definition at line 291 of file wave_gen.c.

292{
293 s_type = type;
294}
static wave_type_t s_type
Definition wave_gen.c:46

References s_type.

Referenced by app_main().

Here is the caller graph for this function:

◆ wave_gen_set_volume()

void wave_gen_set_volume ( float volume)

Set the output volume/amplitude.

Parameters
volume0.0 to 1.0 (clamped)

Definition at line 296 of file wave_gen.c.

297{
298 if (volume < 0.0f) volume = 0.0f;
299 if (volume > 1.0f) volume = 1.0f;
300 s_volume = volume;
301}
static float s_volume
Definition wave_gen.c:45

References s_volume.

Referenced by app_main().

Here is the caller graph for this function:

◆ wave_gen_start()

esp_err_t wave_gen_start ( void )

Start the wave generation task.

Returns
esp_err_t ESP_OK on success

Definition at line 253 of file wave_gen.c.

254{
255 if (!tx_conn_handle) return ESP_FAIL;
256 if (s_running) return ESP_OK;
257
258 ESP_RETURN_ON_ERROR(i2s_channel_enable(tx_conn_handle), TAG, "Failed to enable channel");
259
260 s_running = true;
261 xTaskCreate(wave_gen_task, "wave_gen_task", 4096, NULL, 5, &s_wave_task_handle);
262 ESP_LOGI(TAG, "Wave Gen Started");
263 return ESP_OK;
264}
static void wave_gen_task(void *args)
Definition wave_gen.c:146
static TaskHandle_t s_wave_task_handle
Definition wave_gen.c:40
static bool s_running
Definition wave_gen.c:41

References ESP_OK, ESP_RETURN_ON_ERROR, s_running, s_wave_task_handle, TAG, tx_conn_handle, and wave_gen_task().

Referenced by app_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ wave_gen_stop()

esp_err_t wave_gen_stop ( void )

Stop the wave generation task.

Returns
esp_err_t ESP_OK on success

Definition at line 266 of file wave_gen.c.

267{
268 if (!s_running) return ESP_OK;
269 s_running = false;
270 // Wait for task or just let it spin down?
271 // For simplicity, we assume task sees s_running false and exits.
272 // Ideally we'd join or wait.
273
274 // Allow task to exit loop
275 vTaskDelay(pdMS_TO_TICKS(100));
276
277 if (tx_conn_handle) {
278 i2s_channel_disable(tx_conn_handle);
279 }
280 ESP_LOGI(TAG, "Wave Gen Stopped");
281 return ESP_OK;
282}

References ESP_OK, s_running, TAG, and tx_conn_handle.

◆ wave_gen_task()

void wave_gen_task ( void * args)
static

Definition at line 146 of file wave_gen.c.

147{
148 size_t w_bytes = 0;
149 // Stereo buffer (Left + Right interleaving)
150 // Using 32-bit samples for high resolution
151 int32_t *samples = (int32_t *)malloc(I2S_BUFFER_SIZE * 2 * sizeof(int32_t));
152 if (!samples) {
153 ESP_LOGE(TAG, "Failed to allocate audio buffer");
154 vTaskDelete(NULL);
155 return;
156 }
157
158 float phase_inc = 0.0f;
159
160 while (s_running) {
161 // Recalculate phase increment per block to allow dynamic frequency changes
162 // phase goes from 0.0f to 1.0f
163 if (s_sample_rate > 0) {
164 phase_inc = s_frequency / (float)s_sample_rate;
165 }
166
167 // Fill buffer
168 for (int i = 0; i < I2S_BUFFER_SIZE; i++) {
169 float sample_val = 0.0f;
170
171 switch (s_type) {
172 case WAVE_TYPE_SINE:
173 sample_val = sinf(s_phase * 2.0f * PI);
174 break;
175 case WAVE_TYPE_SQUARE:
176 sample_val = (s_phase < 0.5f) ? 1.0f : -1.0f;
177 break;
179 sample_val = (s_phase < 0.5f) ? (4.0f * s_phase - 1.0f) : (3.0f - 4.0f * s_phase);
180 break;
182 sample_val = 2.0f * s_phase - 1.0f;
183 break;
184 }
185
186 // Apply volume and scale to 32-bit signed integer range
187 // Max positive: 2147483647
188 int32_t pcm_val = (int32_t)(sample_val * s_volume * 2147483647.0f);
189
190 // Interleaved Stereo (Left = Right)
191 samples[i * 2] = pcm_val;
192 samples[i * 2 + 1] = pcm_val;
193
194 // Advance phase
195 s_phase += phase_inc;
196 if (s_phase >= 1.0f) {
197 s_phase -= 1.0f;
198 }
199 }
200
201 // Write to I2S
202 /* Because we are writing to a standard I2S channel, we should ensure the format matches the config */
203 if (i2s_channel_write(tx_conn_handle, samples, I2S_BUFFER_SIZE * 2 * sizeof(int32_t), &w_bytes, portMAX_DELAY) != ESP_OK) {
204 ESP_LOGW(TAG, "I2S Write Failed");
205 }
206 }
207
208 free(samples);
209 vTaskDelete(NULL);
210 s_wave_task_handle = NULL;
211}
#define I2S_BUFFER_SIZE
Definition wave_gen.c:33
#define PI
Definition wave_gen.c:37
static float s_phase
Definition wave_gen.c:48
@ WAVE_TYPE_SAWTOOTH
Definition wave_gen.h:16
@ WAVE_TYPE_TRIANGLE
Definition wave_gen.h:15
@ WAVE_TYPE_SINE
Definition wave_gen.h:13
@ WAVE_TYPE_SQUARE
Definition wave_gen.h:14

References ESP_OK, I2S_BUFFER_SIZE, PI, s_frequency, s_phase, s_running, s_sample_rate, s_type, s_volume, s_wave_task_handle, TAG, tx_conn_handle, WAVE_TYPE_SAWTOOTH, WAVE_TYPE_SINE, WAVE_TYPE_SQUARE, and WAVE_TYPE_TRIANGLE.

Referenced by wave_gen_start().

Here is the caller graph for this function:

Variable Documentation

◆ s_frequency

float s_frequency = 440.0f
static

Definition at line 44 of file wave_gen.c.

Referenced by wave_gen_set_freq(), and wave_gen_task().

◆ s_phase

float s_phase = 0.0f
static

Definition at line 48 of file wave_gen.c.

Referenced by wave_gen_task().

◆ s_running

bool s_running = false
static

Definition at line 41 of file wave_gen.c.

Referenced by wave_gen_start(), wave_gen_stop(), and wave_gen_task().

◆ s_sample_rate

uint32_t s_sample_rate = 44100
static

Definition at line 47 of file wave_gen.c.

Referenced by wave_gen_init(), wave_gen_set_freq(), and wave_gen_task().

◆ s_type

wave_type_t s_type = WAVE_TYPE_SINE
static

Definition at line 46 of file wave_gen.c.

Referenced by wave_gen_set_type(), and wave_gen_task().

◆ s_volume

float s_volume = 0.5f
static

Definition at line 45 of file wave_gen.c.

Referenced by wave_gen_set_volume(), and wave_gen_task().

◆ s_wave_task_handle

TaskHandle_t s_wave_task_handle = NULL
static

Definition at line 40 of file wave_gen.c.

Referenced by wave_gen_start(), and wave_gen_task().

◆ TAG

const char* TAG = "wave_gen"
static

Definition at line 31 of file wave_gen.c.

◆ tx_conn_handle

i2s_chan_handle_t tx_conn_handle = NULL
static

Definition at line 39 of file wave_gen.c.

Referenced by wave_gen_init(), wave_gen_start(), wave_gen_stop(), and wave_gen_task().