Skip to content

Commit 048a457

Browse files
committed
incorporate feedback from review and add more comments
1 parent 369450c commit 048a457

File tree

5 files changed

+91
-16
lines changed

5 files changed

+91
-16
lines changed

libraries/I2S/keywords.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,3 @@ onTransmit KEYWORD2
2323
I2S_PHILIPS_MODE LITERAL1
2424
I2S_RIGHT_JUSTIFIED_MODE LITERAL1
2525
I2S_LEFT_JUSTIFIED_MODE LITERAL1
26-
I2S_DSP_MODE LITERAL1

libraries/I2S/src/I2S.cpp

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,13 @@ I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, u
4747

4848
int I2SClass::begin(int mode, long sampleRate, int bitsPerSample)
4949
{
50+
// master mode (driving clock and frame select pins - output)
5051
return begin(mode, sampleRate, bitsPerSample, true);
5152
}
5253

5354
int I2SClass::begin(int mode, int bitsPerSample)
5455
{
56+
// slave mode (not driving clock and frame select pin - input)
5557
return begin(mode, 0, bitsPerSample, false);
5658
}
5759

@@ -68,6 +70,7 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
6870
break;
6971

7072
default:
73+
// invalid mode
7174
return 1;
7275
}
7376

@@ -79,14 +82,17 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
7982
break;
8083

8184
default:
85+
// invalid bits per sample
8286
return 1;
8387
}
8488

89+
// try to allocate a DMA channel
8590
DMA.begin();
8691

8792
_dmaChannel = DMA.allocateChannel();
8893

8994
if (_dmaChannel < 0) {
95+
// no DMA channel available
9096
return 1;
9197
}
9298

@@ -101,15 +107,18 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
101107
_beginCount++;
102108

103109
if (driveClock) {
110+
// set up clock
104111
enableClock(sampleRate * 2 * bitsPerSample);
105112

106113
i2sd.setSerialClockSelectMasterClockDiv(_deviceIndex);
107114
i2sd.setFrameSyncSelectSerialClockDiv(_deviceIndex);
108115
} else {
116+
// use input signal from SCK and FS pins
109117
i2sd.setSerialClockSelectPin(_deviceIndex);
110118
i2sd.setFrameSyncSelectPin(_deviceIndex);
111119
}
112120

121+
// disable device before continuing
113122
i2sd.disable();
114123

115124
if (mode == I2S_PHILIPS_MODE) {
@@ -119,6 +128,7 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
119128
}
120129
i2sd.setNumberOfSlots(_deviceIndex, 1);
121130
i2sd.setSlotSize(_deviceIndex, bitsPerSample);
131+
i2sd.setDataSize(_deviceIndex, bitsPerSample);
122132

123133
pinPeripheral(_sckPin, PIO_COM);
124134
pinPeripheral(_fsPin, PIO_COM);
@@ -133,6 +143,7 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
133143

134144
pinPeripheral(_sdPin, PIO_COM);
135145

146+
// done configure enable
136147
i2sd.enable();
137148

138149
_doubleBuffer.reset();
@@ -152,6 +163,7 @@ void I2SClass::end()
152163
i2sd.disableSerializer(_deviceIndex);
153164
i2sd.disableClockUnit(_deviceIndex);
154165

166+
// set the pins back to input mode
155167
pinMode(_sdPin, INPUT);
156168
pinMode(_fsPin, INPUT);
157169
pinMode(_sckPin, INPUT);
@@ -183,10 +195,12 @@ int I2SClass::available()
183195
avail = _doubleBuffer.available();
184196

185197
if (_dmaTransferInProgress == false && _doubleBuffer.available() == 0) {
198+
// no DMA transfer in progress, start a receive process
186199
_dmaTransferInProgress = true;
187200

188201
DMA.transfer(_dmaChannel, i2sd.data(_deviceIndex), _doubleBuffer.data(), _doubleBuffer.availableForWrite());
189202

203+
// switch to the next buffer for user output (will be empty)
190204
_doubleBuffer.swap();
191205
}
192206

@@ -198,24 +212,37 @@ int I2SClass::available()
198212
return avail;
199213
}
200214

215+
union i2s_sample_t {
216+
uint8_t b8;
217+
int16_t b16;
218+
int32_t b32;
219+
};
220+
201221
int I2SClass::read()
202222
{
203-
int sample = 0;
223+
i2s_sample_t sample;
224+
225+
sample.b32 = 0;
204226

205227
read(&sample, _bitsPerSample / 8);
206228

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;
210237
}
211-
212-
return sample;
213238
}
214239

215240
int I2SClass::peek()
216241
{
217242
uint8_t enableInterrupts = ((__get_PRIMASK() & 0x1) == 0);
218-
int sample = 0;
243+
i2s_sample_t sample;
244+
245+
sample.b32 = 0;
219246

220247
// disable interrupts,
221248
__disable_irq();
@@ -227,16 +254,20 @@ int I2SClass::peek()
227254
__enable_irq();
228255
}
229256

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;
233265
}
234-
235-
return sample;
236266
}
237267

238268
void I2SClass::flush()
239269
{
270+
// do nothing, writes are DMA triggered
240271
}
241272

242273
size_t I2SClass::write(uint8_t data)
@@ -285,10 +316,12 @@ int I2SClass::read(void* buffer, size_t size)
285316
int read = _doubleBuffer.read(buffer, size);
286317

287318
if (_dmaTransferInProgress == false && _doubleBuffer.available() == 0) {
319+
// no DMA transfer in progress, start a receive process
288320
_dmaTransferInProgress = true;
289321

290322
DMA.transfer(_dmaChannel, i2sd.data(_deviceIndex), _doubleBuffer.data(), _doubleBuffer.availableForWrite());
291323

324+
// switch to the next buffer for user output (will be empty)
292325
_doubleBuffer.swap();
293326
}
294327

@@ -311,6 +344,7 @@ size_t I2SClass::write(int32_t sample)
311344
enableTransmitter();
312345
}
313346

347+
// this is a blocking write
314348
while(!i2sd.txReady(_deviceIndex));
315349

316350
i2sd.writeData(_deviceIndex, sample);
@@ -335,10 +369,12 @@ size_t I2SClass::write(const void *buffer, size_t size)
335369
written = _doubleBuffer.write(buffer, size);
336370

337371
if (_dmaTransferInProgress == false && _doubleBuffer.available()) {
372+
// no DMA transfer in progress, start a transmit process
338373
_dmaTransferInProgress = true;
339374

340375
DMA.transfer(_dmaChannel, _doubleBuffer.data(), i2sd.data(_deviceIndex), _doubleBuffer.available());
341376

377+
// switch to the next buffer for input
342378
_doubleBuffer.swap();
343379
}
344380

@@ -362,16 +398,19 @@ void I2SClass::onReceive(void(*function)(void))
362398

363399
void I2SClass::enableClock(int divider)
364400
{
401+
// configure the clock divider
365402
while (GCLK->STATUS.bit.SYNCBUSY);
366403
GCLK->GENDIV.bit.ID = _clockGenerator;
367404
GCLK->GENDIV.bit.DIV = SystemCoreClock / divider;
368405

406+
// use the DFLL as the source
369407
while (GCLK->STATUS.bit.SYNCBUSY);
370408
GCLK->GENCTRL.bit.ID = _clockGenerator;
371409
GCLK->GENCTRL.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val;
372410
GCLK->GENCTRL.bit.IDC = 1;
373411
GCLK->GENCTRL.bit.GENEN = 1;
374412

413+
// enable
375414
while (GCLK->STATUS.bit.SYNCBUSY);
376415
GCLK->CLKCTRL.bit.ID = i2sd.glckId(_deviceIndex);
377416
GCLK->CLKCTRL.bit.GEN = _clockGenerator;
@@ -427,26 +466,39 @@ void I2SClass::enableReceiver()
427466
void I2SClass::onTransferComplete(void)
428467
{
429468
if (_state == I2S_STATE_TRANSMITTER) {
469+
// transmit complete
470+
430471
if (_doubleBuffer.available()) {
472+
// output is available to transfer, start the DMA process for the current buffer
473+
431474
DMA.transfer(_dmaChannel, _doubleBuffer.data(), i2sd.data(_deviceIndex), _doubleBuffer.available());
432475

476+
// swap to the next user buffer for input
433477
_doubleBuffer.swap();
434478
} else {
479+
// no user data buffered to send
435480
_dmaTransferInProgress = false;
436481
}
437482

483+
// call the users transmit callback if provided
438484
if (_onTransmit) {
439485
_onTransmit();
440486
}
441487
} else {
488+
// receive complete
489+
442490
if (_doubleBuffer.available() == 0) {
491+
// the user has read all the current input, start the DMA process to fill it again
443492
DMA.transfer(_dmaChannel, i2sd.data(_deviceIndex), _doubleBuffer.data(), _doubleBuffer.availableForWrite());
444493

494+
// swap to the next buffer that has previously been filled, so that the user can read it
445495
_doubleBuffer.swap(_doubleBuffer.availableForWrite());
446496
} else {
497+
// user has not read current data, no free buffer to transfer into
447498
_dmaTransferInProgress = false;
448499
}
449500

501+
// call the users receveive callback if provided
450502
if (_onReceive) {
451503
_onReceive();
452504
}

libraries/I2S/src/I2S.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@ typedef enum {
3232
class I2SClass : public Stream
3333
{
3434
public:
35+
// the device index and pins must map to the "COM" pads in Table 6-1 of the datasheet
3536
I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin);
3637

38+
// the SCK and FS pins are driven as outputs using the sample rate
3739
int begin(int mode, long sampleRate, int bitsPerSample);
40+
// the SCK and FS pins are inputs, other side controls sample rate
3841
int begin(int mode, int bitsPerSample);
3942
void end();
4043

@@ -98,6 +101,8 @@ class I2SClass : public Stream
98101
void (*_onReceive)(void);
99102
};
100103

104+
// "I2S" is already defined by the CMSIS device, undefine it so the I2SClass
105+
// instance can be called I2S
101106
#undef I2S
102107

103108
#if I2S_INTERFACES_COUNT > 0

libraries/I2S/src/utility/DMA.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
#define NUM_DMA_CHANNELS 1
2121

22+
/*
23+
WARNING: The API for this class may change and it's not intended for public use!
24+
*/
2225
class DMAClass
2326
{
2427
public:

libraries/I2S/src/utility/SAMD21_I2SDevice.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,37 @@ class I2SDevice_SAMD21G18x {
7979
switch (size) {
8080
case 32:
8181
i2s.CLKCTRL[index].bit.SLOTSIZE = I2S_CLKCTRL_SLOTSIZE_32_Val;
82-
i2s.SERCTRL[index].bit.DATASIZE = I2S_SERCTRL_DATASIZE_32_Val;
8382
break;
8483

8584
case 24:
8685
i2s.CLKCTRL[index].bit.SLOTSIZE = I2S_CLKCTRL_SLOTSIZE_24_Val;
87-
i2s.SERCTRL[index].bit.DATASIZE = I2S_SERCTRL_DATASIZE_24_Val;
8886
break;
8987

9088
case 16:
9189
i2s.CLKCTRL[index].bit.SLOTSIZE = I2S_CLKCTRL_SLOTSIZE_16_Val;
92-
i2s.SERCTRL[index].bit.DATASIZE = I2S_SERCTRL_DATASIZE_16_Val;
9390
break;
9491

9592
case 8:
9693
i2s.CLKCTRL[index].bit.SLOTSIZE = I2S_CLKCTRL_SLOTSIZE_8_Val;
94+
break;
95+
}
96+
}
97+
98+
inline void setDataSize(int index, int size) {
99+
switch (size) {
100+
case 32:
101+
i2s.SERCTRL[index].bit.DATASIZE = I2S_SERCTRL_DATASIZE_32_Val;
102+
break;
103+
104+
case 24:
105+
i2s.SERCTRL[index].bit.DATASIZE = I2S_SERCTRL_DATASIZE_24_Val;
106+
break;
107+
108+
case 16:
109+
i2s.SERCTRL[index].bit.DATASIZE = I2S_SERCTRL_DATASIZE_16_Val;
110+
break;
111+
112+
case 8:
97113
i2s.SERCTRL[index].bit.DATASIZE = I2S_SERCTRL_DATASIZE_8_Val;
98114
break;
99115
}

0 commit comments

Comments
 (0)