arduino-audio-tools
Loading...
Searching...
No Matches
I2SDriverESP32V1.h
Go to the documentation of this file.
1#pragma once
2
3#include "AudioToolsConfig.h"
4#if defined(ESP32) && !USE_LEGACY_I2S || defined(DOXYGEN)
5
8#include "driver/i2s_pdm.h"
9#include "driver/i2s_std.h"
10#include "driver/i2s_tdm.h"
11#include "esp_system.h"
12#include <atomic>
13
14#define IS_I2S_IMPLEMENTED
15
16namespace audio_tools {
17
18// i2s_port_t not valid any more in ESP-IDF v6, but we keep it for compatibility
19#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
20using i2s_port_t = int;
21#endif
22
23// support for Arduino ESP32 v3.0.7
24#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 1, 4)
25#define I2S_MCLK_MULTIPLE_192 static_cast<i2s_mclk_multiple_t>(192)
26#endif
27
28
37 public:
40 I2SConfigESP32V1 c(mode);
41 return c;
42 }
45 // nothing to do
46 if (is_started) {
47 if (info.equals(cfg)) return true;
48 if (info.equalsExSampleRate(cfg)) {
50 LOGI("i2s_set_sample_rates: %d", (int)info.sample_rate);
52 }
53 } else {
54 LOGE("not started");
55 }
56 return false;
57 }
58
60 bool begin(RxTxMode mode) { return begin(defaultConfig(mode)); }
61
64 bool begin() { return (!is_started) ? begin(cfg) : true; }
65
68 TRACED();
69 this->cfg = cfg;
70
71 // stop if it is already open
72 if (is_started) end();
73
74 switch (cfg.rx_tx_mode) {
75 case TX_MODE:
76 return begin(cfg, cfg.pin_data, I2S_GPIO_UNUSED);
77 case RX_MODE:
78 // usually we expet cfg.pin_data but if the used assinged rx we might
79 // consider this one
80 return begin(cfg, I2S_GPIO_UNUSED,
81 cfg.pin_data_rx != I2S_GPIO_UNUSED ? cfg.pin_data_rx
82 : cfg.pin_data);
83 default:
85 }
86 LOGE("Did not expect go get here");
87 }
88
91
99 uint32_t backlog = bytes_written_.load(std::memory_order_relaxed) -
100 bytes_sent_.load(std::memory_order_relaxed);
101 // Guards against transient over-reads while counters are mid-update
102 // across the ISR/task boundary; backlog can never legitimately exceed
103 // the DMA capacity itself.
104 if (backlog > dma_capacity_) backlog = dma_capacity_;
105 return (int)(dma_capacity_ - backlog);
106 }
107
109 void end() {
110 TRACED();
111 if (rx_chan != nullptr) {
112 i2s_channel_disable(rx_chan);
113 i2s_del_channel(rx_chan);
114 rx_chan = nullptr;
115 }
116 if (tx_chan != nullptr) {
117 i2s_channel_disable(tx_chan);
118 i2s_del_channel(tx_chan);
119 tx_chan = nullptr;
120 }
121
122 dma_capacity_ = 0;
123 is_started = false;
124 }
125
128
130 size_t writeBytes(const void *src, size_t size_bytes) {
131 TRACED();
132 size_t result = 0;
133 assert(tx_chan != nullptr);
134 if (i2s_channel_write(tx_chan, src, size_bytes, &result,
135 ticks_to_wait_write) != ESP_OK) {
136 TRACEE();
137 }
138 bytes_written_.fetch_add((uint32_t)result, std::memory_order_relaxed);
139 return result;
140 }
141
142 size_t readBytes(void *dest, size_t size_bytes) {
143 size_t result = 0;
144 if (i2s_channel_read(rx_chan, dest, size_bytes, &result,
145 ticks_to_wait_read) != ESP_OK) {
146 TRACEE();
147 }
148 return result;
149 }
150
157
158 protected:
160 i2s_std_config_t i2s_config;
161 i2s_chan_handle_t tx_chan = nullptr; // I2S tx channel handler
162 i2s_chan_handle_t rx_chan = nullptr; // I2S rx channel handler
163 bool is_started = false;
166
167 // Real TX DMA backlog tracking for availableForWrite() -- see
168 // DriverI2S::startChannels() for where onSentCb gets registered, and
169 // newChannels() for where dma_capacity_ is computed from the actual
170 // dma_desc_num/dma_frame_num ESP-IDF ends up allocating.
171 std::atomic<uint32_t> bytes_written_{0};
172 std::atomic<uint32_t> bytes_sent_{0};
173 uint32_t dma_capacity_ = 0;
174
178 static IRAM_ATTR bool onSentCb(i2s_chan_handle_t handle, i2s_event_data_t *event,
179 void *user_ctx) {
180 auto *self = static_cast<I2SDriverESP32V1 *>(user_ctx);
181 self->bytes_sent_.fetch_add((uint32_t)event->size,
182 std::memory_order_relaxed);
183 return false; // no higher-priority task to wake
184 }
185
188 i2s_chan_handle_t &tx_chan,
189 i2s_chan_handle_t &rx_chan, int txPin,
190 int rxPin, I2SDriverESP32V1 *self) = 0;
191
192 virtual i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) = 0;
193 // changes the sample rate
195 i2s_chan_handle_t &tx_chan,
196 i2s_chan_handle_t &rx_chan) {
197 return false;
198 }
199
200 protected:
202 int get_bits_eff(int bits) { return (bits == 24) ? 32 : bits; }
203 };
204
205 struct DriverI2S : public DriverCommon {
206 bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
207 i2s_chan_handle_t &rx_chan, int txPin, int rxPin,
208 I2SDriverESP32V1 *self) {
209 TRACED();
210 LOGI("tx: %d, rx: %d", txPin, rxPin);
211 i2s_std_config_t std_cfg;
212 std_cfg.clk_cfg = getClockConfig(cfg);
213 std_cfg.slot_cfg = getSlotConfig(cfg);
214 std_cfg.gpio_cfg = {
215 .mclk = (gpio_num_t)cfg.pin_mck,
216 .bclk = (gpio_num_t)cfg.pin_bck,
217 .ws = (gpio_num_t)cfg.pin_ws,
218 .dout = (gpio_num_t)txPin,
219 .din = (gpio_num_t)rxPin,
220 .invert_flags =
221 {
222 .mclk_inv = false,
223 .bclk_inv = false,
224 .ws_inv = false,
225 },
226 };
227
228
230 if (i2s_channel_init_std_mode(tx_chan, &std_cfg) != ESP_OK) {
231 LOGE("i2s_channel_init_std_mode %s", "tx");
232 return false;
233 }
234 // Must register while the channel is REGISTERED/READY, i.e. before
235 // i2s_channel_enable() below transitions it to RUNNING.
236 i2s_event_callbacks_t cbs = {};
237 cbs.on_sent = &I2SDriverESP32V1::onSentCb;
238 if (i2s_channel_register_event_callback(tx_chan, &cbs, self) != ESP_OK) {
239 LOGE("i2s_channel_register_event_callback %s", "tx");
240 } else {
241 // Real DMA capacity for availableForWrite(): read back the
242 // dma_desc_num/dma_frame_num ESP-IDF actually allocated (from the
243 // same getChannelConfig() computation newChannels() used to call
244 // i2s_new_channel()) rather than assuming
245 // cfg.buffer_size * cfg.buffer_count -- getChannelConfig() doesn't
246 // always set dma_desc_num explicitly, in which case it falls back
247 // to the I2S_CHANNEL_DEFAULT_CONFIG macro default (6).
248 i2s_chan_config_t chan_cfg = getChannelConfig(cfg);
249 int frame_size =
250 ((cfg.bits_per_sample == 24) ? 32 : cfg.bits_per_sample) *
251 cfg.channels / 8;
252 if (frame_size <= 0) frame_size = 1;
253 self->dma_capacity_ = (uint32_t)chan_cfg.dma_desc_num *
254 chan_cfg.dma_frame_num * frame_size;
255 self->bytes_written_ = 0;
256 self->bytes_sent_ = 0;
257 }
258 if (i2s_channel_enable(tx_chan) != ESP_OK) {
259 LOGE("i2s_channel_enable %s", "tx");
260 return false;
261 }
262 }
263
265 if (i2s_channel_init_std_mode(rx_chan, &std_cfg) != ESP_OK) {
266 LOGE("i2s_channel_init_std_mode %s", "rx");
267 return false;
268 }
269 if (i2s_channel_enable(rx_chan) != ESP_OK) {
270 LOGE("i2s_channel_enable %s", "rx");
271 return false;
272 }
273 }
274
275 LOGD("%s - %s", __func__, "started");
276 return true;
277 }
278
279 protected:
280 i2s_std_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg) {
281 TRACED();
282 i2s_std_slot_config_t result;
283 switch (cfg.i2s_format) {
285 case I2S_MSB_FORMAT:
286 result = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(
287 (i2s_data_bit_width_t)cfg.bits_per_sample,
288 (i2s_slot_mode_t)cfg.channels);
289 break;
290 case I2S_PCM:
291 result = I2S_STD_PCM_SLOT_DEFAULT_CONFIG(
292 (i2s_data_bit_width_t)cfg.bits_per_sample,
293 (i2s_slot_mode_t)cfg.channels);
294 break;
295 default:
296 result = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(
297 (i2s_data_bit_width_t)cfg.bits_per_sample,
298 (i2s_slot_mode_t)cfg.channels);
299 }
300
301 // Update slot_mask if only one channel
302 if (cfg.channels == 1) {
303 switch (cfg.channel_format) {
305 result.slot_mask = I2S_STD_SLOT_LEFT;
306 break;
308 result.slot_mask = I2S_STD_SLOT_RIGHT;
309 break;
310 default:
311 LOGW("Using channel_format: I2SChannelSelect::Left for mono");
312 result.slot_mask = I2S_STD_SLOT_LEFT;
313 break;
314 }
315 }
316
317 return result;
318 }
319
321 TRACED();
322 i2s_chan_config_t result = I2S_CHANNEL_DEFAULT_CONFIG(
324 cfg.is_master ? I2S_ROLE_MASTER : I2S_ROLE_SLAVE);
325 // use the legicy size parameters for frame num
326 int size = cfg.buffer_size * cfg.buffer_count;
327 int frame_size = get_bits_eff(cfg.bits_per_sample) * cfg.channels / 8;
328 frame_size = (frame_size == 0) ? 1 : frame_size;
329 if (size > 0) result.dma_frame_num = size / frame_size;
330 if (result.dma_frame_num == 0) result.dma_frame_num = 1;
331 LOGI("frame_size: %d", (int)frame_size);
332 LOGI("dma_frame_num: %d", (int)result.dma_frame_num);
333 LOGI("total buffer size: %d", (int)(result.dma_frame_num * frame_size));
334 result.auto_clear = cfg.auto_clear;
335 return result;
336 }
337
338 i2s_std_clk_config_t getClockConfig(I2SConfigESP32V1 &cfg) {
339 TRACED();
340 i2s_std_clk_config_t clk_cfg;// = I2S_STD_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
341 memset(&clk_cfg, 0, sizeof(i2s_std_clk_config_t));
342 clk_cfg.sample_rate_hz = cfg.sample_rate;
343 clk_cfg.clk_src = getClockSource(cfg);
344 // clk_cfg.ext_clk_freq_hz = 0;
345
346 if (cfg.mclk_multiple > 0) {
347 clk_cfg.mclk_multiple = (i2s_mclk_multiple_t)cfg.mclk_multiple;
348 LOGI("mclk_multiple=%d", clk_cfg.mclk_multiple);
349 } else {
350 if (cfg.bits_per_sample == 24) {
351 // mclk_multiple' should be the multiple of 3 while using 24-bit
352 // using the apll seems to double the frequency
353 clk_cfg.mclk_multiple = cfg.use_apll ? I2S_MCLK_MULTIPLE_192: I2S_MCLK_MULTIPLE_384;
354 LOGI("mclk_multiple=384");
355 } else {
356 // when use_appll is true, the multiple of 128 gives 256kHz
357 // using the apll seems to double the frequency
358 clk_cfg.mclk_multiple = cfg.use_apll ? I2S_MCLK_MULTIPLE_128 : I2S_MCLK_MULTIPLE_256;
359 LOGI("mclk_multiple=%d", clk_cfg.mclk_multiple);
360 }
361 }
362
363 return clk_cfg;
364 }
365
367 soc_periph_i2s_clk_src_t getClockSource(I2SConfigESP32V1 &cfg){
368 soc_periph_i2s_clk_src_t result = I2S_CLK_SRC_DEFAULT;
369 // use mclk pin as input in slave mode if supported
370 if (cfg.pin_mck != -1 && !cfg.is_master) {
371#if SOC_I2S_HW_VERSION_2
372 LOGI("pin_mclk is input");
373 result = I2S_CLK_SRC_EXTERNAL;
374 return result;
375#else
376 LOGE("pin_mclk as input not supported");
377#endif
378 }
379
380 // select APLL clock if possible
381 if (cfg.use_apll) {
382 // select clock source
383#if SOC_I2S_SUPPORTS_APLL
384 result = I2S_CLK_SRC_APLL;
385 LOGI("clk_src is I2S_CLK_SRC_APLL");
386#elif SOC_I2S_SUPPORTS_PLL_F160M
387 result = I2S_CLK_SRC_PLL_160M;
388 LOGI("clk_src is I2S_CLK_SRC_PLL_160M");
389#endif
390 }
391
392 return result;
393 }
394
395 bool changeSampleRate(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
396 i2s_chan_handle_t &rx_chan) override {
397 bool rc = false;
398 auto clock_cfg = getClockConfig(cfg);
399 if (tx_chan != nullptr) {
400 i2s_channel_disable(tx_chan);
401 rc = i2s_channel_reconfig_std_clock(tx_chan, &clock_cfg) == ESP_OK;
402 i2s_channel_enable(tx_chan);
403 }
404 if (rx_chan != nullptr) {
405 i2s_channel_disable(rx_chan);
406 rc = i2s_channel_reconfig_std_clock(rx_chan, &clock_cfg) == ESP_OK;
407 i2s_channel_enable(rx_chan);
408 }
409 return rc;
410 }
411
413
414#ifdef USE_PDM
415
416 struct DriverPDM : public DriverCommon {
417 bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
418 i2s_chan_handle_t &rx_chan, int txPin, int rxPin,
419 I2SDriverESP32V1 * /*self*/) {
420 if (cfg.rx_tx_mode == TX_MODE) {
421 return startTX(cfg, tx_chan, txPin);
422 } else if (cfg.rx_tx_mode == RX_MODE) {
423 return startRX(cfg, rx_chan, rxPin);
424 }
425 LOGE("Only RX and TX is supported for PDM")
426 return false;
427 }
428
429 protected:
430 i2s_pdm_tx_slot_config_t getTxSlotConfig(I2SConfigESP32V1 &cfg) {
431#ifdef SOC_I2S_HW_VERSION_2
432 return I2S_PDM_TX_SLOT_DAC_DEFAULT_CONFIG(
433 (i2s_data_bit_width_t)cfg.bits_per_sample,
434 (i2s_slot_mode_t)cfg.channels);
435#else
436 return I2S_PDM_TX_SLOT_DEFAULT_CONFIG(
437 (i2s_data_bit_width_t)cfg.bits_per_sample,
438 (i2s_slot_mode_t)cfg.channels);
439#endif
440 }
441
442 i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) {
443 return I2S_CHANNEL_DEFAULT_CONFIG(
444 (i2s_port_t)cfg.port_no,
445 cfg.is_master ? I2S_ROLE_MASTER : I2S_ROLE_SLAVE);
446 }
447
448 i2s_pdm_tx_clk_config_t getTxClockConfig(I2SConfigESP32V1 &cfg) {
449#if defined(I2S_PDM_TX_CLK_DAC_DEFAULT_CONFIG)
450 return I2S_PDM_TX_CLK_DAC_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
451#else
452 return I2S_PDM_TX_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
453#endif
454 }
455
456 bool startTX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, int txPin) {
457 i2s_pdm_tx_config_t pdm_tx_cfg = {
458 .clk_cfg = getTxClockConfig(cfg),
459 .slot_cfg = getTxSlotConfig(cfg),
460 .gpio_cfg =
461 {
462 .clk = (gpio_num_t)cfg.pin_bck,
463 .dout = (gpio_num_t)txPin,
464#if SOC_I2S_PDM_MAX_TX_LINES > 1
465 .dout2 = I2S_GPIO_UNUSED, // required in IDF v6+
466#endif
467 .invert_flags =
468 {
469 .clk_inv = false,
470 },
471 },
472 };
473
474 if (i2s_channel_init_pdm_tx_mode(tx_chan, &pdm_tx_cfg) != ESP_OK) {
475 LOGE("i2s_channel_init_pdm_tx_mode %s", "tx");
476 return false;
477 }
478 if (i2s_channel_enable(tx_chan) != ESP_OK) {
479 LOGE("i2s_channel_enable %s", "tx");
480 return false;
481 }
482 return true;
483 }
484
485#if defined(USE_PDM_RX)
486 i2s_pdm_rx_slot_config_t getRxSlotConfig(I2SConfigESP32V1 &cfg) {
487 return I2S_PDM_RX_SLOT_DEFAULT_CONFIG(
488 (i2s_data_bit_width_t)cfg.bits_per_sample,
489 (i2s_slot_mode_t)cfg.channels);
490 }
491 i2s_pdm_rx_clk_config_t getRxClockConfig(I2SConfigESP32V1 &cfg) {
492 return I2S_PDM_RX_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
493 }
494 bool startRX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &rx_chan, int rxPin) {
495 i2s_pdm_rx_config_t pdm_rx_cfg = {
496 .clk_cfg = getRxClockConfig(cfg),
497 .slot_cfg = getRxSlotConfig(cfg),
498 .gpio_cfg =
499 {
500 .clk = (gpio_num_t)cfg.pin_bck,
501 .din = (gpio_num_t)rxPin,
502 .invert_flags =
503 {
504 .clk_inv = false,
505 },
506 },
507 };
508
509 if (i2s_channel_init_pdm_rx_mode(rx_chan, &pdm_rx_cfg) != ESP_OK) {
510 LOGE("i2s_channel_init_pdm_rx_mode %s", "rx");
511 return false;
512 }
513 if (i2s_channel_enable(rx_chan) != ESP_OK) {
514 LOGE("i2s_channel_enable %s", "tx");
515 return false;
516 }
517 return true;
518 }
519#else
520 bool startRX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &rx_chan, int rxPin) {
521 LOGE("PDM RX not supported");
522 return false;
523 }
524#endif
525 } pdm;
526
527#endif
528
529#ifdef USE_TDM
530 // example at
531 // https://github.com/espressif/esp-idf/blob/v5.3-dev/examples/peripherals/i2s/i2s_basic/i2s_tdm/main/i2s_tdm_example_main.c
532 struct DriverTDM : public DriverCommon {
533 bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
534 i2s_chan_handle_t &rx_chan, int txPin, int rxPin,
535 I2SDriverESP32V1 * /*self*/) {
536 i2s_tdm_config_t tdm_cfg = {
537 .clk_cfg = getClockConfig(cfg),
538 .slot_cfg = getSlotConfig(cfg),
539 .gpio_cfg =
540 {
541 .mclk = (gpio_num_t)cfg.pin_mck,
542 .bclk = (gpio_num_t)cfg.pin_bck,
543 .ws = (gpio_num_t)cfg.pin_ws,
544 .dout = (gpio_num_t)txPin,
545 .din = (gpio_num_t)rxPin,
546 .invert_flags =
547 {
548 .mclk_inv = false,
549 .bclk_inv = false,
550 .ws_inv = false,
551 },
552 },
553 };
554
555 if (cfg.rx_tx_mode == TX_MODE || cfg.rx_tx_mode == RXTX_MODE) {
556 if (i2s_channel_init_tdm_mode(tx_chan, &tdm_cfg) != ESP_OK) {
557 LOGE("i2s_channel_init_tdm_tx_mode %s", "tx");
558 return false;
559 }
560 }
561 if (cfg.rx_tx_mode == RX_MODE || cfg.rx_tx_mode == RXTX_MODE) {
562 if (i2s_channel_init_tdm_mode(rx_chan, &tdm_cfg) != ESP_OK) {
563 LOGE("i2s_channel_init_tdm_tx_mode %s", "rx");
564 return false;
565 }
566 }
567 return true;
568 }
569
570 protected:
571 i2s_tdm_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg) {
572 int slots = 0;
573 for (int j = 0; j < cfg.channels; j++) {
574 slots |= 1 << j;
575 }
576 // setup default format
577 i2s_tdm_slot_config_t slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(
578 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
579 (i2s_tdm_slot_mask_t)slots);
580
581 switch (cfg.i2s_format) {
583 case I2S_LSB_FORMAT:
585 case I2S_STD_FORMAT:
586 slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(
587 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
588 (i2s_tdm_slot_mask_t)slots);
589 break;
591 case I2S_MSB_FORMAT:
592 slot_cfg = I2S_TDM_MSB_SLOT_DEFAULT_CONFIG(
593 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
594 (i2s_tdm_slot_mask_t)slots);
595 break;
596 case I2S_PCM:
597 slot_cfg = I2S_TDM_PCM_LONG_SLOT_DEFAULT_CONFIG(
598 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
599 (i2s_tdm_slot_mask_t)slots);
600 break;
601 default:
602 LOGE("TDM: Unsupported format");
603 }
604
605 return slot_cfg;
606 }
607
608 i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) {
609 return I2S_CHANNEL_DEFAULT_CONFIG(
610 (i2s_port_t)cfg.port_no,
611 cfg.is_master ? I2S_ROLE_MASTER : I2S_ROLE_SLAVE);
612 }
613
614 i2s_tdm_clk_config_t getClockConfig(I2SConfigESP32V1 &cfg) {
615 return I2S_TDM_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
616 }
617
618 } tdm;
619
620#endif
621
623
625 bool begin(I2SConfigESP32V1 cfg, int txPin, int rxPin) {
626 TRACED();
627 cfg.logInfo();
628 this->cfg = cfg;
629 if (cfg.channels <= 0 || cfg.channels > 2) {
630 LOGE("invalid channels: %d", cfg.channels);
631 return false;
632 }
633
634 DriverCommon &driver = getDriver(cfg);
635 if (!newChannels(cfg, driver)) {
636 end();
637 return false;
638 }
639
640 is_started = driver.startChannels(cfg, tx_chan, rx_chan, txPin, rxPin, this);
641 if (!is_started) {
642 end();
643 LOGE("Channels not started");
644 }
645 return is_started;
646 }
647
649 i2s_chan_config_t chan_cfg = driver.getChannelConfig(cfg);
650 // dma_capacity_/counters are only set up in DriverI2S::startChannels()
651 // (the only driver that registers the on_sent callback crediting
652 // bytes_sent_ back) -- leave them at 0 here for PDM/TDM so
653 // availableForWrite() keeps using the old constant fallback for those.
654 switch (cfg.rx_tx_mode) {
655 case RX_MODE:
656 if (i2s_new_channel(&chan_cfg, NULL, &rx_chan) != ESP_OK) {
657 LOGE("i2s_channel");
658 return false;
659 }
660 break;
661 case TX_MODE:
662 if (i2s_new_channel(&chan_cfg, &tx_chan, NULL) != ESP_OK) {
663 LOGE("i2s_channel");
664 return false;
665 }
666 break;
667 default:
668 if (i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan) != ESP_OK) {
669 LOGE("i2s_channel");
670 return false;
671 }
672 }
673 return true;
674 }
675
677 switch (cfg.signal_type) {
678 case Digital:
679 return i2s;
680#ifdef USE_PDM
681 case Analog:
682 case PDM:
683 return pdm;
684#endif
685#ifdef USE_TDM
686 case TDM:
687 return tdm;
688#endif
689 default:
690 break;
691 }
692 LOGE("Unsupported signal_type");
693 return i2s;
694 }
695};
696
697using I2SDriver = I2SDriverESP32V1;
698
699} // namespace audio_tools
700
701#endif
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define TRACEE()
Definition AudioLoggerIDF.h:34
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define IRAM_ATTR
Definition AudioStreams.h:13
#define I2S_BUFFER_SIZE
Definition AudioToolsConfig.h:107
#define I2S_BUFFER_COUNT
Definition AudioToolsConfig.h:111
#define I2S_MCLK_MULTIPLE_192
Definition I2SDriverESP32V1.h:25
#define portMAX_DELAY
Definition QueueZephyr.h:14
#define pdMS_TO_TICKS(ms)
Definition QueueZephyr.h:17
uint32_t TickType_t
Definition QueueZephyr.h:11
#define assert(T)
Definition avr.h:10
Configuration for ESP32 i2s for IDF > 5.0.
Definition I2SConfigESP32V1.h:21
int buffer_count
total buffer is max buffer_count * buffer_size
Definition I2SConfigESP32V1.h:65
int pin_mck
Definition I2SConfigESP32V1.h:63
RxTxMode rx_tx_mode
public settings
Definition I2SConfigESP32V1.h:54
int pin_ws
Definition I2SConfigESP32V1.h:59
bool auto_clear
Definition I2SConfigESP32V1.h:69
I2SSignalType signal_type
Definition I2SConfigESP32V1.h:56
int pin_data
Definition I2SConfigESP32V1.h:61
int pin_data_rx
Definition I2SConfigESP32V1.h:62
bool use_apll
Definition I2SConfigESP32V1.h:68
int mclk_multiple
masterclock multiple (-1 = use default)
Definition I2SConfigESP32V1.h:73
bool is_master
Definition I2SConfigESP32V1.h:57
int pin_bck
Definition I2SConfigESP32V1.h:60
I2SFormat i2s_format
Definition I2SConfigESP32V1.h:55
void logInfo(const char *source="")
Definition I2SConfigESP32V1.h:75
int port_no
Definition I2SConfigESP32V1.h:58
I2SChannelSelect channel_format
Select left or right channel when channels == 1.
Definition I2SConfigESP32V1.h:71
int buffer_size
total buffer is max buffer_count * buffer_size
Definition I2SConfigESP32V1.h:67
Definition I2SDriverBase.h:7
Basic I2S API for the ESP32 (using the new API). https://docs.espressif.com/projects/esp-idf/en/v5....
Definition I2SDriverESP32V1.h:36
std::atomic< uint32_t > bytes_written_
Definition I2SDriverESP32V1.h:171
I2SConfigESP32V1 defaultConfig(RxTxMode mode)
Provides the default configuration.
Definition I2SDriverESP32V1.h:39
void setWaitTimeWriteMs(TickType_t ms)
Definition I2SDriverESP32V1.h:154
bool begin(I2SConfigESP32V1 cfg)
starts the DAC
Definition I2SDriverESP32V1.h:67
i2s_chan_handle_t rx_chan
Definition I2SDriverESP32V1.h:162
TickType_t ticks_to_wait_read
Definition I2SDriverESP32V1.h:164
audio_tools::I2SDriverESP32V1::DriverI2S i2s
void setWaitTimeReadMs(TickType_t ms)
Definition I2SDriverESP32V1.h:151
int available()
we assume the data is already available in the buffer
Definition I2SDriverESP32V1.h:90
bool is_started
Definition I2SDriverESP32V1.h:163
bool begin()
Definition I2SDriverESP32V1.h:64
bool setAudioInfo(AudioInfo info)
Potentially updates the sample rate (if supported)
Definition I2SDriverESP32V1.h:44
std::atomic< uint32_t > bytes_sent_
Definition I2SDriverESP32V1.h:172
i2s_chan_handle_t tx_chan
Definition I2SDriverESP32V1.h:161
bool newChannels(I2SConfigESP32V1 &cfg, DriverCommon &driver)
Definition I2SDriverESP32V1.h:648
int availableForWrite()
Definition I2SDriverESP32V1.h:97
I2SConfigESP32V1 config()
provides the actual configuration
Definition I2SDriverESP32V1.h:127
uint32_t dma_capacity_
Definition I2SDriverESP32V1.h:173
DriverCommon & getDriver(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:676
static IRAM_ATTR bool onSentCb(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
Definition I2SDriverESP32V1.h:178
void end()
stops the I2C and unistalls the driver
Definition I2SDriverESP32V1.h:109
bool begin(RxTxMode mode)
starts the DAC with the default config
Definition I2SDriverESP32V1.h:60
bool begin(I2SConfigESP32V1 cfg, int txPin, int rxPin)
-> protected methods from I2SDriverESP32V1
Definition I2SDriverESP32V1.h:625
TickType_t ticks_to_wait_write
Definition I2SDriverESP32V1.h:165
size_t writeBytes(const void *src, size_t size_bytes)
writes the data to the I2S interface
Definition I2SDriverESP32V1.h:130
I2SConfigESP32V1 cfg
Definition I2SDriverESP32V1.h:159
i2s_std_config_t i2s_config
Definition I2SDriverESP32V1.h:160
size_t readBytes(void *dest, size_t size_bytes)
Definition I2SDriverESP32V1.h:142
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:26
@ RXTX_MODE
Definition AudioTypes.h:26
@ TX_MODE
Definition AudioTypes.h:26
@ RX_MODE
Definition AudioTypes.h:26
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
@ Digital
Definition AudioTypes.h:439
@ PDM
Definition AudioTypes.h:441
@ TDM
Definition AudioTypes.h:442
@ Analog
Definition AudioTypes.h:440
@ I2S_STD_FORMAT
Definition AudioTypes.h:418
@ I2S_PHILIPS_FORMAT
Definition AudioTypes.h:421
@ I2S_LSB_FORMAT
Definition AudioTypes.h:419
@ I2S_LEFT_JUSTIFIED_FORMAT
Definition AudioTypes.h:423
@ I2S_RIGHT_JUSTIFIED_FORMAT
Definition AudioTypes.h:422
@ I2S_MSB_FORMAT
Definition AudioTypes.h:420
@ I2S_PCM
Definition AudioTypes.h:424
int i2s_port_t
Definition I2SDriverESP32V1.h:20
I2SDriverESP32 I2SDriver
Definition I2SDriverESP32.h:403
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:51
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:53
bool equals(AudioInfo alt)
Returns true if alt values are the same like the current values.
Definition AudioTypes.h:83
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:55
bool equalsExSampleRate(AudioInfo alt)
Checks if only the sample rate is different.
Definition AudioTypes.h:86
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:57
Definition I2SDriverESP32V1.h:186
virtual i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg)=0
int get_bits_eff(int bits)
24 bits are stored in a 32 bit integer
Definition I2SDriverESP32V1.h:202
virtual bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, i2s_chan_handle_t &rx_chan, int txPin, int rxPin, I2SDriverESP32V1 *self)=0
virtual bool changeSampleRate(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, i2s_chan_handle_t &rx_chan)
Definition I2SDriverESP32V1.h:194
Definition I2SDriverESP32V1.h:205
bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, i2s_chan_handle_t &rx_chan, int txPin, int rxPin, I2SDriverESP32V1 *self)
Definition I2SDriverESP32V1.h:206
i2s_std_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:280
i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:320
i2s_std_clk_config_t getClockConfig(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:338
bool changeSampleRate(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, i2s_chan_handle_t &rx_chan) override
Definition I2SDriverESP32V1.h:395
soc_periph_i2s_clk_src_t getClockSource(I2SConfigESP32V1 &cfg)
select clock source dependent on is_master and use_apll
Definition I2SDriverESP32V1.h:367