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// Some ESP-IDF development snapshots (e.g. IDF_VERSION already bumped to a
29// release that hasn't shipped yet) initialize dma_buffer_in_psram before
30// allow_pd in I2S_CHANNEL_DEFAULT_CONFIG, which does not match
31// i2s_chan_config_t's declaration order and is ill-formed under C++20/26
32// aggregate-init rules. ESP_IDF_VERSION alone can't reliably tell such a
33// snapshot apart from an older one that predates these optional fields
34// entirely, so detect field presence directly and build the struct by
35// assignment instead of relying on the macro's designator order.
36#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 2, 0)
37#include <type_traits>
38namespace i2s_detail {
39template <typename T, typename = void>
40struct HasDmaBurstSize : std::false_type {};
41template <typename T>
42struct HasDmaBurstSize<T, std::void_t<decltype(std::declval<T &>().dma_burst_size)>>
43 : std::true_type {};
44
45template <typename T, typename = void>
46struct HasDmaBufferInPsram : std::false_type {};
47template <typename T>
48struct HasDmaBufferInPsram<T, std::void_t<decltype(std::declval<T &>().dma_buffer_in_psram)>>
49 : std::true_type {};
50} // namespace i2s_detail
51
52// Templated on T (defaulted to i2s_chan_config_t) so that the field accesses
53// below are dependent expressions: if constexpr only skips semantic checks on
54// a discarded branch inside a templated entity, not in an ordinary function.
55template <typename T = i2s_chan_config_t>
56static inline i2s_chan_config_t getDefaultChannelConfig(i2s_port_t port, i2s_role_t role) {
57 T result{};
58 result.id = port;
59 result.role = role;
60 result.dma_desc_num = 6;
61 result.dma_frame_num = 240;
63 result.dma_burst_size = 0;
64 }
65 result.auto_clear_after_cb = false;
66 result.auto_clear_before_cb = false;
68 result.dma_buffer_in_psram = false;
69 }
70 result.allow_pd = false;
71 result.intr_priority = 0;
72 // tx_destination/rx_destination (i2s_destination_t), where present, default
73 // to I2S_DESTINATION_DMA == 0, which T result{} already zero-initializes -
74 // no need to name the enumerator (it doesn't exist on older IDF versions).
75 return result;
76}
77#define I2S_CHANNEL_DEFAULT_CONFIG_SAFE(port, role) getDefaultChannelConfig(port, role)
78#else
79#define I2S_CHANNEL_DEFAULT_CONFIG_SAFE(port, role) I2S_CHANNEL_DEFAULT_CONFIG(port, role)
80#endif
81
82
91 public:
94 I2SConfigESP32V1 c(mode);
95 return c;
96 }
99 // nothing to do
100 if (is_started) {
101 if (info.equals(cfg)) return true;
102 if (info.equalsExSampleRate(cfg)) {
104 LOGI("i2s_set_sample_rates: %d", (int)info.sample_rate);
106 }
107 } else {
108 LOGE("not started");
109 }
110 return false;
111 }
112
114 bool begin(RxTxMode mode) { return begin(defaultConfig(mode)); }
115
118 bool begin() { return (!is_started) ? begin(cfg) : true; }
119
122 TRACED();
123 this->cfg = cfg;
124
125 // stop if it is already open
126 if (is_started) end();
127
128 switch (cfg.rx_tx_mode) {
129 case TX_MODE:
130 return begin(cfg, cfg.pin_data, I2S_GPIO_UNUSED);
131 case RX_MODE:
132 // usually we expet cfg.pin_data but if the used assinged rx we might
133 // consider this one
134 return begin(cfg, I2S_GPIO_UNUSED,
135 cfg.pin_data_rx != I2S_GPIO_UNUSED ? cfg.pin_data_rx
136 : cfg.pin_data);
137 default:
139 }
140 LOGE("Did not expect go get here");
141 }
142
145
153 uint32_t written = bytes_written_.load(std::memory_order_relaxed);
154 uint32_t sent = bytes_sent_.load(std::memory_order_relaxed);
155 // sent can exceed written: with auto_clear the driver fills idle DMA
156 // buffers with silence on its own, and on_sent still fires for those
157 // completions even though writeBytes() never ran for them. Saturate
158 // instead of letting the unsigned subtraction wrap to a huge value -
159 // that would get clamped to dma_capacity_ below and permanently report
160 // 0 free space, deadlocking the writer since nothing could call
161 // writeBytes() to let bytes_written_ catch back up.
162 uint32_t backlog = written > sent ? written - sent : 0;
163 // Guards against transient over-reads while counters are mid-update
164 // across the ISR/task boundary; backlog can never legitimately exceed
165 // the DMA capacity itself.
166 if (backlog > dma_capacity_) backlog = dma_capacity_;
167 return (int)(dma_capacity_ - backlog);
168 }
169
171 void end() {
172 TRACED();
173 if (rx_chan != nullptr) {
174 i2s_channel_disable(rx_chan);
175 i2s_del_channel(rx_chan);
176 rx_chan = nullptr;
177 }
178 if (tx_chan != nullptr) {
179 i2s_channel_disable(tx_chan);
180 i2s_del_channel(tx_chan);
181 tx_chan = nullptr;
182 }
183
184 dma_capacity_ = 0;
185 is_started = false;
186 }
187
201 void flush() override {
202 if (tx_chan != nullptr) {
203 i2s_channel_disable(tx_chan);
204 i2s_channel_enable(tx_chan);
205 bytes_written_.store(0, std::memory_order_relaxed);
206 bytes_sent_.store(0, std::memory_order_relaxed);
207 }
208 }
209
212
214 size_t writeBytes(const void *src, size_t size_bytes) {
215 TRACED();
216 size_t result = 0;
217 assert(tx_chan != nullptr);
218 if (i2s_channel_write(tx_chan, src, size_bytes, &result,
219 ticks_to_wait_write) != ESP_OK) {
220 TRACEE();
221 }
222 bytes_written_.fetch_add((uint32_t)result, std::memory_order_relaxed);
223 return result;
224 }
225
226 size_t readBytes(void *dest, size_t size_bytes) {
227 size_t result = 0;
228 if (i2s_channel_read(rx_chan, dest, size_bytes, &result,
229 ticks_to_wait_read) != ESP_OK) {
230 TRACEE();
231 }
232 return result;
233 }
234
241
242 protected:
244 i2s_std_config_t i2s_config;
245 i2s_chan_handle_t tx_chan = nullptr; // I2S tx channel handler
246 i2s_chan_handle_t rx_chan = nullptr; // I2S rx channel handler
247 bool is_started = false;
250
251 // Real TX DMA backlog tracking for availableForWrite() -- see
252 // DriverI2S::startChannels() for where onSentCb gets registered, and
253 // newChannels() for where dma_capacity_ is computed from the actual
254 // dma_desc_num/dma_frame_num ESP-IDF ends up allocating.
255 std::atomic<uint32_t> bytes_written_{0};
256 std::atomic<uint32_t> bytes_sent_{0};
257 uint32_t dma_capacity_ = 0;
258
262 static IRAM_ATTR bool onSentCb(i2s_chan_handle_t handle, i2s_event_data_t *event,
263 void *user_ctx) {
264 auto *self = static_cast<I2SDriverESP32V1 *>(user_ctx);
265 self->bytes_sent_.fetch_add((uint32_t)event->size,
266 std::memory_order_relaxed);
267 return false; // no higher-priority task to wake
268 }
269
272 i2s_chan_handle_t &tx_chan,
273 i2s_chan_handle_t &rx_chan, int txPin,
274 int rxPin, I2SDriverESP32V1 *self) = 0;
275
276 virtual i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) = 0;
277 // changes the sample rate
279 i2s_chan_handle_t &tx_chan,
280 i2s_chan_handle_t &rx_chan) {
281 return false;
282 }
283
284 protected:
286 int get_bits_eff(int bits) { return (bits == 24) ? 32 : bits; }
287 };
288
289 struct DriverI2S : public DriverCommon {
290 bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
291 i2s_chan_handle_t &rx_chan, int txPin, int rxPin,
292 I2SDriverESP32V1 *self) {
293 TRACED();
294 LOGI("tx: %d, rx: %d", txPin, rxPin);
295 i2s_std_config_t std_cfg;
296 std_cfg.clk_cfg = getClockConfig(cfg);
297 std_cfg.slot_cfg = getSlotConfig(cfg);
298 std_cfg.gpio_cfg = {
299 .mclk = (gpio_num_t)cfg.pin_mck,
300 .bclk = (gpio_num_t)cfg.pin_bck,
301 .ws = (gpio_num_t)cfg.pin_ws,
302 .dout = (gpio_num_t)txPin,
303 .din = (gpio_num_t)rxPin,
304 .invert_flags =
305 {
306 .mclk_inv = false,
307 .bclk_inv = false,
308 .ws_inv = false,
309 },
310 };
311
312
314 if (i2s_channel_init_std_mode(tx_chan, &std_cfg) != ESP_OK) {
315 LOGE("i2s_channel_init_std_mode %s", "tx");
316 return false;
317 }
318 // Must register while the channel is REGISTERED/READY, i.e. before
319 // i2s_channel_enable() below transitions it to RUNNING.
320 i2s_event_callbacks_t cbs = {};
321 cbs.on_sent = &I2SDriverESP32V1::onSentCb;
322 if (i2s_channel_register_event_callback(tx_chan, &cbs, self) != ESP_OK) {
323 LOGE("i2s_channel_register_event_callback %s", "tx");
324 } else {
325 // Real DMA capacity for availableForWrite(): read back the
326 // dma_desc_num/dma_frame_num ESP-IDF actually allocated (from the
327 // same getChannelConfig() computation newChannels() used to call
328 // i2s_new_channel()) rather than assuming
329 // cfg.buffer_size * cfg.buffer_count -- getChannelConfig() doesn't
330 // always set dma_desc_num explicitly, in which case it falls back
331 // to the I2S_CHANNEL_DEFAULT_CONFIG macro default (6).
332 i2s_chan_config_t chan_cfg = getChannelConfig(cfg);
333 int frame_size =
334 ((cfg.bits_per_sample == 24) ? 32 : cfg.bits_per_sample) *
335 cfg.channels / 8;
336 if (frame_size <= 0) frame_size = 1;
337 self->dma_capacity_ = (uint32_t)chan_cfg.dma_desc_num *
338 chan_cfg.dma_frame_num * frame_size;
339 self->bytes_written_ = 0;
340 self->bytes_sent_ = 0;
341 }
342 if (i2s_channel_enable(tx_chan) != ESP_OK) {
343 LOGE("i2s_channel_enable %s", "tx");
344 return false;
345 }
346 }
347
349 if (i2s_channel_init_std_mode(rx_chan, &std_cfg) != ESP_OK) {
350 LOGE("i2s_channel_init_std_mode %s", "rx");
351 return false;
352 }
353 if (i2s_channel_enable(rx_chan) != ESP_OK) {
354 LOGE("i2s_channel_enable %s", "rx");
355 return false;
356 }
357 }
358
359 LOGD("%s - %s", __func__, "started");
360 return true;
361 }
362
363 protected:
364 i2s_std_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg) {
365 TRACED();
366 i2s_std_slot_config_t result;
367 switch (cfg.i2s_format) {
369 case I2S_MSB_FORMAT:
370 result = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(
371 (i2s_data_bit_width_t)cfg.bits_per_sample,
372 (i2s_slot_mode_t)cfg.channels);
373 break;
374 case I2S_PCM:
375 result = I2S_STD_PCM_SLOT_DEFAULT_CONFIG(
376 (i2s_data_bit_width_t)cfg.bits_per_sample,
377 (i2s_slot_mode_t)cfg.channels);
378 break;
379 default:
380 result = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(
381 (i2s_data_bit_width_t)cfg.bits_per_sample,
382 (i2s_slot_mode_t)cfg.channels);
383 }
384
385 // Update slot_mask if only one channel
386 if (cfg.channels == 1) {
387 switch (cfg.channel_format) {
389 result.slot_mask = I2S_STD_SLOT_LEFT;
390 break;
392 result.slot_mask = I2S_STD_SLOT_RIGHT;
393 break;
394 default:
395 LOGW("Using channel_format: I2SChannelSelect::Left for mono");
396 result.slot_mask = I2S_STD_SLOT_LEFT;
397 break;
398 }
399 }
400
401 return result;
402 }
403
405 TRACED();
406 i2s_chan_config_t result = I2S_CHANNEL_DEFAULT_CONFIG_SAFE(
408 cfg.is_master ? I2S_ROLE_MASTER : I2S_ROLE_SLAVE);
409 // use the legicy size parameters for frame num
410 int size = cfg.buffer_size * cfg.buffer_count;
411 int frame_size = get_bits_eff(cfg.bits_per_sample) * cfg.channels / 8;
412 frame_size = (frame_size == 0) ? 1 : frame_size;
413 if (size > 0) result.dma_frame_num = size / frame_size;
414 if (result.dma_frame_num == 0) result.dma_frame_num = 1;
415 LOGI("frame_size: %d", (int)frame_size);
416 LOGI("dma_frame_num: %d", (int)result.dma_frame_num);
417 LOGI("total buffer size: %d", (int)(result.dma_frame_num * frame_size));
418 result.auto_clear = cfg.auto_clear;
419 return result;
420 }
421
422 i2s_std_clk_config_t getClockConfig(I2SConfigESP32V1 &cfg) {
423 TRACED();
424 i2s_std_clk_config_t clk_cfg;// = I2S_STD_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
425 memset(&clk_cfg, 0, sizeof(i2s_std_clk_config_t));
426 clk_cfg.sample_rate_hz = cfg.sample_rate;
427 clk_cfg.clk_src = getClockSource(cfg);
428 // clk_cfg.ext_clk_freq_hz = 0;
429
430 if (cfg.mclk_multiple > 0) {
431 clk_cfg.mclk_multiple = (i2s_mclk_multiple_t)cfg.mclk_multiple;
432 LOGI("mclk_multiple=%d", clk_cfg.mclk_multiple);
433 } else {
434 if (cfg.bits_per_sample == 24) {
435 // mclk_multiple' should be the multiple of 3 while using 24-bit
436 // using the apll seems to double the frequency
437 clk_cfg.mclk_multiple = cfg.use_apll ? I2S_MCLK_MULTIPLE_192: I2S_MCLK_MULTIPLE_384;
438 LOGI("mclk_multiple=384");
439 } else {
440 // when use_appll is true, the multiple of 128 gives 256kHz
441 // using the apll seems to double the frequency
442 clk_cfg.mclk_multiple = cfg.use_apll ? I2S_MCLK_MULTIPLE_128 : I2S_MCLK_MULTIPLE_256;
443 LOGI("mclk_multiple=%d", clk_cfg.mclk_multiple);
444 }
445 }
446
447 return clk_cfg;
448 }
449
451 soc_periph_i2s_clk_src_t getClockSource(I2SConfigESP32V1 &cfg){
452 soc_periph_i2s_clk_src_t result = I2S_CLK_SRC_DEFAULT;
453 // use mclk pin as input in slave mode if supported
454 if (cfg.pin_mck != -1 && !cfg.is_master) {
455#if SOC_I2S_HW_VERSION_2
456 LOGI("pin_mclk is input");
457 result = I2S_CLK_SRC_EXTERNAL;
458 return result;
459#else
460 LOGE("pin_mclk as input not supported");
461#endif
462 }
463
464 // select APLL clock if possible
465 if (cfg.use_apll) {
466 // select clock source
467#if SOC_I2S_SUPPORTS_APLL
468 result = I2S_CLK_SRC_APLL;
469 LOGI("clk_src is I2S_CLK_SRC_APLL");
470#elif SOC_I2S_SUPPORTS_PLL_F160M
471 result = I2S_CLK_SRC_PLL_160M;
472 LOGI("clk_src is I2S_CLK_SRC_PLL_160M");
473#endif
474 }
475
476 return result;
477 }
478
479 bool changeSampleRate(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
480 i2s_chan_handle_t &rx_chan) override {
481 bool rc = false;
482 auto clock_cfg = getClockConfig(cfg);
483 if (tx_chan != nullptr) {
484 i2s_channel_disable(tx_chan);
485 rc = i2s_channel_reconfig_std_clock(tx_chan, &clock_cfg) == ESP_OK;
486 i2s_channel_enable(tx_chan);
487 }
488 if (rx_chan != nullptr) {
489 i2s_channel_disable(rx_chan);
490 rc = i2s_channel_reconfig_std_clock(rx_chan, &clock_cfg) == ESP_OK;
491 i2s_channel_enable(rx_chan);
492 }
493 return rc;
494 }
495
497
498#ifdef USE_PDM
499
500 struct DriverPDM : public DriverCommon {
501 bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
502 i2s_chan_handle_t &rx_chan, int txPin, int rxPin,
503 I2SDriverESP32V1 * /*self*/) {
504 if (cfg.rx_tx_mode == TX_MODE) {
505 return startTX(cfg, tx_chan, txPin);
506 } else if (cfg.rx_tx_mode == RX_MODE) {
507 return startRX(cfg, rx_chan, rxPin);
508 }
509 LOGE("Only RX and TX is supported for PDM")
510 return false;
511 }
512
513 protected:
514 i2s_pdm_tx_slot_config_t getTxSlotConfig(I2SConfigESP32V1 &cfg) {
515#ifdef SOC_I2S_HW_VERSION_2
516 return I2S_PDM_TX_SLOT_DAC_DEFAULT_CONFIG(
517 (i2s_data_bit_width_t)cfg.bits_per_sample,
518 (i2s_slot_mode_t)cfg.channels);
519#else
520 return I2S_PDM_TX_SLOT_DEFAULT_CONFIG(
521 (i2s_data_bit_width_t)cfg.bits_per_sample,
522 (i2s_slot_mode_t)cfg.channels);
523#endif
524 }
525
526 i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) {
528 (i2s_port_t)cfg.port_no,
529 cfg.is_master ? I2S_ROLE_MASTER : I2S_ROLE_SLAVE);
530 }
531
532 i2s_pdm_tx_clk_config_t getTxClockConfig(I2SConfigESP32V1 &cfg) {
533#if defined(I2S_PDM_TX_CLK_DAC_DEFAULT_CONFIG)
534 return I2S_PDM_TX_CLK_DAC_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
535#else
536 return I2S_PDM_TX_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
537#endif
538 }
539
540 bool startTX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, int txPin) {
541 i2s_pdm_tx_config_t pdm_tx_cfg = {
542 .clk_cfg = getTxClockConfig(cfg),
543 .slot_cfg = getTxSlotConfig(cfg),
544 .gpio_cfg =
545 {
546 .clk = (gpio_num_t)cfg.pin_bck,
547 .dout = (gpio_num_t)txPin,
548#if SOC_I2S_PDM_MAX_TX_LINES > 1
549 .dout2 = I2S_GPIO_UNUSED, // required in IDF v6+
550#endif
551 .invert_flags =
552 {
553 .clk_inv = false,
554 },
555 },
556 };
557
558 if (i2s_channel_init_pdm_tx_mode(tx_chan, &pdm_tx_cfg) != ESP_OK) {
559 LOGE("i2s_channel_init_pdm_tx_mode %s", "tx");
560 return false;
561 }
562 if (i2s_channel_enable(tx_chan) != ESP_OK) {
563 LOGE("i2s_channel_enable %s", "tx");
564 return false;
565 }
566 return true;
567 }
568
569#if defined(USE_PDM_RX)
570 i2s_pdm_rx_slot_config_t getRxSlotConfig(I2SConfigESP32V1 &cfg) {
571 return I2S_PDM_RX_SLOT_DEFAULT_CONFIG(
572 (i2s_data_bit_width_t)cfg.bits_per_sample,
573 (i2s_slot_mode_t)cfg.channels);
574 }
575 i2s_pdm_rx_clk_config_t getRxClockConfig(I2SConfigESP32V1 &cfg) {
576 return I2S_PDM_RX_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
577 }
578 bool startRX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &rx_chan, int rxPin) {
579 i2s_pdm_rx_config_t pdm_rx_cfg = {
580 .clk_cfg = getRxClockConfig(cfg),
581 .slot_cfg = getRxSlotConfig(cfg),
582 .gpio_cfg =
583 {
584 .clk = (gpio_num_t)cfg.pin_bck,
585 .din = (gpio_num_t)rxPin,
586 .invert_flags =
587 {
588 .clk_inv = false,
589 },
590 },
591 };
592
593 if (i2s_channel_init_pdm_rx_mode(rx_chan, &pdm_rx_cfg) != ESP_OK) {
594 LOGE("i2s_channel_init_pdm_rx_mode %s", "rx");
595 return false;
596 }
597 if (i2s_channel_enable(rx_chan) != ESP_OK) {
598 LOGE("i2s_channel_enable %s", "tx");
599 return false;
600 }
601 return true;
602 }
603#else
604 bool startRX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &rx_chan, int rxPin) {
605 LOGE("PDM RX not supported");
606 return false;
607 }
608#endif
609 } pdm;
610
611#endif
612
613#ifdef USE_TDM
614 // example at
615 // https://github.com/espressif/esp-idf/blob/v5.3-dev/examples/peripherals/i2s/i2s_basic/i2s_tdm/main/i2s_tdm_example_main.c
616 struct DriverTDM : public DriverCommon {
617 bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
618 i2s_chan_handle_t &rx_chan, int txPin, int rxPin,
619 I2SDriverESP32V1 * /*self*/) {
620 i2s_tdm_config_t tdm_cfg = {
621 .clk_cfg = getClockConfig(cfg),
622 .slot_cfg = getSlotConfig(cfg),
623 .gpio_cfg =
624 {
625 .mclk = (gpio_num_t)cfg.pin_mck,
626 .bclk = (gpio_num_t)cfg.pin_bck,
627 .ws = (gpio_num_t)cfg.pin_ws,
628 .dout = (gpio_num_t)txPin,
629 .din = (gpio_num_t)rxPin,
630 .invert_flags =
631 {
632 .mclk_inv = false,
633 .bclk_inv = false,
634 .ws_inv = false,
635 },
636 },
637 };
638
639 if (cfg.rx_tx_mode == TX_MODE || cfg.rx_tx_mode == RXTX_MODE) {
640 if (i2s_channel_init_tdm_mode(tx_chan, &tdm_cfg) != ESP_OK) {
641 LOGE("i2s_channel_init_tdm_tx_mode %s", "tx");
642 return false;
643 }
644 }
645 if (cfg.rx_tx_mode == RX_MODE || cfg.rx_tx_mode == RXTX_MODE) {
646 if (i2s_channel_init_tdm_mode(rx_chan, &tdm_cfg) != ESP_OK) {
647 LOGE("i2s_channel_init_tdm_tx_mode %s", "rx");
648 return false;
649 }
650 }
651 return true;
652 }
653
654 protected:
655 i2s_tdm_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg) {
656 int slots = 0;
657 for (int j = 0; j < cfg.channels; j++) {
658 slots |= 1 << j;
659 }
660 // setup default format
661 i2s_tdm_slot_config_t slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(
662 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
663 (i2s_tdm_slot_mask_t)slots);
664
665 switch (cfg.i2s_format) {
667 case I2S_LSB_FORMAT:
669 case I2S_STD_FORMAT:
670 slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(
671 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
672 (i2s_tdm_slot_mask_t)slots);
673 break;
675 case I2S_MSB_FORMAT:
676 slot_cfg = I2S_TDM_MSB_SLOT_DEFAULT_CONFIG(
677 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
678 (i2s_tdm_slot_mask_t)slots);
679 break;
680 case I2S_PCM:
681 slot_cfg = I2S_TDM_PCM_LONG_SLOT_DEFAULT_CONFIG(
682 (i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
683 (i2s_tdm_slot_mask_t)slots);
684 break;
685 default:
686 LOGE("TDM: Unsupported format");
687 }
688
689 return slot_cfg;
690 }
691
692 i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) {
694 (i2s_port_t)cfg.port_no,
695 cfg.is_master ? I2S_ROLE_MASTER : I2S_ROLE_SLAVE);
696 }
697
698 i2s_tdm_clk_config_t getClockConfig(I2SConfigESP32V1 &cfg) {
699 return I2S_TDM_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
700 }
701
702 } tdm;
703
704#endif
705
707
709 bool begin(I2SConfigESP32V1 cfg, int txPin, int rxPin) {
710 TRACED();
711 cfg.logInfo();
712 this->cfg = cfg;
713 if (cfg.channels <= 0 || cfg.channels > 2) {
714 LOGE("invalid channels: %d", cfg.channels);
715 return false;
716 }
717
718 DriverCommon &driver = getDriver(cfg);
719 if (!newChannels(cfg, driver)) {
720 end();
721 return false;
722 }
723
724 is_started = driver.startChannels(cfg, tx_chan, rx_chan, txPin, rxPin, this);
725 if (!is_started) {
726 end();
727 LOGE("Channels not started");
728 }
729 return is_started;
730 }
731
733 i2s_chan_config_t chan_cfg = driver.getChannelConfig(cfg);
734 // dma_capacity_/counters are only set up in DriverI2S::startChannels()
735 // (the only driver that registers the on_sent callback crediting
736 // bytes_sent_ back) -- leave them at 0 here for PDM/TDM so
737 // availableForWrite() keeps using the old constant fallback for those.
738 switch (cfg.rx_tx_mode) {
739 case RX_MODE:
740 if (i2s_new_channel(&chan_cfg, NULL, &rx_chan) != ESP_OK) {
741 LOGE("i2s_channel");
742 return false;
743 }
744 break;
745 case TX_MODE:
746 if (i2s_new_channel(&chan_cfg, &tx_chan, NULL) != ESP_OK) {
747 LOGE("i2s_channel");
748 return false;
749 }
750 break;
751 default:
752 if (i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan) != ESP_OK) {
753 LOGE("i2s_channel");
754 return false;
755 }
756 }
757 return true;
758 }
759
761 switch (cfg.signal_type) {
762 case Digital:
763 return i2s;
764#ifdef USE_PDM
765 case Analog:
766 case PDM:
767 return pdm;
768#endif
769#ifdef USE_TDM
770 case TDM:
771 return tdm;
772#endif
773 default:
774 break;
775 }
776 LOGE("Unsupported signal_type");
777 return i2s;
778 }
779};
780
781using I2SDriver = I2SDriverESP32V1;
782
783} // namespace audio_tools
784
785#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 portMAX_DELAY
Definition BufferBlocking.h:14
#define pdMS_TO_TICKS(ms)
Definition BufferBlocking.h:17
uint32_t TickType_t
Definition BufferBlocking.h:11
#define I2S_CHANNEL_DEFAULT_CONFIG_SAFE(port, role)
Definition I2SDriverESP32V1.h:77
#define I2S_MCLK_MULTIPLE_192
Definition I2SDriverESP32V1.h:25
#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:90
void flush() override
Definition I2SDriverESP32V1.h:201
std::atomic< uint32_t > bytes_written_
Definition I2SDriverESP32V1.h:255
I2SConfigESP32V1 defaultConfig(RxTxMode mode)
Provides the default configuration.
Definition I2SDriverESP32V1.h:93
void setWaitTimeWriteMs(TickType_t ms)
Definition I2SDriverESP32V1.h:238
bool begin(I2SConfigESP32V1 cfg)
starts the DAC
Definition I2SDriverESP32V1.h:121
i2s_chan_handle_t rx_chan
Definition I2SDriverESP32V1.h:246
TickType_t ticks_to_wait_read
Definition I2SDriverESP32V1.h:248
audio_tools::I2SDriverESP32V1::DriverI2S i2s
void setWaitTimeReadMs(TickType_t ms)
Definition I2SDriverESP32V1.h:235
int available()
we assume the data is already available in the buffer
Definition I2SDriverESP32V1.h:144
bool is_started
Definition I2SDriverESP32V1.h:247
bool begin()
Definition I2SDriverESP32V1.h:118
bool setAudioInfo(AudioInfo info)
Potentially updates the sample rate (if supported)
Definition I2SDriverESP32V1.h:98
std::atomic< uint32_t > bytes_sent_
Definition I2SDriverESP32V1.h:256
i2s_chan_handle_t tx_chan
Definition I2SDriverESP32V1.h:245
bool newChannels(I2SConfigESP32V1 &cfg, DriverCommon &driver)
Definition I2SDriverESP32V1.h:732
int availableForWrite()
Definition I2SDriverESP32V1.h:151
I2SConfigESP32V1 config()
provides the actual configuration
Definition I2SDriverESP32V1.h:211
uint32_t dma_capacity_
Definition I2SDriverESP32V1.h:257
DriverCommon & getDriver(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:760
static IRAM_ATTR bool onSentCb(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
Definition I2SDriverESP32V1.h:262
void end()
stops the I2C and unistalls the driver
Definition I2SDriverESP32V1.h:171
bool begin(RxTxMode mode)
starts the DAC with the default config
Definition I2SDriverESP32V1.h:114
bool begin(I2SConfigESP32V1 cfg, int txPin, int rxPin)
-> protected methods from I2SDriverESP32V1
Definition I2SDriverESP32V1.h:709
TickType_t ticks_to_wait_write
Definition I2SDriverESP32V1.h:249
size_t writeBytes(const void *src, size_t size_bytes)
writes the data to the I2S interface
Definition I2SDriverESP32V1.h:214
I2SConfigESP32V1 cfg
Definition I2SDriverESP32V1.h:243
i2s_std_config_t i2s_config
Definition I2SDriverESP32V1.h:244
size_t readBytes(void *dest, size_t size_bytes)
Definition I2SDriverESP32V1.h:226
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:444
@ PDM
Definition AudioTypes.h:446
@ TDM
Definition AudioTypes.h:447
@ Analog
Definition AudioTypes.h:445
@ I2S_STD_FORMAT
Definition AudioTypes.h:423
@ I2S_PHILIPS_FORMAT
Definition AudioTypes.h:426
@ I2S_LSB_FORMAT
Definition AudioTypes.h:424
@ I2S_LEFT_JUSTIFIED_FORMAT
Definition AudioTypes.h:428
@ I2S_RIGHT_JUSTIFIED_FORMAT
Definition AudioTypes.h:427
@ I2S_MSB_FORMAT
Definition AudioTypes.h:425
@ I2S_PCM
Definition AudioTypes.h:429
int i2s_port_t
Definition I2SDriverESP32V1.h:20
I2SDriverESP32 I2SDriver
Definition I2SDriverESP32.h:418
static i2s_chan_config_t getDefaultChannelConfig(i2s_port_t port, i2s_role_t role)
Definition I2SDriverESP32V1.h:56
Definition InitializerList.h:7
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:56
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:58
bool equals(AudioInfo alt)
Returns true if alt values are the same like the current values.
Definition AudioTypes.h:88
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:60
bool equalsExSampleRate(AudioInfo alt)
Checks if only the sample rate is different.
Definition AudioTypes.h:91
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:62
Definition I2SDriverESP32V1.h:270
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:286
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:278
Definition I2SDriverESP32V1.h:289
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:290
i2s_std_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:364
i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:404
i2s_std_clk_config_t getClockConfig(I2SConfigESP32V1 &cfg)
Definition I2SDriverESP32V1.h:422
bool changeSampleRate(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, i2s_chan_handle_t &rx_chan) override
Definition I2SDriverESP32V1.h:479
soc_periph_i2s_clk_src_t getClockSource(I2SConfigESP32V1 &cfg)
select clock source dependent on is_master and use_apll
Definition I2SDriverESP32V1.h:451
Definition I2SDriverESP32V1.h:46
Definition I2SDriverESP32V1.h:40