arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
I2SRP2040.h
1#pragma once
2
3#include "AudioTools/CoreAudio/AudioI2S/I2SConfig.h"
4#if defined(RP2040_HOWER)
5#include <I2S.h>
6
7#define IS_I2S_IMPLEMENTED
8
9namespace audio_tools {
10
18class I2SDriverRP2040 {
19 friend class I2SStream;
20
21 public:
23 I2SConfigStd defaultConfig(RxTxMode mode) {
24 I2SConfigStd c(mode);
25 return c;
26 }
28 bool setAudioInfo(AudioInfo info) {
29 if (info.sample_rate != cfg.sample_rate && !i2s.setFrequency(info.sample_rate)) {
30 LOGI("i2s.setFrequency %d failed", info.sample_rate);
31 return false;
32 }
33 if (info.bits_per_sample != cfg.bits_per_sample && !i2s.setBitsPerSample(info.bits_per_sample)) {
34 LOGI("i2s.setBitsPerSample %d failed", info.bits_per_sample);
35 return false;
36 }
37 cfg.sample_rate = info.sample_rate;
38 cfg.bits_per_sample = info.bits_per_sample;
39 cfg.channels = info.channels;
40 return true;
41 }
42
44 bool begin(RxTxMode mode = TX_MODE) {
45 TRACED();
46 return begin(defaultConfig(mode));
47 }
48
50 bool begin(I2SConfigStd cfg) {
51 TRACEI();
52 // prevent multiple begins w/o calling end
53 if (is_active) end();
54 this->cfg = cfg;
55 cfg.logInfo();
56 switch (cfg.rx_tx_mode) {
57 case TX_MODE:
58 i2s = I2S(OUTPUT);
59 break;
60 case RX_MODE:
61 i2s = I2S(INPUT);
62 has_input[0] = has_input[1] = false;
63 break;
64 default:
65 LOGE("Unsupported mode: only TX_MODE is supported");
66 return false;
67 break;
68 }
69
70 if (cfg.pin_ws == cfg.pin_bck + 1) { // normal pin order
71 if (!i2s.setBCLK(cfg.pin_bck)) {
72 LOGE("Could not set bck pin: %d", cfg.pin_bck);
73 return false;
74 }
75 } else if (cfg.pin_ws == cfg.pin_bck - 1) { // reverse pin order
76 if (!i2s.swapClocks() ||
77 !i2s.setBCLK(
78 cfg.pin_ws)) { // setBCLK() actually sets the lower pin of bck/ws
79 LOGE("Could not set bck pin: %d", cfg.pin_bck);
80 return false;
81 }
82 } else {
83 LOGE("pins bck: '%d' and ws: '%d' must be next to each other",
84 cfg.pin_bck, cfg.pin_ws);
85 return false;
86 }
87 if (!i2s.setDATA(cfg.pin_data)) {
88 LOGE("Could not set data pin: %d", cfg.pin_data);
89 return false;
90 }
91 if (cfg.pin_mck != -1) {
92 i2s.setMCLKmult(cfg.mck_multiplier);
93 if (!i2s.setMCLK(cfg.pin_mck)) {
94 LOGE("Could not set data pin: %d", cfg.pin_mck);
95 return false;
96 }
97 }
98
99 if (cfg.bits_per_sample == 8 ||
100 !i2s.setBitsPerSample(cfg.bits_per_sample)) {
101 LOGE("Could not set bits per sample: %d", cfg.bits_per_sample);
102 return false;
103 }
104
105 if (!i2s.setBuffers(cfg.buffer_count, cfg.buffer_size)) {
106 LOGE("Could not set buffers: Count: '%d', size: '%d'", cfg.buffer_count,
107 cfg.buffer_size);
108 return false;
109 }
110
111 // setup format
112 if (cfg.i2s_format == I2S_STD_FORMAT ||
113 cfg.i2s_format == I2S_PHILIPS_FORMAT) {
114 // default setting: do nothing
115 } else if (cfg.i2s_format == I2S_LEFT_JUSTIFIED_FORMAT ||
116 cfg.i2s_format == I2S_LSB_FORMAT) {
117 if (!i2s.setLSBJFormat()) {
118 LOGE("Could not set LSB Format")
119 return false;
120 }
121 } else {
122 LOGE("Unsupported I2S format");
123 return false;
124 }
125
126#if defined(RP2040_HOWER)
127
128 if (cfg.signal_type != TDM && (cfg.channels < 1 || cfg.channels > 2)) {
129 LOGE("Unsupported channels: '%d'", cfg.channels);
130 return false;
131 }
132
133 if (cfg.signal_type == TDM) {
134 i2s.setTDMFormat();
135 i2s.setTDMChannels(cfg.channels);
136 }
137
138#else
139
140 if (cfg.channels < 1 || cfg.channels > 2) {
141 LOGE("Unsupported channels: '%d'", cfg.channels);
142 return false;
143 }
144
145 if (cfg.signal_type != Digital) {
146 LOGE("Unsupported signal_type: '%d'", cfg.signal_type);
147 return false;
148 }
149
150#endif
151 if (!i2s.begin(cfg.sample_rate)) {
152 LOGE("Could not start I2S");
153 return false;
154 }
155 is_active = true;
156 return true;
157 }
158
160 void end() {
161 flush();
162 i2s.end();
163 is_active = false;
164 }
165
167 I2SConfigStd config() { return cfg; }
168
170 size_t writeBytes(const void *src, size_t size_bytes) {
171 LOGD("writeBytes(%d)", size_bytes);
172 size_t result = 0;
173
174 if (cfg.channels == 1) {
175 result = writeExpandChannel(src, size_bytes);
176 } else if (cfg.channels == 2) {
177 const uint8_t *p = (const uint8_t *)src;
178 while (size_bytes >= sizeof(int32_t)) {
179 bool justWritten = i2s.write(
180 *(int32_t *)p,
181 true); // I2S::write(int32,bool) actually only returns 0 or 1
182 if (justWritten) {
183 size_bytes -= sizeof(int32_t);
184 p += sizeof(int32_t);
185 result += sizeof(int32_t);
186 } else
187 return result;
188 }
189 }
190 return result;
191 }
192
193 size_t readBytes(void *dest, size_t size_bytes) {
194 TRACED();
195 switch (cfg.channels) {
196 case 1:
197 return read1Channel(dest, size_bytes);
198 case 2:
199 return read2Channels(dest, size_bytes);
200 }
201 return 0;
202 }
203
204 int availableForWrite() {
205 if (cfg.channels == 1) {
206 return cfg.buffer_size;
207 } else {
208 return i2s.availableForWrite();
209 }
210 }
211
212 int available() { return min(i2s.available(), cfg.buffer_size); }
213
214 void flush() { i2s.flush(); }
215
216 bool getOverUnderflow() {
217 return i2s.getOverUnderflow() ;
218 }
219
220 protected:
221 I2SConfigStd cfg;
222 I2S i2s;
223 bool has_input[2];
224 bool is_active = false;
225
227 // returns amount of bytes written from src to i2s
228 size_t writeExpandChannel(const void *src, size_t size_bytes) {
229 switch (cfg.bits_per_sample) {
230 // case 8: {
231 // int8_t *pt8 = (int8_t*) src;
232 // int16_t sample16 = static_cast<int16_t>(*pt8) << 8;
233 // for (int j=0;j<size_bytes;j++){
234 // // 8 bit does not work
235 // i2s.write8(pt8[j], pt8[j]);
236 // //LOGI("%d", pt8[j]);
237 // }
238 // } break;
239 case 16: {
240 int16_t *pt16 = (int16_t *)src;
241 for (int j = 0; j < size_bytes / sizeof(int16_t); j++) {
242 i2s.write16(pt16[j], pt16[j]);
243 }
244 } break;
245 case 24: {
246 int32_t *pt24 = (int32_t *)src;
247 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
248 i2s.write24(pt24[j], pt24[j]);
249 }
250 } break;
251 case 32: {
252 int32_t *pt32 = (int32_t *)src;
253 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
254 i2s.write32(pt32[j], pt32[j]);
255 }
256 } break;
257 }
258 return size_bytes;
259 }
260
262 size_t read2Channels(void *dest, size_t size_bytes) {
263 TRACED();
264 size_t result = 0;
265 switch (cfg.bits_per_sample) {
266 // case 8:{
267 // int8_t *data = (int8_t*)dest;
268 // for (int j=0;j<size_bytes;j+=2){
269 // if (i2s.read8(data+j, data+j+1)){
270 // result+=2;;
271 // } else {
272 // return result;
273 // }
274 // }
275 // }break;
276
277 case 16: {
278 int16_t *data = (int16_t *)dest;
279 for (int j = 0; j < size_bytes / sizeof(int16_t); j += 2) {
280 if (i2s.read16(data + j, data + j + 1)) {
281 result += 4;
282 } else {
283 return result;
284 }
285 }
286 } break;
287
288 case 24: {
289 int32_t *data = (int32_t *)dest;
290 for (int j = 0; j < size_bytes / sizeof(int32_t); j += 2) {
291 if (i2s.read24(data + j, data + j + 1)) {
292 result += 8;
293 } else {
294 return result;
295 }
296 }
297 } break;
298
299 case 32: {
300 int32_t *data = (int32_t *)dest;
301 for (int j = 0; j < size_bytes / sizeof(int32_t); j += 2) {
302 if (i2s.read32(data + j, data + j + 1)) {
303 result += 8;
304 } else {
305 return result;
306 }
307 }
308
309 } break;
310 }
311 return result;
312 }
313
315 size_t read1Channel(void *dest, size_t size_bytes) {
316 TRACED();
317 size_t result = 0;
318 switch (cfg.bits_per_sample) {
319 // case 8:{
320 // int8_t tmp[2];
321 // int8_t *data = (int8_t*)dest;
322 // for (int j=0;j<size_bytes;j++){
323 // if (i2s.read8(tmp, tmp+1)){
324 // data[j] = mix(tmp[0], tmp[1]);
325 // result++;;
326 // } else {
327 // return result;
328 // }
329 // }
330 // }break;
331
332 case 16: {
333 int16_t tmp[2];
334 int16_t *data = (int16_t *)dest;
335 for (int j = 0; j < size_bytes / sizeof(int16_t); j++) {
336 if (i2s.read16(tmp, tmp + 1)) {
337 data[j] = mix(tmp[0], tmp[1]);
338 result += 2;
339 } else {
340 return result;
341 }
342 }
343 } break;
344
345 case 24: {
346 int32_t tmp[2];
347 int32_t *data = (int32_t *)dest;
348 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
349 if (i2s.read24(tmp, tmp + 1)) {
350 data[j] = mix(tmp[0], tmp[1]);
351 result += 4;
352 } else {
353 return result;
354 }
355 }
356 } break;
357
358 case 32: {
359 int32_t tmp[2];
360 int32_t *data = (int32_t *)dest;
361 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
362 if (i2s.read32(tmp, tmp + 1)) {
363 data[j] = mix(tmp[0], tmp[1]);
364 result += 4;
365 } else {
366 return result;
367 }
368 }
369 } break;
370 }
371 return result;
372 }
373
374 // we just provide the avg of both samples
375 template <class T>
376 T mix(T left, T right) {
377 if (left != 0) has_input[0] = true;
378 if (right != 0) has_input[1] = true;
379
380 // if right is always empty we return left
381 if (has_input[0] && !has_input[1]) {
382 return left;
383 }
384
385 // if left is always empty we return right
386 if (!has_input[0] && has_input[1]) {
387 return right;
388 }
389
390 return (left / 2) + (right / 2);
391 }
392};
393
394using I2SDriver = I2SDriverRP2040;
395
396} // namespace audio_tools
397
398#endif
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:28
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10