Skip to content

Commit fd4b3e9

Browse files
committed
I2S using DMA
1 parent 4c1ef09 commit fd4b3e9

File tree

4 files changed

+402
-88
lines changed

4 files changed

+402
-88
lines changed

libraries/I2S/src/I2S.cpp

Lines changed: 91 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
#include <Arduino.h>
22
#include <wiring_private.h>
33

4+
#include "utility/DMA.h"
5+
46
#include "I2S.h"
57

6-
I2SClass::I2SClass(SERCOM *p_sercom, uint8_t uc_index, uint8_t uc_pinSD, uint8_t uc_pinSCK, uint8_t uc_pinFS) :
7-
_p_sercom(p_sercom),
8+
I2SClass::I2SClass(uint8_t uc_index, uint8_t uc_clock_generator, uint8_t uc_pinSD, uint8_t uc_pinSCK, uint8_t uc_pinFS) :
89
_uc_index(uc_index),
10+
_uc_clock_generator(uc_clock_generator),
911
_uc_sd(uc_pinSD),
1012
_uc_sck(uc_pinSCK),
1113
_uc_fs(uc_pinFS),
1214

13-
_i_head(0),
14-
_i_tail(0)
15+
_i_dma_channel(-1),
16+
freeBuffers(2),
17+
inIndex(0),
18+
19+
_onTransmit(NULL)
1520
{
16-
memset(_aui_buffer, 0, sizeof(_aui_buffer));
1721
}
1822

1923
int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, int driveClock)
@@ -35,32 +39,39 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, int driveClock
3539
case 16:
3640
case 24:
3741
case 32:
38-
_i_bits_per_sample = bitsPerSample;
3942
break;
4043

4144
default:
4245
Serial.println("invalid bits per sample");
4346
return 1;
4447
}
4548

49+
DMA.begin();
50+
51+
_i_dma_channel = DMA.allocateChannel();
52+
53+
if (_i_dma_channel < 0) {
54+
return 1;
55+
}
56+
4657
while(_i2s->SYNCBUSY.bit.SWRST);
4758
_i2s->CTRLA.bit.SWRST = 1;
4859

4960
PM->APBCMASK.reg |= PM_APBCMASK_I2S;
5061

5162
while (GCLK->STATUS.bit.SYNCBUSY);
52-
GCLK->GENDIV.bit.ID = GCLK_CLKCTRL_GEN_GCLK3_Val;
63+
GCLK->GENDIV.bit.ID = _uc_clock_generator;
5364
GCLK->GENDIV.bit.DIV = SystemCoreClock / (sampleRate * 2 * bitsPerSample);
5465

5566
while (GCLK->STATUS.bit.SYNCBUSY);
56-
GCLK->GENCTRL.bit.ID = GCLK_CLKCTRL_GEN_GCLK3_Val;
67+
GCLK->GENCTRL.bit.ID = _uc_clock_generator;
5768
GCLK->GENCTRL.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val;
5869
GCLK->GENCTRL.bit.IDC = 1;
5970
GCLK->GENCTRL.bit.GENEN = 1;
6071

6172
while (GCLK->STATUS.bit.SYNCBUSY);
6273
GCLK->CLKCTRL.bit.ID = (_uc_index == 0) ? I2S_GCLK_ID_0 : I2S_GCLK_ID_1;
63-
GCLK->CLKCTRL.bit.GEN = GCLK_CLKCTRL_GEN_GCLK3_Val;
74+
GCLK->CLKCTRL.bit.GEN = _uc_clock_generator;
6475
GCLK->CLKCTRL.bit.CLKEN = 1;
6576

6677
while (GCLK->STATUS.bit.SYNCBUSY);
@@ -163,8 +174,33 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, int driveClock
163174
_i2s->CTRLA.bit.SEREN1 = 1;
164175
}
165176

166-
NVIC_EnableIRQ(I2S_IRQn);
167-
NVIC_SetPriority(I2S_IRQn, (1 << __NVIC_PRIO_BITS) - 1); /* set Priority */
177+
DMA.incSrc(_i_dma_channel);
178+
DMA.onTransferComplete(_i_dma_channel, I2SClass::onDmaTransferComplete);
179+
DMA.onTransferError(_i_dma_channel, I2SClass::onDmaTransferError);
180+
181+
if (_uc_index == 0) {
182+
DMA.setTriggerSource(_i_dma_channel, I2S_DMAC_ID_TX_0);
183+
} else {
184+
DMA.setTriggerSource(_i_dma_channel, I2S_DMAC_ID_TX_1);
185+
}
186+
187+
switch (bitsPerSample) {
188+
case 32:
189+
DMA.setTransferWidth(_i_dma_channel, 32);
190+
break;
191+
192+
case 24:
193+
DMA.setTransferWidth(_i_dma_channel, 32);
194+
break;
195+
196+
case 16:
197+
DMA.setTransferWidth(_i_dma_channel, 16);
198+
break;
199+
200+
case 8:
201+
DMA.setTransferWidth(_i_dma_channel, 8);
202+
break;
203+
}
168204

169205
return 0;
170206
}
@@ -195,99 +231,81 @@ void I2SClass::flush()
195231

196232
size_t I2SClass::write(uint8_t data)
197233
{
198-
return write((int32_t)data);
234+
return write(&data, sizeof(data));
199235
}
200236

201237
size_t I2SClass::write(const uint8_t *buffer, size_t size)
202238
{
203-
size_t written = 0;
204-
int bytesPerSample = (_i_bits_per_sample) / 8;
239+
__disable_irq();
205240

206-
size = (size / bytesPerSample) * bytesPerSample;
241+
if (freeBuffers == 0) {
242+
__enable_irq();
243+
return 0;
244+
}
245+
246+
if (size > I2S_BUFFER_SIZE) {
247+
size = I2S_BUFFER_SIZE;
248+
}
207249

208-
while (size) {
209-
int32_t data;
250+
freeBuffers--;
251+
memcpy(&_auc_buffer[inIndex], buffer, size);
210252

211-
memcpy(&data, buffer + written, bytesPerSample);
212-
written += bytesPerSample;
213-
size -= bytesPerSample;
253+
if (freeBuffers == 1) {
254+
DMA.transfer(_i_dma_channel, &_auc_buffer[inIndex], (void*)&_i2s->DATA[_uc_index].reg, size);
255+
}
214256

215-
if (write(data) == 0) {
216-
break;
217-
}
257+
if (inIndex == 0) {
258+
inIndex = I2S_BUFFER_SIZE;
259+
} else {
260+
inIndex = 0;
218261
}
219262

220-
return written;
263+
__enable_irq();
264+
265+
return size;
221266
}
222267

223268
size_t I2SClass::availableForWrite()
224269
{
225-
if (_i_head >= _i_tail) {
226-
return I2S_BUFFER_SIZE - 1 - _i_head + _i_tail;
227-
} else {
228-
return _i_tail - _i_head - 1;
229-
}
270+
return (freeBuffers * I2S_BUFFER_SIZE);
230271
}
231272

232-
int I2SClass::read(int8_t data[], int size)
273+
void I2SClass::onTransmit(void(*function)(void))
233274
{
234-
return 0;
275+
_onTransmit = function;
235276
}
236277

237-
int I2SClass::write(short data)
278+
void I2SClass::onDmaTransferComplete()
238279
{
239-
return write((int32_t)data);
280+
I2S.onTransferComplete();
240281
}
241282

242-
int I2SClass::write(int data)
283+
void I2SClass::onDmaTransferError()
243284
{
244-
return write((int32_t)data);
285+
I2S.onTransferError();
245286
}
246287

247-
int I2SClass::write(int32_t data)
288+
void I2SClass::onTransferComplete(void)
248289
{
249-
int i = ((uint32_t)(_i_head + 1) % I2S_BUFFER_SIZE);
250-
251-
if (i == _i_tail) {
252-
return 0;
253-
}
254-
255-
_aui_buffer[i] = data;
256-
_i_head = i;
290+
freeBuffers++;
257291

292+
int outIndex;
258293

259-
if (_uc_index == 0) {
260-
_i2s->INTENSET.bit.TXRDY0 = 1;
294+
if (inIndex == 0) {
295+
outIndex = I2S_BUFFER_SIZE;
261296
} else {
262-
_i2s->INTENSET.bit.TXRDY1 = 1;
297+
outIndex = 0;
263298
}
264299

265-
return 1;
266-
}
267-
268-
void I2SClass::onService() {
300+
DMA.transfer(_i_dma_channel, &_auc_buffer[outIndex], (void*)&_i2s->DATA[_uc_index].reg, 512);
269301

270-
if (_uc_index == 0) {
271-
if (_i2s->INTFLAG.bit.TXRDY0) {
272-
if (_i_head != _i_tail) {
273-
int32_t data = _aui_buffer[_i_tail];
274-
_i_tail = ((uint32_t)(_i_tail + 1) % I2S_BUFFER_SIZE);
275-
276-
while (_i2s->SYNCBUSY.bit.DATA0);
277-
_i2s->DATA[_uc_index].bit.DATA = data;
278-
} else {
279-
_i2s->INTENSET.bit.TXRDY0 = 0;
280-
}
281-
282-
_i2s->INTFLAG.bit.TXRDY0 = 1;
283-
}
302+
if (_onTransmit) {
303+
_onTransmit();
284304
}
285305
}
286306

287-
extern "C" {
288-
void I2S_Handler() {
289-
I2S.onService();
290-
}
307+
void I2SClass::onTransferError(void)
308+
{
291309
}
292310

293311
/*
@@ -307,4 +325,7 @@ extern "C" {
307325
+--------+--------------+-----------+-----------------+
308326
*/
309327

310-
I2SClass I2S(&sercom2, 0, 9, 1, 0);
328+
329+
// I2SClass I2S(0, GCLK_CLKCTRL_GEN_GCLK3_Val, 9, 1, 0);
330+
331+
I2SClass I2S(0, GCLK_CLKCTRL_GEN_GCLK3_Val, A6, 2, 3);

libraries/I2S/src/I2S.h

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ typedef enum {
1010
I2S_DSP_MODE
1111
} i2s_mode_t;
1212

13-
#define I2S_BUFFER_SIZE 256
13+
#define I2S_BUFFER_SIZE 512
1414

1515
class I2SClass : public Stream
1616
{
1717
public:
18-
I2SClass(SERCOM *p_sercom, uint8_t uc_index, uint8_t uc_pinSD, uint8_t uc_pinSCK, uint8_t uc_pinFS);
18+
I2SClass(uint8_t uc_index, uint8_t uc_clock_generator, uint8_t uc_pinSD, uint8_t uc_pinSCK, uint8_t uc_pinFS);
1919

2020
int begin(int mode, long sampleRate, int bitsPerSample, int driveClock = 1);
2121

@@ -31,37 +31,35 @@ class I2SClass : public Stream
3131

3232
virtual size_t availableForWrite();
3333

34-
int write(short);
35-
int write(int);
3634
int write(int32_t);
3735

38-
int read(int8_t data[], int size);
39-
int read(int16_t data[], int size);
40-
int read(int32_t data[], int size);
41-
42-
int write(const int8_t data[], int size);
43-
int write(const int16_t data[], int size);
44-
int write(const int32_t data[], int size);
45-
4636
void onReceive(void(*)(int));
4737
void onTransmit(void(*)(void));
4838

49-
void onService(void);
39+
40+
private:
41+
static void onDmaTransferComplete();
42+
static void onDmaTransferError();
43+
44+
void onTransferComplete(void);
45+
void onTransferError(void);
5046

5147
private:
5248
volatile I2s *_i2s = I2S;
5349

54-
SERCOM *_p_sercom;
5550
uint8_t _uc_index;
51+
uint8_t _uc_clock_generator;
5652
uint8_t _uc_sd;
5753
uint8_t _uc_sck;
5854
uint8_t _uc_fs;
5955

60-
int _i_bits_per_sample;
56+
int _i_dma_channel;
57+
58+
uint8_t* _auc_buffer[I2S_BUFFER_SIZE * 2];
59+
volatile int freeBuffers;
60+
volatile int inIndex;
6161

62-
int32_t _aui_buffer[I2S_BUFFER_SIZE];
63-
volatile int _i_head;
64-
volatile int _i_tail;
62+
void (*_onTransmit)(void);
6563
};
6664

6765
#undef I2S

0 commit comments

Comments
 (0)