@@ -47,11 +47,13 @@ I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, u
47
47
48
48
int I2SClass::begin (int mode, long sampleRate, int bitsPerSample)
49
49
{
50
+ // master mode (driving clock and frame select pins - output)
50
51
return begin (mode, sampleRate, bitsPerSample, true );
51
52
}
52
53
53
54
int I2SClass::begin (int mode, int bitsPerSample)
54
55
{
56
+ // slave mode (not driving clock and frame select pin - input)
55
57
return begin (mode, 0 , bitsPerSample, false );
56
58
}
57
59
@@ -68,6 +70,7 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
68
70
break ;
69
71
70
72
default :
73
+ // invalid mode
71
74
return 1 ;
72
75
}
73
76
@@ -79,14 +82,17 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
79
82
break ;
80
83
81
84
default :
85
+ // invalid bits per sample
82
86
return 1 ;
83
87
}
84
88
89
+ // try to allocate a DMA channel
85
90
DMA.begin ();
86
91
87
92
_dmaChannel = DMA.allocateChannel ();
88
93
89
94
if (_dmaChannel < 0 ) {
95
+ // no DMA channel available
90
96
return 1 ;
91
97
}
92
98
@@ -101,15 +107,18 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
101
107
_beginCount++;
102
108
103
109
if (driveClock) {
110
+ // set up clock
104
111
enableClock (sampleRate * 2 * bitsPerSample);
105
112
106
113
i2sd.setSerialClockSelectMasterClockDiv (_deviceIndex);
107
114
i2sd.setFrameSyncSelectSerialClockDiv (_deviceIndex);
108
115
} else {
116
+ // use input signal from SCK and FS pins
109
117
i2sd.setSerialClockSelectPin (_deviceIndex);
110
118
i2sd.setFrameSyncSelectPin (_deviceIndex);
111
119
}
112
120
121
+ // disable device before continuing
113
122
i2sd.disable ();
114
123
115
124
if (mode == I2S_PHILIPS_MODE) {
@@ -119,6 +128,7 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
119
128
}
120
129
i2sd.setNumberOfSlots (_deviceIndex, 1 );
121
130
i2sd.setSlotSize (_deviceIndex, bitsPerSample);
131
+ i2sd.setDataSize (_deviceIndex, bitsPerSample);
122
132
123
133
pinPeripheral (_sckPin, PIO_COM);
124
134
pinPeripheral (_fsPin, PIO_COM);
@@ -133,6 +143,7 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
133
143
134
144
pinPeripheral (_sdPin, PIO_COM);
135
145
146
+ // done configure enable
136
147
i2sd.enable ();
137
148
138
149
_doubleBuffer.reset ();
@@ -152,6 +163,7 @@ void I2SClass::end()
152
163
i2sd.disableSerializer (_deviceIndex);
153
164
i2sd.disableClockUnit (_deviceIndex);
154
165
166
+ // set the pins back to input mode
155
167
pinMode (_sdPin, INPUT);
156
168
pinMode (_fsPin, INPUT);
157
169
pinMode (_sckPin, INPUT);
@@ -183,10 +195,12 @@ int I2SClass::available()
183
195
avail = _doubleBuffer.available ();
184
196
185
197
if (_dmaTransferInProgress == false && _doubleBuffer.available () == 0 ) {
198
+ // no DMA transfer in progress, start a receive process
186
199
_dmaTransferInProgress = true ;
187
200
188
201
DMA.transfer (_dmaChannel, i2sd.data (_deviceIndex), _doubleBuffer.data (), _doubleBuffer.availableForWrite ());
189
202
203
+ // switch to the next buffer for user output (will be empty)
190
204
_doubleBuffer.swap ();
191
205
}
192
206
@@ -198,24 +212,37 @@ int I2SClass::available()
198
212
return avail;
199
213
}
200
214
215
+ union i2s_sample_t {
216
+ uint8_t b8;
217
+ int16_t b16;
218
+ int32_t b32;
219
+ };
220
+
201
221
int I2SClass::read ()
202
222
{
203
- int sample = 0 ;
223
+ i2s_sample_t sample;
224
+
225
+ sample.b32 = 0 ;
204
226
205
227
read (&sample, _bitsPerSample / 8 );
206
228
207
- if (_bitsPerSample == 16 && (sample & 0x8000 )) {
208
- // sign extend value
209
- sample |= 0xffff0000 ;
229
+ if (_bitsPerSample == 32 ) {
230
+ return sample.b32 ;
231
+ } else if (_bitsPerSample == 16 ) {
232
+ return sample.b16 ;
233
+ } else if (_bitsPerSample == 8 ) {
234
+ return sample.b8 ;
235
+ } else {
236
+ return 0 ;
210
237
}
211
-
212
- return sample;
213
238
}
214
239
215
240
int I2SClass::peek ()
216
241
{
217
242
uint8_t enableInterrupts = ((__get_PRIMASK () & 0x1 ) == 0 );
218
- int sample = 0 ;
243
+ i2s_sample_t sample;
244
+
245
+ sample.b32 = 0 ;
219
246
220
247
// disable interrupts,
221
248
__disable_irq ();
@@ -227,16 +254,20 @@ int I2SClass::peek()
227
254
__enable_irq ();
228
255
}
229
256
230
- if (_bitsPerSample == 16 && (sample & 0x8000 )) {
231
- // sign extend value
232
- sample |= 0xffff0000 ;
257
+ if (_bitsPerSample == 32 ) {
258
+ return sample.b32 ;
259
+ } else if (_bitsPerSample == 16 ) {
260
+ return sample.b16 ;
261
+ } else if (_bitsPerSample == 8 ) {
262
+ return sample.b8 ;
263
+ } else {
264
+ return 0 ;
233
265
}
234
-
235
- return sample;
236
266
}
237
267
238
268
void I2SClass::flush ()
239
269
{
270
+ // do nothing, writes are DMA triggered
240
271
}
241
272
242
273
size_t I2SClass::write (uint8_t data)
@@ -285,10 +316,12 @@ int I2SClass::read(void* buffer, size_t size)
285
316
int read = _doubleBuffer.read (buffer, size);
286
317
287
318
if (_dmaTransferInProgress == false && _doubleBuffer.available () == 0 ) {
319
+ // no DMA transfer in progress, start a receive process
288
320
_dmaTransferInProgress = true ;
289
321
290
322
DMA.transfer (_dmaChannel, i2sd.data (_deviceIndex), _doubleBuffer.data (), _doubleBuffer.availableForWrite ());
291
323
324
+ // switch to the next buffer for user output (will be empty)
292
325
_doubleBuffer.swap ();
293
326
}
294
327
@@ -311,6 +344,7 @@ size_t I2SClass::write(int32_t sample)
311
344
enableTransmitter ();
312
345
}
313
346
347
+ // this is a blocking write
314
348
while (!i2sd.txReady (_deviceIndex));
315
349
316
350
i2sd.writeData (_deviceIndex, sample);
@@ -335,10 +369,12 @@ size_t I2SClass::write(const void *buffer, size_t size)
335
369
written = _doubleBuffer.write (buffer, size);
336
370
337
371
if (_dmaTransferInProgress == false && _doubleBuffer.available ()) {
372
+ // no DMA transfer in progress, start a transmit process
338
373
_dmaTransferInProgress = true ;
339
374
340
375
DMA.transfer (_dmaChannel, _doubleBuffer.data (), i2sd.data (_deviceIndex), _doubleBuffer.available ());
341
376
377
+ // switch to the next buffer for input
342
378
_doubleBuffer.swap ();
343
379
}
344
380
@@ -362,16 +398,19 @@ void I2SClass::onReceive(void(*function)(void))
362
398
363
399
void I2SClass::enableClock (int divider)
364
400
{
401
+ // configure the clock divider
365
402
while (GCLK->STATUS .bit .SYNCBUSY );
366
403
GCLK->GENDIV .bit .ID = _clockGenerator;
367
404
GCLK->GENDIV .bit .DIV = SystemCoreClock / divider;
368
405
406
+ // use the DFLL as the source
369
407
while (GCLK->STATUS .bit .SYNCBUSY );
370
408
GCLK->GENCTRL .bit .ID = _clockGenerator;
371
409
GCLK->GENCTRL .bit .SRC = GCLK_GENCTRL_SRC_DFLL48M_Val;
372
410
GCLK->GENCTRL .bit .IDC = 1 ;
373
411
GCLK->GENCTRL .bit .GENEN = 1 ;
374
412
413
+ // enable
375
414
while (GCLK->STATUS .bit .SYNCBUSY );
376
415
GCLK->CLKCTRL .bit .ID = i2sd.glckId (_deviceIndex);
377
416
GCLK->CLKCTRL .bit .GEN = _clockGenerator;
@@ -427,26 +466,39 @@ void I2SClass::enableReceiver()
427
466
void I2SClass::onTransferComplete (void )
428
467
{
429
468
if (_state == I2S_STATE_TRANSMITTER) {
469
+ // transmit complete
470
+
430
471
if (_doubleBuffer.available ()) {
472
+ // output is available to transfer, start the DMA process for the current buffer
473
+
431
474
DMA.transfer (_dmaChannel, _doubleBuffer.data (), i2sd.data (_deviceIndex), _doubleBuffer.available ());
432
475
476
+ // swap to the next user buffer for input
433
477
_doubleBuffer.swap ();
434
478
} else {
479
+ // no user data buffered to send
435
480
_dmaTransferInProgress = false ;
436
481
}
437
482
483
+ // call the users transmit callback if provided
438
484
if (_onTransmit) {
439
485
_onTransmit ();
440
486
}
441
487
} else {
488
+ // receive complete
489
+
442
490
if (_doubleBuffer.available () == 0 ) {
491
+ // the user has read all the current input, start the DMA process to fill it again
443
492
DMA.transfer (_dmaChannel, i2sd.data (_deviceIndex), _doubleBuffer.data (), _doubleBuffer.availableForWrite ());
444
493
494
+ // swap to the next buffer that has previously been filled, so that the user can read it
445
495
_doubleBuffer.swap (_doubleBuffer.availableForWrite ());
446
496
} else {
497
+ // user has not read current data, no free buffer to transfer into
447
498
_dmaTransferInProgress = false ;
448
499
}
449
500
501
+ // call the users receveive callback if provided
450
502
if (_onReceive) {
451
503
_onReceive ();
452
504
}
0 commit comments