10#define IS_I2S_IMPLEMENTED
26class I2SDriverSTM32 :
public I2SDriverBase {
27 friend class I2SStream;
31 I2SConfigStd defaultConfig(RxTxMode mode = TX_MODE) {
37 bool setAudioInfo(AudioInfo) {
return false;}
40 bool begin(RxTxMode mode = TX_MODE) {
42 return begin(defaultConfig(mode));
46 bool begin(I2SConfigStd cfg) {
51 LOGI(
"buffer_size: %d", cfg.buffer_size);
52 LOGI(
"buffer_count: %d", cfg.buffer_count);
54 if (cfg.channels > 2 || cfg.channels <= 0) {
55 LOGE(
"Channels not supported: %d", cfg.channels);
59 setupDefaultI2SParameters();
61 result = use_dma ? startI2SDMA() : startI2S();
62 this->active = result;
76 if (!active)
return 0;
77 if (use_dma && p_rx_buffer ==
nullptr)
return 0;
78 return cfg.buffer_size;
82 int availableForWrite() {
83 if (!active)
return 0;
84 if (use_dma && p_tx_buffer ==
nullptr)
return 0;
85 return cfg.buffer_size;
89 I2SConfigStd config() {
return cfg; }
92 size_t writeBytes(
const void *src,
size_t size_bytes) {
96 result = i2s.write((uint8_t *)src, size_bytes);
99 if (p_dma_in !=
nullptr) {
106 result = writeBytesDMA(src, size_bytes);
112 size_t readBytes(
void *dest,
size_t size_bytes) {
115 return i2s.readBytes((uint8_t *)dest, size_bytes);
117 if (cfg.channels == 2) {
118 return p_rx_buffer->readArray((uint8_t *)dest, size_bytes);
120 return readBytesDMA(dest, size_bytes);
127 static void writeFromReceive(uint8_t *buffer, uint16_t byteCount,
void *ref) {
128 I2SDriverSTM32 *self = (I2SDriverSTM32 *)ref;
132 uint16_t written = 0;
133 if (self->p_dma_out !=
nullptr)
134 written = self->p_dma_out->write(buffer, byteCount);
136 written = self->p_rx_buffer->writeArray(buffer, byteCount);
138 if (written != byteCount) self->rx_overflow_count++;
143 static void readToTransmit(uint8_t *buffer, uint16_t byteCount,
void *ref) {
144 I2SDriverSTM32 *self = (I2SDriverSTM32 *)ref;
149 if (self->p_dma_in !=
nullptr) {
151 if (self->isWriteTimedOut()) {
156 read = self->p_dma_in->readBytes(buffer, byteCount);
160 if (self->stm32_write_active) {
161 read = self->p_tx_buffer->readArray(buffer, byteCount);
164 memset(buffer+read, 0, byteCount-read);
166 if (read != byteCount) self->tx_underflow_count++;
170 bool isWriteTimedOut() {
171 return last_write_ms != 0 && last_write_ms + 500 <
millis();
175 void setDMAActive(
bool flag) { use_dma = flag; }
178 void setDMAInputStream(
Stream &in) {
184 void setDMAOutput(
Print &out) {
190 uint32_t getUnderflowCount() {
return tx_underflow_count; }
193 uint32_t getOverflowCount() {
return rx_overflow_count; }
196 void resetErrorCounters() { tx_underflow_count = 0; rx_overflow_count = 0; }
199 stm32_i2s::Stm32I2sClass i2s;
200 stm32_i2s::I2SSettingsSTM32 i2s_stm32;
204 BaseBuffer<uint8_t> *p_tx_buffer =
nullptr;
205 BaseBuffer<uint8_t> *p_rx_buffer =
nullptr;
206 volatile bool stm32_write_active =
false;
209 volatile uint32_t tx_underflow_count = 0;
210 volatile uint32_t rx_overflow_count = 0;
211 Print *p_dma_out =
nullptr;
212 Stream *p_dma_in =
nullptr;
213 uint32_t last_write_ms = 0;
215 size_t writeBytesDMA(
const void *src,
size_t size_bytes) {
218 const uint8_t *p_src = (
const uint8_t *)src;
219 int open = size_bytes;
221 int actual_written = writeBytesExt(p_src, open);
222 if (actual_written <= 0) {
224 stm32_write_active =
true;
227 p_src += actual_written;
228 result += actual_written;
229 open -= actual_written;
235 if (!stm32_write_active && p_tx_buffer->availableForWrite() == 0) {
236 stm32_write_active =
true;
237 LOGI(
"Buffer is full->starting i2s output");
243 size_t readBytesDMA(
void *dest,
size_t size_bytes) {
245 int req_bytes = size_bytes * 2;
246 uint8_t tmp[req_bytes];
247 int16_t *tmp_16 = (int16_t *)tmp;
248 int eff_bytes = p_rx_buffer->readArray((uint8_t *)tmp, req_bytes);
250 int16_t *dest_16 = (int16_t *)dest;
251 int16_t eff_samples = eff_bytes / 2;
253 for (
int j = 0; j < eff_samples; j += 2) {
254 dest_16[idx++] =
static_cast<float>(tmp_16[j]) + tmp_16[j + 1] / 2.0;
256 return eff_bytes / 2;
260 switch (cfg.rx_tx_mode) {
262 result = i2s.begin(i2s_stm32,
false,
true);
265 result = i2s.begin(i2s_stm32,
true,
false);
269 result = i2s.begin(i2s_stm32,
true,
true);
276 switch (cfg.rx_tx_mode) {
278 if (use_dma && p_rx_buffer ==
nullptr)
279 p_rx_buffer = allocateBuffer();
280 result = i2s.beginReadDMA(i2s_stm32, writeFromReceive);
283 stm32_write_active =
false;
284 if (use_dma && p_tx_buffer ==
nullptr)
285 p_tx_buffer = allocateBuffer();
286 result = i2s.beginWriteDMA(i2s_stm32, readToTransmit);
291 stm32_write_active =
false;
292 if (p_rx_buffer ==
nullptr)
293 p_rx_buffer = allocateBuffer();
294 if (p_tx_buffer ==
nullptr)
295 p_tx_buffer = allocateBuffer();
297 result = i2s.beginReadWriteDMA(
298 i2s_stm32, readToTransmit, writeFromReceive);
302 LOGE(
"Unsupported mode");
308 uint32_t toDataFormat(
int bits_per_sample) {
309 switch (bits_per_sample) {
311 return I2S_DATAFORMAT_16B;
313 return I2S_DATAFORMAT_24B;
315 return I2S_DATAFORMAT_32B;
317 return I2S_DATAFORMAT_16B;
320 void deleteBuffers() {
321 if (p_rx_buffer !=
nullptr) {
323 p_rx_buffer =
nullptr;
325 if (p_tx_buffer !=
nullptr) {
327 p_tx_buffer =
nullptr;
331 void setupDefaultI2SParameters() {
332 i2s_stm32.sample_rate = getSampleRate(cfg);
333 i2s_stm32.data_format = toDataFormat(cfg.bits_per_sample);
334 i2s_stm32.mode = getMode(cfg);
335 i2s_stm32.standard = getStandard(cfg);
336 i2s_stm32.fullduplexmode = cfg.rx_tx_mode ==
RXTX_MODE
337 ? I2S_FULLDUPLEXMODE_ENABLE
338 : I2S_FULLDUPLEXMODE_DISABLE;
339 i2s_stm32.hardware_config.buffer_size = cfg.buffer_size;
341 i2s_stm32.ref =
this;
345 if (cfg.pin_bck == -1 || cfg.pin_ws == -1 || cfg.pin_data == -1) {
346 LOGW(
"pins ignored: used from stm32-i2s");
348 LOGI(
"setting up pins for stm32-i2s");
354 i2s_stm32.hardware_config.pins[0].function = stm32_i2s::mclk;
355 i2s_stm32.hardware_config.pins[0].pin = digitalPinToPinName(cfg.pin_mck);
356 if (cfg.pin_alt_function != -1)
357 i2s_stm32.hardware_config.pins[0].altFunction = cfg.pin_alt_function;
359 i2s_stm32.hardware_config.pins[1].function = stm32_i2s::bck;
360 i2s_stm32.hardware_config.pins[1].pin = digitalPinToPinName(cfg.pin_bck);
361 if (cfg.pin_alt_function != -1)
362 i2s_stm32.hardware_config.pins[1].altFunction = cfg.pin_alt_function;
364 i2s_stm32.hardware_config.pins[2].function = stm32_i2s::ws;
365 i2s_stm32.hardware_config.pins[2].pin = digitalPinToPinName(cfg.pin_ws);
366 if (cfg.pin_alt_function != -1)
367 i2s_stm32.hardware_config.pins[2].altFunction = cfg.pin_alt_function;
369 switch (cfg.rx_tx_mode) {
371 i2s_stm32.hardware_config.pins[3].function = stm32_i2s::data_out;
372 i2s_stm32.hardware_config.pins[3].pin = digitalPinToPinName(cfg.pin_data);
373 if (cfg.pin_alt_function != -1)
374 i2s_stm32.hardware_config.pins[3].altFunction = cfg.pin_alt_function;
377 i2s_stm32.hardware_config.pins[4].function = stm32_i2s::data_in;
378 i2s_stm32.hardware_config.pins[4].pin = digitalPinToPinName(cfg.pin_data);
379 if (cfg.pin_alt_function != -1)
380 i2s_stm32.hardware_config.pins[4].altFunction = cfg.pin_alt_function;
383 i2s_stm32.hardware_config.pins[3].function = stm32_i2s::data_out;
384 i2s_stm32.hardware_config.pins[3].pin = digitalPinToPinName(cfg.pin_data);
385 if (cfg.pin_alt_function != -1)
386 i2s_stm32.hardware_config.pins[3].altFunction = cfg.pin_alt_function;
388 i2s_stm32.hardware_config.pins[4].function = stm32_i2s::data_in;
389 i2s_stm32.hardware_config.pins[4].pin = digitalPinToPinName(cfg.pin_data);
390 if (cfg.pin_alt_function != -1)
391 i2s_stm32.hardware_config.pins[4].altFunction = cfg.pin_alt_function;
398 uint32_t getMode(I2SConfigStd &cfg) {
400 switch (cfg.rx_tx_mode) {
402 return I2S_MODE_MASTER_RX;
404 return I2S_MODE_MASTER_TX;
406 LOGE(
"RXTX_MODE not supported");
407 return I2S_MODE_MASTER_TX;
410 switch (cfg.rx_tx_mode) {
412 return I2S_MODE_SLAVE_RX;
414 return I2S_MODE_SLAVE_TX;
416 LOGE(
"RXTX_MODE not supported");
417 return I2S_MODE_SLAVE_TX;
422 uint32_t getStandard(I2SConfigStd &cfg) {
429 switch (cfg.i2s_format) {
432 return I2S_STANDARD_PHILIPS;
435 return I2S_STANDARD_LSB;
438 return I2S_STANDARD_MSB;
440 return I2S_STANDARD_PHILIPS;
443 uint32_t getSampleRate(I2SConfigStd &cfg) {
444 switch (cfg.sample_rate) {
445 case I2S_AUDIOFREQ_192K:
446 case I2S_AUDIOFREQ_96K:
447 case I2S_AUDIOFREQ_48K:
448 case I2S_AUDIOFREQ_44K:
449 case I2S_AUDIOFREQ_32K:
450 case I2S_AUDIOFREQ_22K:
451 case I2S_AUDIOFREQ_16K:
452 case I2S_AUDIOFREQ_11K:
453 case I2S_AUDIOFREQ_8K:
454 return cfg.sample_rate;
456 LOGE(
"Unsupported sample rate: %u", cfg.sample_rate);
457 return cfg.sample_rate;
461 size_t writeBytesExt(
const void *src,
size_t size_bytes) {
466 if (cfg.channels == 2) {
467 result = p_tx_buffer->writeArray((uint8_t *)src, size_bytes);
470 int samples = size_bytes / 2;
471 int16_t *src_16 = (int16_t *)src;
473 for (
int j = 0; j < samples; j++) {
476 if (p_tx_buffer->availableForWrite() >= 4) {
477 p_tx_buffer->writeArray((uint8_t *)tmp, 4);
478 result = (j + 1) * 2;
485 LOGD(
"writeBytesExt: %u", result)
493 BaseBuffer<uint8_t>* allocateBuffer() {
494 return new RingBufferSPSC<uint8_t>(cfg.buffer_size * cfg.buffer_count);
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
@ RXTX_MODE
Definition AudioTypes.h:26
@ TX_MODE
Definition AudioTypes.h:26
@ RX_MODE
Definition AudioTypes.h:26
constexpr const _Ep * end(initializer_list< _Ep > __il) noexcept
Definition InitializerList.h:63
constexpr const _Ep * begin(initializer_list< _Ep > __il) noexcept
Definition InitializerList.h:55