Skip to content

Commit 34c9a7f

Browse files
committed
interrupt based write with ring buffer
1 parent 21157f0 commit 34c9a7f

File tree

3 files changed

+87
-17
lines changed

3 files changed

+87
-17
lines changed

libraries/I2S/examples/tone_generator/tone_generator.ino

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ void playWave(int16_t* buffer, uint16_t length, float frequency, float seconds)
108108
// Duplicate the sample so it's sent to both the left and right channel.
109109
// It appears the order is right channel, left channel if you want to write
110110
// stereo sound.
111+
while(I2S.availableForWrite() < 2);
112+
111113
I2S.write(sample);
112114
I2S.write(sample);
113115
}

libraries/I2S/src/I2S.cpp

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ I2SClass::I2SClass(SERCOM *p_sercom, uint8_t uc_index, uint8_t uc_pinSD, uint8_t
88
_uc_index(uc_index),
99
_uc_sd(uc_pinSD),
1010
_uc_sck(uc_pinSCK),
11-
_uc_fs(uc_pinFS)
11+
_uc_fs(uc_pinFS),
12+
13+
_i_head(0),
14+
_i_tail(0)
1215
{
16+
memset(_aui_buffer, 0, sizeof(_aui_buffer));
1317
}
1418

1519
int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, int driveClock)
@@ -31,6 +35,7 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, int driveClock
3135
case 16:
3236
case 24:
3337
case 32:
38+
_i_bits_per_sample = bitsPerSample;
3439
break;
3540

3641
default:
@@ -158,6 +163,15 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, int driveClock
158163
_i2s->CTRLA.bit.SEREN1 = 1;
159164
}
160165

166+
NVIC_EnableIRQ(I2S_IRQn);
167+
NVIC_SetPriority(I2S_IRQn, (1 << __NVIC_PRIO_BITS) - 1); /* set Priority */
168+
169+
if (_uc_index == 0) {
170+
_i2s->INTENSET.bit.TXRDY0 = 1;
171+
} else {
172+
_i2s->INTENSET.bit.TXRDY1 = 1;
173+
}
174+
161175
return 0;
162176
}
163177

@@ -187,17 +201,38 @@ void I2SClass::flush()
187201

188202
size_t I2SClass::write(uint8_t data)
189203
{
190-
return write((int)data);
204+
return write((int32_t)data);
191205
}
192206

193207
size_t I2SClass::write(const uint8_t *buffer, size_t size)
194208
{
195-
return 0;
209+
size_t written = 0;
210+
int bytesPerSample = (_i_bits_per_sample) / 8;
211+
212+
size = (size / bytesPerSample) * bytesPerSample;
213+
214+
while (size) {
215+
int32_t data;
216+
217+
memcpy(&data, buffer + written, bytesPerSample);
218+
written += bytesPerSample;
219+
size -= bytesPerSample;
220+
221+
if (write(data) == 0) {
222+
break;
223+
}
224+
}
225+
226+
return written;
196227
}
197228

198229
size_t I2SClass::availableForWrite()
199230
{
200-
return 0;
231+
if (_i_head >= _i_tail) {
232+
return I2S_BUFFER_SIZE - 1 - _i_head + _i_tail;
233+
} else {
234+
return _i_tail - _i_head - 1;
235+
}
201236
}
202237

203238
int I2SClass::read(int8_t data[], int size)
@@ -207,28 +242,51 @@ int I2SClass::read(int8_t data[], int size)
207242

208243
int I2SClass::write(short data)
209244
{
210-
return write((int)data);
245+
return write((int32_t)data);
211246
}
212247

213248
int I2SClass::write(int data)
214249
{
215-
if (_uc_index == 0) {
216-
while (!_i2s->INTFLAG.bit.TXRDY0);
217-
while (_i2s->SYNCBUSY.bit.DATA0);
218-
} else {
219-
while (!_i2s->INTFLAG.bit.TXRDY1);
220-
while (_i2s->SYNCBUSY.bit.DATA1);
250+
return write((int32_t)data);
251+
}
252+
253+
int I2SClass::write(int32_t data)
254+
{
255+
int i = ((uint32_t)(_i_head + 1) % I2S_BUFFER_SIZE);
256+
257+
if (i == _i_tail) {
258+
return 0;
221259
}
222260

223-
_i2s->DATA[_uc_index].bit.DATA = data;
261+
_aui_buffer[i] = data;
262+
_i_head = i;
263+
264+
return 1;
265+
}
266+
267+
void I2SClass::onService() {
224268

225269
if (_uc_index == 0) {
226-
_i2s->INTFLAG.bit.TXRDY0 = 1;
227-
} else {
228-
_i2s->INTFLAG.bit.TXRDY1 = 1;
270+
if (_i2s->INTFLAG.bit.TXRDY0) {
271+
int32_t data = 0;
272+
273+
if (_i_head != _i_tail) {
274+
data = _aui_buffer[_i_tail];
275+
_i_tail = ((uint32_t)(_i_tail + 1) % I2S_BUFFER_SIZE);
276+
}
277+
278+
while (_i2s->SYNCBUSY.bit.DATA0);
279+
_i2s->DATA[_uc_index].bit.DATA = data;
280+
281+
_i2s->INTFLAG.bit.TXRDY0 = 1;
282+
}
229283
}
284+
}
230285

231-
return 1;
286+
extern "C" {
287+
void I2S_Handler() {
288+
I2S.onService();
289+
}
232290
}
233291

234292
/*

libraries/I2S/src/I2S.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ typedef enum {
1010
I2S_DSP_MODE
1111
} i2s_mode_t;
1212

13+
#define I2S_BUFFER_SIZE 256
14+
1315
class I2SClass : public Stream
1416
{
1517
public:
@@ -29,9 +31,9 @@ class I2SClass : public Stream
2931

3032
virtual size_t availableForWrite();
3133

32-
3334
int write(short);
3435
int write(int);
36+
int write(int32_t);
3537

3638
int read(int8_t data[], int size);
3739
int read(int16_t data[], int size);
@@ -44,6 +46,8 @@ class I2SClass : public Stream
4446
void onReceive(void(*)(int));
4547
void onTransmit(void(*)(void));
4648

49+
void onService(void);
50+
4751
private:
4852
volatile I2s *_i2s = I2S;
4953

@@ -52,6 +56,12 @@ class I2SClass : public Stream
5256
uint8_t _uc_sd;
5357
uint8_t _uc_sck;
5458
uint8_t _uc_fs;
59+
60+
int _i_bits_per_sample;
61+
62+
int32_t _aui_buffer[I2S_BUFFER_SIZE];
63+
volatile int _i_head;
64+
volatile int _i_tail;
5565
};
5666

5767
#undef I2S

0 commit comments

Comments
 (0)