Skip to content

Commit 0432e2a

Browse files
committed
nRF52: Dynamic buffers, preliminary I2S input code
-Allocate internal ADC and DAC buffers dynamically. - Allow users to specify max buffer size (in # of samples) by setting `maxBufferSize` prior to calling begin - Adjust the `useI2S` variable so 1 is DAC output, 2 is ADC output and 3 is both - Preliminary code for I2S microphone (untested)
1 parent cd5e1cb commit 0432e2a

File tree

2 files changed

+125
-35
lines changed

2 files changed

+125
-35
lines changed

src/AutoAnalogAudio.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,13 @@ class AutoAnalog
4848

4949
AutoAnalog();
5050

51-
/** Setup the timer(s) */
51+
/** Setup the timer(s)
52+
*
53+
* NRF52 Only: Call the below code prior to begin() to limit memory usage/buffer sizes:
54+
* @code
55+
* aaAudio.maxBufferSize = YOUR_AUDIO_BUFFER_SIZE;
56+
* @endcode
57+
*/
5258
void begin(bool enADC, bool enDAC, uint8_t _useI2S = false);
5359

5460
/**
@@ -194,23 +200,23 @@ class AutoAnalog
194200
#if defined (ARDUINO_ARCH_NRF52840) || defined (ARDUINO_ARCH_NRF52) && !defined ARDUINO_NRF52840_FEATHER && defined __MBED__
195201
inline static uint8_t aCtr;
196202
inline static uint32_t aSize;
197-
inline static uint16_t *buf0 = NULL;
198-
inline static uint16_t *buf1 = NULL;
203+
inline static uint16_t *adcBuf0 = NULL;
204+
inline static uint16_t *adcBuf1 = NULL;
199205
inline static void (*_onReceive)(uint16_t *buf, uint32_t buf_len) = NULL;
200206
inline static void adcCallback(uint16_t *buf, uint32_t buf_len);
201207
inline static void set_callback(void(*function)(uint16_t *buf, uint32_t buf_len));
202208
inline static bool adcReady;
203-
inline static uint16_t dacBuf0[MAX_BUFFER_SIZE];
204-
inline static uint16_t dacBuf1[MAX_BUFFER_SIZE];
209+
inline static uint16_t *dacBuf0;
210+
inline static uint16_t *dacBuf1;
205211
inline static uint32_t sampleCounter;
206212

207213
#elif defined (ARDUINO_ARCH_NRF52840) || defined (ARDUINO_ARCH_NRF52) || defined (ARDUINO_NRF52840_FEATHER) && !defined __MBED__
208-
uint16_t dacBuf0[MAX_BUFFER_SIZE];
209-
uint16_t dacBuf1[MAX_BUFFER_SIZE];
214+
uint16_t *dacBuf0;
215+
uint16_t *dacBuf1;
210216
static uint8_t aCtr;
211217
static uint32_t aSize;
212-
static uint16_t *buf0;
213-
static uint16_t *buf1;
218+
static uint16_t *adcBuf0;
219+
static uint16_t *adcBuf1;
214220
static void (*_onReceive)(uint16_t *buf, uint32_t buf_len);
215221
static void adcCallback(uint16_t *buf, uint32_t buf_len);
216222
void set_callback(void(*function)(uint16_t *buf, uint32_t buf_len));
@@ -224,7 +230,7 @@ class AutoAnalog
224230
int dinPin;
225231
int clkPin;
226232
int8_t gain;
227-
bool useI2S;
233+
uint8_t useI2S;
228234
uint16_t I2S_PIN_MCK;
229235
uint8_t I2S_PORT_MCK;
230236
uint16_t I2S_PIN_SCK;
@@ -233,7 +239,9 @@ class AutoAnalog
233239
uint8_t I2S_PORT_LRCK;
234240
uint16_t I2S_PIN_SDOUT;
235241
uint8_t I2S_PORT_SDOUT;
236-
242+
uint16_t I2S_PIN_SDIN;
243+
uint8_t I2S_PORT_SDIN;
244+
uint32_t maxBufferSize;
237245
#endif
238246

239247

src/NRF52840/AutoAnalogAudio.cpp

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
bool AutoAnalog::adcReady;
3131
uint32_t AutoAnalog::aSize;
3232
uint8_t AutoAnalog::aCtr;
33-
uint16_t *AutoAnalog::buf0;
34-
uint16_t *AutoAnalog::buf1;
33+
uint16_t *AutoAnalog::adcBuf0;
34+
uint16_t *AutoAnalog::adcBuf1;
3535
void (*AutoAnalog::_onReceive)(uint16_t *buf, uint32_t buf_len);
3636
#endif
3737

@@ -79,10 +79,7 @@
7979
/* Public Functions */
8080
/****************************************************************************/
8181

82-
uint16_t adcBuf0[MAX_BUFFER_SIZE];
83-
uint16_t adcBuf1[MAX_BUFFER_SIZE];
8482
uint8_t analogCounter = 0;
85-
uint32_t buf_size = MAX_BUFFER_SIZE;
8683
uint16_t mycounter = 0;
8784
//int16_t sine_table[] = { 0, 0, 23170, 23170, 32767, 32767, 23170, 23170, 0, 0, -23170, -23170, -32768, -32768, -23170, -23170};
8885

@@ -97,12 +94,11 @@ AutoAnalog::AutoAnalog(){
9794
dacBuffer[i] = 0;
9895
}
9996

100-
aSize = MAX_BUFFER_SIZE;//&buf_size;
101-
buf0 = &adcBuf0[0];
102-
buf1 = &adcBuf1[0];
97+
aSize = MAX_BUFFER_SIZE;
10398
aCtr = 0;
10499
micOn = 0;
105100
sampleCounter = 0;
101+
maxBufferSize = 0;
106102
I2S_PIN_MCK = 2;
107103
I2S_PORT_MCK = 0;
108104
I2S_PIN_SCK = 3;
@@ -111,16 +107,28 @@ AutoAnalog::AutoAnalog(){
111107
I2S_PORT_LRCK = 0;
112108
I2S_PIN_SDOUT = 5;
113109
I2S_PORT_SDOUT = 0;
110+
I2S_PIN_SDIN = 4;
111+
I2S_PORT_SDIN = 0;
114112
}
115113

116114
void AutoAnalog::begin(bool enADC, bool enDAC, uint8_t _useI2S){
117115

116+
maxBufferSize = maxBufferSize > 0 ? maxBufferSize : MAX_BUFFER_SIZE;
117+
useI2S = _useI2S;
118+
118119
if(enADC){
120+
adcBuf0 = reinterpret_cast<uint16_t*>(malloc(maxBufferSize * 2));
121+
memset(adcBuf0,0,maxBufferSize * 2);
122+
adcBuf1 = reinterpret_cast<uint16_t*>(malloc(maxBufferSize * 2));
123+
memset(adcBuf1,0,maxBufferSize * 2);
119124
adcSetup();
120125
}
121126

122127
if(enDAC){
123-
useI2S = _useI2S;
128+
dacBuf0 = reinterpret_cast<uint16_t*>(malloc(maxBufferSize * 2));
129+
memset(dacBuf0,0,maxBufferSize * 2);
130+
dacBuf1 = reinterpret_cast<uint16_t*>(malloc(maxBufferSize * 2));
131+
memset(dacBuf1,0,maxBufferSize * 2);
124132
dacSetup();
125133
}
126134

@@ -243,9 +251,37 @@ void AutoAnalog::disableAdcChannel(uint8_t pinAx){
243251
/****************************************************************************/
244252

245253
void AutoAnalog::getADC(uint32_t samples){
246-
while(!adcReady){__WFE();};
247-
aSize = samples;
248-
adcReady = false;
254+
255+
if(useI2S == 2 || useI2S == 3){
256+
while(NRF_I2S->EVENTS_RXPTRUPD == 0){}
257+
258+
uint8_t divider = 2;
259+
if(adcBitsPerSample == 24){
260+
for(uint32_t i=0; i<samples; i++){
261+
adcBuffer16[i] = ((uint32_t)&adcBuf0[0]) >> 8;
262+
}
263+
}else
264+
if(adcBitsPerSample == 16){
265+
memcpy(adcBuffer16,adcBuf0,samples*2);
266+
}else
267+
if(adcBitsPerSample == 8){
268+
memcpy(adcBuffer, adcBuf0, samples);
269+
divider = 4;
270+
}
271+
NRF_I2S->RXD.PTR = (uint32_t)&adcBuf0[0];
272+
273+
274+
275+
if(useI2S == 2){
276+
NRF_I2S->RXTXD.MAXCNT = samples / divider;
277+
}
278+
NRF_I2S->EVENTS_RXPTRUPD = 0;
279+
280+
}else{
281+
while(!adcReady){__WFE();};
282+
aSize = samples;
283+
adcReady = false;
284+
}
249285
}
250286

251287
/****************************************************************************/
@@ -254,8 +290,13 @@ bool whichBuf = 0;
254290

255291
void AutoAnalog::feedDAC(uint8_t dacChannel, uint32_t samples, bool startInterrupts){
256292

257-
if(useI2S){
293+
if(useI2S == 1 || useI2S == 3){
258294

295+
if(NRF_I2S->ENABLE == 0){
296+
NRF_I2S->ENABLE = 1;
297+
NRF_I2S->TASKS_START = 1;
298+
}
299+
259300
while(NRF_I2S->EVENTS_TXPTRUPD == 0){}
260301
if(dacBitsPerSample == 8){
261302
if(whichBuf){
@@ -335,7 +376,47 @@ return 1;
335376
/****************************************************************************/
336377

337378
void AutoAnalog::adcSetup(void){
379+
380+
if(useI2S == 2 || useI2S == 3){
381+
382+
NRF_I2S->CONFIG.RXEN = (I2S_CONFIG_RXEN_RXEN_ENABLE << I2S_CONFIG_RXEN_RXEN_Pos);
383+
384+
// Enable MCK generator
385+
NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_ENABLE << I2S_CONFIG_MCKEN_MCKEN_Pos);
386+
387+
// Master mode, 16Bit, left aligned
388+
NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_MASTER << I2S_CONFIG_MODE_MODE_Pos;
389+
390+
NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16BIT << I2S_CONFIG_SWIDTH_SWIDTH_Pos;
391+
NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;
392+
NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos;
393+
NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_LEFT << I2S_CONFIG_ALIGN_ALIGN_Pos;
394+
395+
// Format = I2S
396+
NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos;
397+
398+
// Use stereo
399+
NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_LEFT << I2S_CONFIG_CHANNELS_CHANNELS_Pos;
400+
401+
// Configure pins
402+
NRF_I2S->PSEL.MCK = (I2S_PIN_MCK << I2S_PSEL_MCK_PIN_Pos) | (I2S_PSEL_MCK_CONNECT_Connected << I2S_PSEL_MCK_CONNECT_Pos) | (I2S_PORT_MCK << I2S_PSEL_MCK_PORT_Pos);
403+
NRF_I2S->PSEL.SCK = (I2S_PIN_SCK << I2S_PSEL_SCK_PIN_Pos) | (I2S_PSEL_SCK_CONNECT_Connected << I2S_PSEL_SCK_CONNECT_Pos) | (I2S_PORT_SCK << I2S_PSEL_SCK_PORT_Pos);
404+
NRF_I2S->PSEL.LRCK = (I2S_PIN_LRCK << I2S_PSEL_LRCK_PIN_Pos) | (I2S_PSEL_LRCK_CONNECT_Connected << I2S_PSEL_LRCK_CONNECT_Pos) | (I2S_PORT_LRCK << I2S_PSEL_LRCK_PORT_Pos);
405+
NRF_I2S->PSEL.SDIN = (I2S_PIN_SDOUT << I2S_PSEL_SDIN_PIN_Pos) | (I2S_PSEL_SDIN_CONNECT_Connected << I2S_PSEL_SDIN_CONNECT_Pos) | (I2S_PORT_SDIN << I2S_PSEL_SDIN_PORT_Pos);
406+
407+
408+
409+
// Configure data pointer
410+
NRF_I2S->RXD.PTR = (uint32_t)adcBuf0;
411+
NRF_I2S->RXTXD.MAXCNT = 16;// / sizeof(uint32_t);
412+
413+
NRF_I2S->ENABLE = 1;
414+
NRF_I2S->TASKS_START = 1;
338415

416+
}else{
417+
418+
419+
339420

340421
set_callback(adcCallback);
341422
dinPin = PIN_PDM_DIN;
@@ -440,6 +521,7 @@ void AutoAnalog::adcSetup(void){
440521
nrf_pdm_task_trigger(myPDM,NRF_PDM_TASK_START);
441522

442523
#endif
524+
} // USE_I2S
443525
}
444526

445527
/****************************************************************************/
@@ -452,7 +534,7 @@ void AutoAnalog::adcInterrupts(bool enabled){
452534

453535
void AutoAnalog::dacSetup(void){
454536

455-
if(useI2S){
537+
if(useI2S == 1 || useI2S == 3){
456538
// Enable transmission
457539
NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos);
458540

@@ -477,7 +559,7 @@ void AutoAnalog::dacSetup(void){
477559
NRF_I2S->PSEL.MCK = (I2S_PIN_MCK << I2S_PSEL_MCK_PIN_Pos) | (I2S_PSEL_MCK_CONNECT_Connected << I2S_PSEL_MCK_CONNECT_Pos) | (I2S_PORT_MCK << I2S_PSEL_MCK_PORT_Pos);
478560
NRF_I2S->PSEL.SCK = (I2S_PIN_SCK << I2S_PSEL_SCK_PIN_Pos) | (I2S_PSEL_SCK_CONNECT_Connected << I2S_PSEL_SCK_CONNECT_Pos) | (I2S_PORT_SCK << I2S_PSEL_SCK_PORT_Pos);
479561
NRF_I2S->PSEL.LRCK = (I2S_PIN_LRCK << I2S_PSEL_LRCK_PIN_Pos) | (I2S_PSEL_LRCK_CONNECT_Connected << I2S_PSEL_LRCK_CONNECT_Pos) | (I2S_PORT_LRCK << I2S_PSEL_LRCK_PORT_Pos);
480-
NRF_I2S->PSEL.SDOUT = (I2S_PIN_SDOUT << I2S_PSEL_SDOUT_PIN_Pos) | (I2S_PSEL_SDOUT_CONNECT_Connected << I2S_PSEL_LRCK_CONNECT_Pos) | (I2S_PORT_SDOUT << I2S_PSEL_SDOUT_PORT_Pos);
562+
NRF_I2S->PSEL.SDOUT = (I2S_PIN_SDOUT << I2S_PSEL_SDOUT_PIN_Pos) | (I2S_PSEL_SDOUT_CONNECT_Connected << I2S_PSEL_SDOUT_CONNECT_Pos) | (I2S_PORT_SDOUT << I2S_PSEL_SDOUT_PORT_Pos);
481563

482564

483565
//NRF_I2S->INTENSET = I2S_INTEN_TXPTRUPD_Enabled << I2S_INTEN_TXPTRUPD_Pos;
@@ -522,7 +604,7 @@ void AutoAnalog::dacSetup(void){
522604
/****************************************************************************/
523605

524606
void AutoAnalog::disableDAC(bool withinTask){
525-
if(useI2S){
607+
if(useI2S > 0){
526608
NRF_I2S->TASKS_STOP = 1;
527609
NRF_I2S->ENABLE = 0;
528610
}else{
@@ -569,17 +651,17 @@ if (nrf_pdm_event_check(NRF_PDM_EVENT_STARTED)) {
569651
// switch to fill
570652

571653
if (AutoAnalog::aCtr) {
572-
nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::buf0), AutoAnalog::aSize);
654+
nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::adcBuf0), AutoAnalog::aSize);
573655
if(AutoAnalog::_onReceive){
574656
NVIC_DisableIRQ(PDM_IRQn);
575-
AutoAnalog::_onReceive(AutoAnalog::buf1, AutoAnalog::aSize);
657+
AutoAnalog::_onReceive(AutoAnalog::adcBuf1, AutoAnalog::aSize);
576658
NVIC_EnableIRQ(PDM_IRQn);
577659
}
578660
} else {
579-
nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::buf1), AutoAnalog::aSize);
661+
nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::adcBuf1), AutoAnalog::aSize);
580662
if(AutoAnalog::_onReceive){
581663
NVIC_DisableIRQ(PDM_IRQn);
582-
AutoAnalog::_onReceive(AutoAnalog::buf0, AutoAnalog::aSize);
664+
AutoAnalog::_onReceive(AutoAnalog::adcBuf0, AutoAnalog::aSize);
583665
NVIC_EnableIRQ(PDM_IRQn);
584666
}
585667
}
@@ -607,17 +689,17 @@ if (nrf_pdm_event_check(myPDM,NRF_PDM_EVENT_STARTED)) {
607689
// switch to fill
608690

609691
if (AutoAnalog::aCtr) {
610-
nrf_pdm_buffer_set(myPDM,(uint32_t*)(AutoAnalog::buf0), AutoAnalog::aSize);
692+
nrf_pdm_buffer_set(myPDM,(uint32_t*)(AutoAnalog::adcBuf0), AutoAnalog::aSize);
611693
if(AutoAnalog::_onReceive){
612694
NVIC_DisableIRQ(PDM_IRQn);
613-
AutoAnalog::_onReceive(AutoAnalog::buf1, AutoAnalog::aSize);
695+
AutoAnalog::_onReceive(AutoAnalog::adcBuf1, AutoAnalog::aSize);
614696
NVIC_EnableIRQ(PDM_IRQn);
615697
}
616698
} else {
617-
nrf_pdm_buffer_set(myPDM,(uint32_t*)(AutoAnalog::buf1), AutoAnalog::aSize);
699+
nrf_pdm_buffer_set(myPDM,(uint32_t*)(AutoAnalog::adcBuf1), AutoAnalog::aSize);
618700
if(AutoAnalog::_onReceive){
619701
NVIC_DisableIRQ(PDM_IRQn);
620-
AutoAnalog::_onReceive(AutoAnalog::buf0, AutoAnalog::aSize);
702+
AutoAnalog::_onReceive(AutoAnalog::adcBuf0, AutoAnalog::aSize);
621703
NVIC_EnableIRQ(PDM_IRQn);
622704
}
623705
}

0 commit comments

Comments
 (0)