Skip to content

Commit 010b6a8

Browse files
committed
add DMA based receiver support
1 parent 9fd1717 commit 010b6a8

File tree

5 files changed

+142
-25
lines changed

5 files changed

+142
-25
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <I2S.h>
2+
3+
void setup() {
4+
// Open serial communications and wait for port to open:
5+
Serial.begin(115200);
6+
while (!Serial) {
7+
; // wait for serial port to connect. Needed for native USB port only
8+
}
9+
10+
// start I2S at 8 kHz with 32-bits per sample
11+
if (I2S.begin(I2S_PHILIPS_MODE, 8000, 32)) {
12+
Serial.println("Failed to initialize I2S!");
13+
while (1); // do nothing
14+
}
15+
}
16+
17+
void loop() {
18+
// read a sample
19+
int sample = I2S.read();
20+
21+
if (sample) {
22+
// if it's non-zero print value to serial
23+
Serial.println(sample);
24+
}
25+
}
26+

libraries/I2S/src/I2S.cpp

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, u
4040
_bitsPerSample(0),
4141
_dmaTransferInProgress(false),
4242

43-
_onTransmit(NULL)
43+
_onTransmit(NULL),
44+
_onReceive(NULL)
4445
{
4546
}
4647

@@ -143,20 +144,35 @@ int I2SClass::available()
143144
enableReceiver();
144145
}
145146

146-
return (_bitsPerSample / 8);
147-
}
147+
uint8_t enableInterrupts = ((__get_PRIMASK() & 0x1) == 0);
148+
size_t avail;
148149

149-
int I2SClass::read()
150-
{
151-
if (_state != I2S_STATE_RECEIVER) {
152-
enableReceiver();
150+
// disable interrupts,
151+
__disable_irq();
152+
153+
avail = _doubleBuffer.available();
154+
155+
if (_dmaTransferInProgress == false && _doubleBuffer.available() == 0) {
156+
_dmaTransferInProgress = true;
157+
158+
DMA.transfer(_dmaChannel, i2sd.data(_deviceIndex), _doubleBuffer.data(), _doubleBuffer.availableForWrite());
159+
160+
_doubleBuffer.swap();
153161
}
154162

155-
while(!i2sd.rxReady(_deviceIndex));
163+
if (enableInterrupts) {
164+
// re-enable the interrupts
165+
__enable_irq();
166+
}
156167

157-
int sample = i2sd.readData(_deviceIndex);
168+
return avail;
169+
}
170+
171+
int I2SClass::read()
172+
{
173+
int sample = 0;
158174

159-
i2sd.clearRxReady(_deviceIndex);
175+
read(&sample, _bitsPerSample / 8);
160176

161177
return sample;
162178
}
@@ -202,6 +218,35 @@ size_t I2SClass::availableForWrite()
202218
return space;
203219
}
204220

221+
int I2SClass::read(void* buffer, size_t size)
222+
{
223+
if (_state != I2S_STATE_RECEIVER) {
224+
enableReceiver();
225+
}
226+
227+
uint8_t enableInterrupts = ((__get_PRIMASK() & 0x1) == 0);
228+
229+
// disable interrupts,
230+
__disable_irq();
231+
232+
int read = _doubleBuffer.read(buffer, size);
233+
234+
if (_dmaTransferInProgress == false && _doubleBuffer.available() == 0) {
235+
_dmaTransferInProgress = true;
236+
237+
DMA.transfer(_dmaChannel, i2sd.data(_deviceIndex), _doubleBuffer.data(), _doubleBuffer.availableForWrite());
238+
239+
_doubleBuffer.swap();
240+
}
241+
242+
if (enableInterrupts) {
243+
// re-enable the interrupts
244+
__enable_irq();
245+
}
246+
247+
return read;
248+
}
249+
205250
size_t I2SClass::write(int sample)
206251
{
207252
return write((int32_t)sample);
@@ -236,7 +281,7 @@ size_t I2SClass::write(const void *buffer, size_t size)
236281

237282
written = _doubleBuffer.write(buffer, size);
238283

239-
if (_dmaTransferInProgress == false) {
284+
if (_dmaTransferInProgress == false && _doubleBuffer.available()) {
240285
_dmaTransferInProgress = true;
241286

242287
DMA.transfer(_dmaChannel, _doubleBuffer.data(), i2sd.data(_deviceIndex), _doubleBuffer.available());
@@ -257,6 +302,11 @@ void I2SClass::onTransmit(void(*function)(void))
257302
_onTransmit = function;
258303
}
259304

305+
void I2SClass::onReceive(void(*function)(void))
306+
{
307+
_onReceive = function;
308+
}
309+
260310
void I2SClass::enableClock(int divider)
261311
{
262312
while (GCLK->STATUS.bit.SYNCBUSY);
@@ -313,7 +363,7 @@ void I2SClass::enableReceiver()
313363
i2sd.enableClockUnit(_deviceIndex);
314364
i2sd.enableSerializer(_deviceIndex);
315365

316-
DMA.incSrc(_dmaChannel);
366+
DMA.incDst(_dmaChannel);
317367
DMA.onTransferComplete(_dmaChannel, I2SClass::onDmaTransferComplete);
318368
DMA.setTriggerSource(_dmaChannel, i2sd.dmaTriggerSource(_deviceIndex));
319369
DMA.setTransferWidth(_dmaChannel, _bitsPerSample);
@@ -323,16 +373,30 @@ void I2SClass::enableReceiver()
323373

324374
void I2SClass::onTransferComplete(void)
325375
{
326-
if (_doubleBuffer.available()) {
327-
DMA.transfer(_dmaChannel, _doubleBuffer.data(), i2sd.data(_deviceIndex), _doubleBuffer.available());
328-
329-
_doubleBuffer.swap();
376+
if (_state == I2S_STATE_TRANSMITTER) {
377+
if (_doubleBuffer.available()) {
378+
DMA.transfer(_dmaChannel, _doubleBuffer.data(), i2sd.data(_deviceIndex), _doubleBuffer.available());
379+
380+
_doubleBuffer.swap();
381+
} else {
382+
_dmaTransferInProgress = false;
383+
}
384+
385+
if (_onTransmit) {
386+
_onTransmit();
387+
}
330388
} else {
331-
_dmaTransferInProgress = false;
332-
}
389+
if (_doubleBuffer.available() == 0) {
390+
DMA.transfer(_dmaChannel, i2sd.data(_deviceIndex), _doubleBuffer.data(), _doubleBuffer.availableForWrite());
391+
392+
_doubleBuffer.swap(_doubleBuffer.availableForWrite());
393+
} else {
394+
_dmaTransferInProgress = false;
395+
}
333396

334-
if (_onTransmit) {
335-
_onTransmit();
397+
if (_onReceive) {
398+
_onReceive();
399+
}
336400
}
337401
}
338402

libraries/I2S/src/I2S.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,14 @@ class I2SClass : public Stream
4747

4848
virtual size_t availableForWrite();
4949

50+
int read(void* buffer, size_t size);
51+
5052
size_t write(int);
5153
size_t write(int32_t);
5254
size_t write(const void *buffer, size_t size);
5355

5456
void onTransmit(void(*)(void));
57+
void onReceive(void(*)(void));
5558

5659
private:
5760
void enableClock(int divider);
@@ -87,6 +90,7 @@ class I2SClass : public Stream
8790
I2SDoubleBuffer _doubleBuffer;
8891

8992
void (*_onTransmit)(void);
93+
void (*_onReceive)(void);
9094
};
9195

9296
#undef I2S

libraries/I2S/src/utility/I2SDoubleBuffer.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ void I2SDoubleBuffer::reset()
3434
_index = 0;
3535
_length[0] = 0;
3636
_length[1] = 0;
37+
_readOffset[0] = 0;
38+
_readOffset[1] = 0;
3739
}
3840

3941
size_t I2SDoubleBuffer::availableForWrite()
4042
{
41-
return (I2S_BUFFER_SIZE - _length[_index]);
43+
return (I2S_BUFFER_SIZE - (_length[_index] - _readOffset[_index]));
4244
}
4345

4446
size_t I2SDoubleBuffer::write(const void *buffer, size_t size)
@@ -60,23 +62,42 @@ size_t I2SDoubleBuffer::write(const void *buffer, size_t size)
6062
return size;
6163
}
6264

65+
size_t I2SDoubleBuffer::read(void *buffer, size_t size)
66+
{
67+
size_t avail = available();
68+
69+
if (size > avail) {
70+
size = avail;
71+
}
72+
73+
if (size == 0) {
74+
return 0;
75+
}
76+
77+
memcpy(buffer, &_buffer[_index][_readOffset[_index]], size);
78+
_readOffset[_index] += size;
79+
80+
return size;
81+
}
82+
6383
void* I2SDoubleBuffer::data()
6484
{
6585
return (void*)_buffer[_index];
6686
}
6787

6888
size_t I2SDoubleBuffer::available()
6989
{
70-
return _length[_index];
90+
return _length[_index] - _readOffset[_index];
7191
}
7292

73-
void I2SDoubleBuffer::swap()
93+
void I2SDoubleBuffer::swap(int length)
7494
{
7595
if (_index == 0) {
7696
_index = 1;
7797
} else {
7898
_index = 0;
7999
}
80100

81-
_length[_index] = 0;
101+
_length[_index] = length;
102+
_readOffset[_index] = 0;
82103
}

libraries/I2S/src/utility/I2SDoubleBuffer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ class I2SDoubleBuffer
3434

3535
size_t availableForWrite();
3636
size_t write(const void *buffer, size_t size);
37+
size_t read(void *buffer, size_t size);
3738
void* data();
3839
size_t available();
39-
void swap();
40+
void swap(int length = 0);
4041

4142
private:
4243
uint8_t _buffer[2][I2S_BUFFER_SIZE];
4344
volatile int _length[2];
45+
volatile int _readOffset[2];
4446
volatile int _index;
4547
};
4648

0 commit comments

Comments
 (0)