#include "i2s_out.h" #include "waveform.h" #include "debug.h" #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/i2s_std.h" #include "driver/gpio.h" #include "esp_log.h" #define TAG "i2s_out" #define BUF_FRAMES 480 #define PIN_BCLK GPIO_NUM_16 #define PIN_WS GPIO_NUM_15 #define PIN_DOUT GPIO_NUM_17 static i2s_chan_handle_t tx_handle; void i2s_out_init(void) { i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); chan_cfg.dma_frame_num = BUF_FRAMES; ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, NULL)); i2s_std_config_t std_cfg = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE), .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), .gpio_cfg = { .mclk = I2S_GPIO_UNUSED, .bclk = PIN_BCLK, .ws = PIN_WS, .dout = PIN_DOUT, .din = I2S_GPIO_UNUSED, .invert_flags = { .mclk_inv = false, .bclk_inv = false, .ws_inv = false, }, }, }; ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); ESP_LOGI(TAG, "I2S TX initialized: 48kHz 16-bit stereo, BCLK=%d WS=%d DOUT=%d", PIN_BCLK, PIN_WS, PIN_DOUT); } static void i2s_out_task(void *arg) { int16_t buf[BUF_FRAMES * 2]; size_t bytes_written; DBG("i2s_out_task started"); for (;;) { for (int i = 0; i < BUF_FRAMES; i++) { buf[i * 2] = waveform_next_sample(0); buf[i * 2 + 1] = waveform_next_sample(1); } i2s_channel_write(tx_handle, buf, sizeof(buf), &bytes_written, portMAX_DELAY); } } void i2s_out_start_task(void) { xTaskCreatePinnedToCore(i2s_out_task, "i2s_out", 4096, NULL, 10, NULL, 1); }