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