arduino-audio-tools
Loading...
Searching...
No Matches
I2SDriverESP32.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
9
10#include "driver/i2s.h"
11#include "esp_system.h"
12
13#ifndef I2S_MCLK_MULTIPLE_DEFAULT
14# define I2S_MCLK_MULTIPLE_DEFAULT ((i2s_mclk_multiple_t)0)
15#endif
16
17#define IS_I2S_IMPLEMENTED
18
19namespace audio_tools {
20
29 friend class AnalogAudio;
30 friend class AudioKitStream;
31
32 public:
35 I2SConfigESP32 c(mode);
36 return c;
37 }
38
41 // nothing to do
42 if (is_started) {
43 if (info.equals(cfg)) return true;
44 if (info.equalsExSampleRate(cfg)) {
46 LOGI("i2s_set_sample_rates: %d", info.sample_rate);
47 return i2s_set_sample_rates((i2s_port_t)cfg.port_no, cfg.sample_rate) == ESP_OK;
48 }
49 } else {
50 LOGE("not started");
51 }
52 return false;
53 }
54
56 bool begin(RxTxMode mode) { return begin(defaultConfig(mode)); }
57
60 bool begin() { return !is_started ? begin(cfg) : true; }
61
64 TRACED();
65 this->cfg = cfg;
66 switch (cfg.rx_tx_mode) {
67 case TX_MODE:
68 return begin(cfg, cfg.pin_data, I2S_PIN_NO_CHANGE);
69 case RX_MODE:
70 // usually we expet cfg.pin_data but if the used assinged rx we might
71 // consider this one
72 return begin(
73 cfg, I2S_PIN_NO_CHANGE,
74 cfg.pin_data != I2S_PIN_NO_CHANGE ? cfg.pin_data : cfg.pin_data_rx);
75 default:
77 }
78 LOGE("Did not expect go get here");
79 }
80
83
86
88 void end() {
89 TRACED();
90 i2s_driver_uninstall(i2s_num);
91 is_started = false;
92 }
93
102 void flush() override {
103 if (is_started) {
104 LOGD("i2s_zero_dma_buffer");
105 i2s_zero_dma_buffer(i2s_num);
106 }
107 }
108
111
113 size_t writeBytes(const void *src, size_t size_bytes) {
114 TRACED();
115
116 size_t result = 0;
118 if (i2s_write(i2s_num, src, size_bytes, &result, ticks_to_wait_write) !=
119 ESP_OK) {
120 TRACEE();
121 }
122 LOGD("i2s_write %d -> %d bytes", size_bytes, result);
123 } else {
124 result =
126 }
127 return result;
128 }
129
130 size_t readBytes(void *dest, size_t size_bytes) {
131 size_t result = 0;
133 if (i2s_read(i2s_num, dest, size_bytes, &result, ticks_to_wait_read) !=
134 ESP_OK) {
135 TRACEE();
136 }
137 } else if (cfg.channels == 1) {
138 // I2S has always 2 channels. We support to reduce it to 1
139 uint8_t temp[size_bytes * 2];
140 if (i2s_read(i2s_num, temp, size_bytes * 2, &result,
141 ticks_to_wait_read) != ESP_OK) {
142 TRACEE();
143 }
144 // convert to 1 channel
145 switch (cfg.bits_per_sample) {
146 case 16: {
147 ChannelReducerT<int16_t> reducer16(1, 2);
148 result = reducer16.convert((uint8_t *)dest, temp, result);
149 } break;
150 case 24: {
151 ChannelReducerT<int24_t> reducer24(1, 2);
152 result = reducer24.convert((uint8_t *)dest, temp, result);
153 } break;
154 case 32: {
155 ChannelReducerT<int32_t> reducer32(1, 2);
156 result = reducer32.convert((uint8_t *)dest, temp, result);
157 } break;
158 default:
159 LOGE("invalid bits_per_sample: %d", cfg.bits_per_sample);
160 break;
161 }
162 } else {
163 LOGE("Invalid channels: %d", cfg.channels);
164 }
165 return result;
166 }
167
174
175 protected:
178 i2s_config_t i2s_config;
179 bool is_started = false;
182
184 if (cfg.channels == 2) return true;
185 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ALL_RIGHT)
186 return true;
187 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ALL_LEFT)
188 return true;
189 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ONLY_RIGHT)
190 return true;
191 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ONLY_LEFT)
192 return true;
193 return false;
194 }
195
197 bool begin(I2SConfigESP32 cfg, int txPin, int rxPin) {
198 TRACED();
199 cfg.logInfo();
200 this->cfg = cfg;
201 this->i2s_num = (i2s_port_t)cfg.port_no;
203
204 i2s_config_t i2s_config_new = {
205 .mode = toMode(cfg),
206 .sample_rate = (eps32_i2s_sample_rate_type)cfg.sample_rate,
207 .bits_per_sample = (i2s_bits_per_sample_t)cfg.bits_per_sample,
208 .channel_format = (i2s_channel_fmt_t)cfg.channel_format,
209 .communication_format = toCommFormat(cfg.i2s_format),
210 .intr_alloc_flags = 0, // default interrupt priority
211 .dma_buf_count = cfg.buffer_count,
212 .dma_buf_len = cfg.buffer_size,
213 .use_apll = (bool)cfg.use_apll,
214 .tx_desc_auto_clear = cfg.auto_clear,
215#if ESP_IDF_VERSION_MAJOR >= 4
216 .fixed_mclk = (int)(cfg.fixed_mclk > 0 ? cfg.fixed_mclk : 0),
217 .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT,
218 .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
219#endif
220 };
221 i2s_config = i2s_config_new;
222
223 // We make sure that we can reconfigure
224 if (is_started) {
225 end();
226 LOGD("%s", "I2S restarting");
227 }
228
229 // setup config
230 LOGD("i2s_driver_install");
231 if (i2s_driver_install(i2s_num, &i2s_config, 0, NULL) != ESP_OK) {
232 LOGE("%s - %s", __func__, "i2s_driver_install");
233 }
234
235 // setup pin config
236 if (this->cfg.signal_type == Digital || this->cfg.signal_type == PDM) {
237 i2s_pin_config_t pin_config = {
238#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 4, 0)
239 .mck_io_num = cfg.pin_mck,
240#endif
241 .bck_io_num = cfg.pin_bck,
242 .ws_io_num = cfg.pin_ws,
243 .data_out_num = txPin,
244 .data_in_num = rxPin};
245
246 LOGD("i2s_set_pin");
247 if (i2s_set_pin(i2s_num, &pin_config) != ESP_OK) {
248 LOGE("%s - %s", __func__, "i2s_set_pin");
249 }
250 } else {
251 LOGD("Using built in DAC");
252 // for internal DAC, this will enable both of the internal channels
253 i2s_set_pin(i2s_num, NULL);
254 }
255
256 // clear initial buffer
257 LOGD("i2s_zero_dma_buffer");
258 i2s_zero_dma_buffer(i2s_num);
259
260 is_started = true;
261 LOGD("%s - %s", __func__, "started");
262 return true;
263 }
264
265 // update the cfg.i2s.channel_format based on the number of channels
266 void setChannels(int channels) { cfg.channels = channels; }
267
269 size_t writeExpandChannel(i2s_port_t i2s_num, const int bits_per_sample,
270 const void *src, size_t size_bytes) {
271 size_t result = 0;
272 int j;
273 switch (bits_per_sample) {
274 case 8:
275 for (j = 0; j < size_bytes; j++) {
276 int8_t frame[2];
277 int8_t *data = (int8_t *)src;
278 frame[0] = data[j];
279 frame[1] = data[j];
280 size_t result_call = 0;
281 if (i2s_write(i2s_num, frame, sizeof(int8_t) * 2, &result_call,
282 ticks_to_wait_write) != ESP_OK) {
283 TRACEE();
284 } else {
285 result += result_call;
286 }
287 }
288 break;
289
290 case 16:
291 for (j = 0; j < size_bytes / 2; j++) {
292 int16_t frame[2];
293 int16_t *data = (int16_t *)src;
294 frame[0] = data[j];
295 frame[1] = data[j];
296 size_t result_call = 0;
297 if (i2s_write(i2s_num, frame, sizeof(int16_t) * 2, &result_call,
298 ticks_to_wait_write) != ESP_OK) {
299 TRACEE();
300 } else {
301 result += result_call;
302 }
303 }
304 break;
305
306 case 24:
307 for (j = 0; j < size_bytes / 4; j++) {
308 int24_t frame[2];
309 int24_t *data = (int24_t *)src;
310 frame[0] = data[j];
311 frame[1] = data[j];
312 size_t result_call = 0;
313 if (i2s_write(i2s_num, frame, sizeof(int24_t) * 2, &result_call,
314 ticks_to_wait_write) != ESP_OK) {
315 TRACEE();
316 } else {
317 result += result_call;
318 }
319 }
320 break;
321
322 case 32:
323 for (j = 0; j < size_bytes / 4; j++) {
324 int32_t frame[2];
325 int32_t *data = (int32_t *)src;
326 frame[0] = data[j];
327 frame[1] = data[j];
328 size_t result_call = 0;
329 if (i2s_write(i2s_num, frame, sizeof(int32_t) * 2, &result_call,
330 ticks_to_wait_write) != ESP_OK) {
331 TRACEE();
332 } else {
333 result += result_call;
334 }
335 }
336 break;
337 }
338 return size_bytes;
339 }
340
341#pragma GCC diagnostic push
342#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
343
344 // determines the i2s_comm_format_t - by default we use
345 // I2S_COMM_FORMAT_STAND_I2S
346 i2s_comm_format_t toCommFormat(I2SFormat mode) {
347 switch (mode) {
349 case I2S_STD_FORMAT:
350 return (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S;
352 case I2S_MSB_FORMAT:
353 return (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S |
354 I2S_COMM_FORMAT_I2S_MSB);
356 case I2S_LSB_FORMAT:
357 return (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S |
358 I2S_COMM_FORMAT_I2S_LSB);
359 case I2S_PCM:
360 return (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_PCM_SHORT;
361
362 default:
363 LOGE("unsupported mode");
364 return (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S;
365 }
366 }
367#pragma GCC diagnostic pop
368
370 int i2s_format = cfg.is_master ? I2S_MODE_MASTER : I2S_MODE_SLAVE;
371 int i2s_rx_tx = 0;
372 switch (cfg.rx_tx_mode) {
373 case TX_MODE:
374 i2s_rx_tx = I2S_MODE_TX;
375 break;
376 case RX_MODE:
377 i2s_rx_tx = I2S_MODE_RX;
378 break;
379 case RXTX_MODE:
380 i2s_rx_tx = I2S_MODE_RX | I2S_MODE_TX;
381 break;
382 default:
383 LOGE("Undefined rx_tx_mode: %d", cfg.rx_tx_mode);
384 }
385 return (i2s_format | i2s_rx_tx);
386 }
387
388 // determines the i2s_format_t
389 i2s_mode_t toMode(I2SConfigESP32 &cfg) {
390 i2s_mode_t mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX);
391 switch (cfg.signal_type) {
392 case Digital:
393 mode = (i2s_mode_t)getModeDigital(cfg);
394 break;
395
396 case PDM:
397 mode = (i2s_mode_t)(getModeDigital(cfg) | I2S_MODE_PDM);
398 break;
399
400 case Analog:
401#if defined(USE_ANALOG)
402 mode = (i2s_mode_t)(cfg.rx_tx_mode ? I2S_MODE_DAC_BUILT_IN
403 : I2S_MODE_ADC_BUILT_IN);
404#else
405 LOGE("mode not supported");
406#endif
407 break;
408
409 default:
410 LOGW("signal_type undefined");
411 mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
412 break;
413 }
414 return mode;
415 }
416};
417
419
420} // namespace audio_tools
421
422#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 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_MCLK_MULTIPLE_DEFAULT
Definition I2SDriverESP32.h:14
AudioKit Stream which uses the https://github.com/pschatzmann/arduino-audiokit library.
Definition AudioKit.h:189
We combine a datastream which consists of multiple channels into less channels. E....
Definition BaseConverter.h:474
size_t convert(uint8_t *src, size_t size)
Definition BaseConverter.h:491
Configuration for ESP32 legacy i2s.
Definition I2SConfigESP32.h:24
int buffer_count
Definition I2SConfigESP32.h:70
int pin_mck
Definition I2SConfigESP32.h:69
RxTxMode rx_tx_mode
public settings
Definition I2SConfigESP32.h:60
int pin_ws
Definition I2SConfigESP32.h:65
bool auto_clear
Definition I2SConfigESP32.h:72
I2SSignalType signal_type
Definition I2SConfigESP32.h:62
int pin_data
Definition I2SConfigESP32.h:67
int pin_data_rx
Definition I2SConfigESP32.h:68
bool use_apll
Definition I2SConfigESP32.h:73
bool is_master
Definition I2SConfigESP32.h:63
int pin_bck
Definition I2SConfigESP32.h:66
int channel_format
Definition I2SConfigESP32.h:75
I2SFormat i2s_format
Definition I2SConfigESP32.h:61
uint32_t fixed_mclk
Definition I2SConfigESP32.h:74
void logInfo(const char *source="")
Definition I2SConfigESP32.h:77
int port_no
Definition I2SConfigESP32.h:64
int buffer_size
Definition I2SConfigESP32.h:71
Definition I2SDriverBase.h:7
Basic I2S API - for the ESP32. If we receive 1 channel, we expand the result to 2 channels.
Definition I2SDriverESP32.h:28
friend class AnalogAudio
Definition I2SDriverESP32.h:29
void flush() override
Definition I2SDriverESP32.h:102
bool isNoChannelConversion(I2SConfigESP32 cfg)
Definition I2SDriverESP32.h:183
i2s_port_t i2s_num
Definition I2SDriverESP32.h:177
void setWaitTimeWriteMs(TickType_t ms)
Definition I2SDriverESP32.h:171
bool begin(I2SConfigESP32 cfg)
starts the DAC
Definition I2SDriverESP32.h:63
I2SConfigESP32 cfg
Definition I2SDriverESP32.h:176
TickType_t ticks_to_wait_read
Definition I2SDriverESP32.h:180
void setWaitTimeReadMs(TickType_t ms)
Definition I2SDriverESP32.h:168
int available()
we assume the data is already available in the buffer
Definition I2SDriverESP32.h:82
bool is_started
Definition I2SDriverESP32.h:179
bool begin()
Definition I2SDriverESP32.h:60
bool setAudioInfo(AudioInfo info)
Potentially updates the sample rate (if supported)
Definition I2SDriverESP32.h:40
size_t writeExpandChannel(i2s_port_t i2s_num, const int bits_per_sample, const void *src, size_t size_bytes)
writes the data by making sure that we send 2 channels
Definition I2SDriverESP32.h:269
int availableForWrite()
We limit the write size to the buffer size.
Definition I2SDriverESP32.h:85
I2SConfigESP32 config()
provides the actual configuration
Definition I2SDriverESP32.h:110
i2s_config_t i2s_config
Definition I2SDriverESP32.h:178
i2s_comm_format_t toCommFormat(I2SFormat mode)
Definition I2SDriverESP32.h:346
void end()
stops the I2C and unistalls the driver
Definition I2SDriverESP32.h:88
void setChannels(int channels)
Definition I2SDriverESP32.h:266
bool begin(RxTxMode mode)
starts the DAC with the default config
Definition I2SDriverESP32.h:56
I2SConfigESP32 defaultConfig(RxTxMode mode)
Provides the default configuration.
Definition I2SDriverESP32.h:34
i2s_mode_t toMode(I2SConfigESP32 &cfg)
Definition I2SDriverESP32.h:389
TickType_t ticks_to_wait_write
Definition I2SDriverESP32.h:181
int getModeDigital(I2SConfigESP32 &cfg)
Definition I2SDriverESP32.h:369
size_t writeBytes(const void *src, size_t size_bytes)
writes the data to the I2S interface
Definition I2SDriverESP32.h:113
size_t readBytes(void *dest, size_t size_bytes)
Definition I2SDriverESP32.h:130
bool begin(I2SConfigESP32 cfg, int txPin, int rxPin)
starts the DAC
Definition I2SDriverESP32.h:197
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition int24_4bytes_t.h:22
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
@ Analog
Definition AudioTypes.h:445
I2SFormat
I2S Formats.
Definition AudioTypes.h:422
@ 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
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