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