From 442c6cf0d6d6ca3486bdec98bc192345c4f20d1b Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Tue, 5 Nov 2024 05:15:44 -0600 Subject: [PATCH] nRF52: Better ADC/DAC config options - Use enADC and enDAC variables to control input/output instead of _useI2S parameter --- src/AutoAnalogAudio.h | 33 +++++++------- src/NRF52840/AutoAnalogAudio.cpp | 75 ++++++++++++++++++++++---------- src/avr/AutoAnalogAudio.cpp | 2 +- src/esp32/AutoAnalogAudio.cpp | 2 +- src/sam/AutoAnalogAudio.cpp | 2 +- 5 files changed, 70 insertions(+), 44 deletions(-) diff --git a/src/AutoAnalogAudio.h b/src/AutoAnalogAudio.h index ba41b1a..61531b3 100644 --- a/src/AutoAnalogAudio.h +++ b/src/AutoAnalogAudio.h @@ -1,6 +1,6 @@ /* AutoAnalogAudio streaming via DAC & ADC by TMRh20 - Copyright (C) 2016-2020 TMRh20 - tmrh20@gmail.com, github.com/TMRh20 + Copyright (C) 2016-2024 TMRh20 - tmrh20@gmail.com, github.com/TMRh20 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -49,13 +49,20 @@ class AutoAnalog AutoAnalog(); /** Setup the timer(s) + * + * Make sure to define your chosen pins before calling `begin();` * - * NRF52 Only: Call the below code prior to begin() to limit memory usage/buffer sizes: + * NRF52 Only: Call the below code prior to begin() to limit memory usage/buffer sizes: * @code * aaAudio.maxBufferSize = YOUR_AUDIO_BUFFER_SIZE; - * @endcode + * @endcode + * + * Third option: + * @param enADC 0 = Disabled, 1 = PDM input, 2 = I2S input, 3 = SAADC input + * @param enDAC 0 = Disabled, 1 = PWM output, 2 = I2S output + * @param _useI2S This is deprecated, use enADC and enDAC t control inputs/outputs */ - void begin(bool enADC, bool enDAC, uint8_t _useI2S = false); + void begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S = 0); /** * @note This function is no longer required and does nothing @@ -221,7 +228,10 @@ class AutoAnalog void set_callback(void(*function)(uint16_t *buf, uint32_t buf_len)); static bool adcReady; uint32_t sampleCounter; - //void DACC_Handler(); + uint8_t enableADC; + uint8_t enableDAC; + bool whichBuf; + bool adcWhichBuf; #endif #if defined (ARDUINO_ARCH_NRF52840) || defined (ARDUINO_ARCH_NRF52) || defined (DOXYGEN_FORCED) @@ -266,18 +276,7 @@ class AutoAnalog */ int8_t gain; - /** - * Enable I2S and/or SAADC on nRF52 - * By default this is disabled (analog output using PWM) - * - * @code - * aaAudio.begin(1,1,3); - * @endcode - * @param Set to 1 for I2S DAC, 2 for I2S ADC, 3 for both, 4 for SAADC only, 5 for SAADC + PWM Output, 6 for SAADC + I2S Output - */ - uint8_t useI2S; - - /** + /** * Configure the pins and ports for nRF52 using GPIO numbers before calling `begin()` * Defaults: * I2S_PIN_MCK = 2; diff --git a/src/NRF52840/AutoAnalogAudio.cpp b/src/NRF52840/AutoAnalogAudio.cpp index 7b5dbb8..4450149 100644 --- a/src/NRF52840/AutoAnalogAudio.cpp +++ b/src/NRF52840/AutoAnalogAudio.cpp @@ -114,10 +114,31 @@ AutoAnalog::AutoAnalog(){ I2S_PORT_SDIN = 0; } -void AutoAnalog::begin(bool enADC, bool enDAC, uint8_t _useI2S){ +void AutoAnalog::begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S){ maxBufferSize = maxBufferSize > 0 ? maxBufferSize : MAX_BUFFER_SIZE; - useI2S = _useI2S; + + // Fix for backward compatiblity with badly thought out changes + if(_useI2S == 1){ + enDAC = 2; + }else + if(_useI2S == 2){ + enADC = 2; + }else + if(_useI2S == 3){ + enADC = 2; + enDAC = 2; + }else + if(_useI2S == 4 || _useI2S == 5){ + enADC = 3; + }else + if(_useI2S == 6){ + enADC = 3; + enDAC = 2; + } + + enableADC = enADC; + enableDAC = enDAC; if(enADC){ adcBuf0 = reinterpret_cast(malloc(maxBufferSize * 2)); @@ -141,14 +162,16 @@ void AutoAnalog::begin(bool enADC, bool enDAC, uint8_t _useI2S){ void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo){ - if(useI2S == 0){ + if(enableDAC == 1){ NRF_PWM0->TASKS_STOP = 1; uint32_t timer = millis(); while(NRF_PWM0->EVENTS_STOPPED == 0){ if(millis() - timer > 1000){break;} } NRF_PWM0->COUNTERTOP = (((uint16_t)((16000000/sampRate))) << PWM_COUNTERTOP_COUNTERTOP_Pos); NRF_PWM0->TASKS_SEQSTART[0] = 1; - }else{ + } + + if(enableDAC == 2 || enableADC == 2){ if(stereo){ NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_STEREO << I2S_CONFIG_CHANNELS_CHANNELS_Pos; @@ -177,7 +200,8 @@ void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo){ NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_32X << I2S_CONFIG_RATIO_RATIO_Pos; } } - + + if(enableADC == 1){ if(sampRate <= 16000){ //Set default 16khz sample rate NRF_PDM->RATIO = ((PDM_RATIO_RATIO_Ratio80 << PDM_RATIO_RATIO_Pos) & PDM_RATIO_RATIO_Msk); @@ -220,9 +244,11 @@ void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo){ #endif } + } - NRF_SAADC->SAMPLERATE = 16000000 / sampRate / 2 | SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos; - + if(enableADC == 3){ + NRF_SAADC->SAMPLERATE = 16000000 / sampRate / 2 | SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos; + } } @@ -255,11 +281,10 @@ void AutoAnalog::disableAdcChannel(uint8_t pinAx){ } /****************************************************************************/ -bool adcWhichBuf = 0; void AutoAnalog::getADC(uint32_t samples){ - if(useI2S == 2 || useI2S == 3){ + if(enableADC == 2){ bool started = false; @@ -283,7 +308,7 @@ void AutoAnalog::getADC(uint32_t samples){ divider = 4; } - if(useI2S == 2 || useI2S == 3){ + if(enableDAC != 2){ //Only update MAXCNT if I2S output is disabled NRF_I2S->RXTXD.MAXCNT = samples / divider; } @@ -320,11 +345,12 @@ void AutoAnalog::getADC(uint32_t samples){ } }else - if(useI2S == 0){ + if(enableADC == 1){ while(!adcReady){__WFE();}; aSize = samples; adcReady = false; - }else{ + }else + if(enableADC == 3){ while(NRF_SAADC->EVENTS_END == 0){ } @@ -369,11 +395,9 @@ void AutoAnalog::getADC(uint32_t samples){ /****************************************************************************/ -bool whichBuf = 0; - void AutoAnalog::feedDAC(uint8_t dacChannel, uint32_t samples, bool startInterrupts){ - if(useI2S == 1 || useI2S == 3 || useI2S == 6){ + if(enableDAC == 2){ bool started = false; if(NRF_I2S->ENABLE == 0){ @@ -436,7 +460,8 @@ void AutoAnalog::feedDAC(uint8_t dacChannel, uint32_t samples, bool startInterru NRF_I2S->TASKS_START = 1; } - }else{ + }else + if(enableDAC == 1){ uint32_t timer = millis() + 1000; while(NRF_PWM0->EVENTS_SEQEND[0] == 0){ if(millis() > timer ){ NRF_PWM0->TASKS_SEQSTART[0] = 1; return; } @@ -495,7 +520,7 @@ return 1; void AutoAnalog::adcSetup(void){ -if(useI2S == 2 || useI2S == 3){ +if(enableADC == 2){ NRF_I2S->CONFIG.RXEN = (I2S_CONFIG_RXEN_RXEN_ENABLE << I2S_CONFIG_RXEN_RXEN_Pos); @@ -529,7 +554,7 @@ if(useI2S == 2 || useI2S == 3){ NRF_I2S->RXTXD.MAXCNT = 16;// / sizeof(uint32_t); }else -if(useI2S == 0){ +if(enableADC == 1){ @@ -632,7 +657,7 @@ if(useI2S == 0){ #endif }else -if(useI2S >= 4 && useI2S <= 6){ +if(enableADC == 3){ NRF_SAADC->CH[0].PSELP = dinPin << SAADC_CH_PSELP_PSELP_Pos; NRF_SAADC->CH[0].PSELN = dinPin << SAADC_CH_PSELN_PSELN_Pos; @@ -668,7 +693,7 @@ void AutoAnalog::adcInterrupts(bool enabled){ void AutoAnalog::dacSetup(void){ - if(useI2S == 1 || useI2S == 3 || useI2S == 6){ + if(enableDAC == 2){ // Enable transmission NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos); @@ -704,7 +729,8 @@ void AutoAnalog::dacSetup(void){ NRF_I2S->RXD.PTR = (uint32_t)dacBuf1; NRF_I2S->RXTXD.MAXCNT = 16;// / sizeof(uint32_t); - }else{ + }else + if(enableDAC == 1){ NRF_PWM0->PSEL.OUT[0] = (DEFAULT_PWM_PIN << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos | DEFAULT_PWM_PORT << PWM_PSEL_OUT_PORT_Pos); #if defined DEFAULT_PWM_PIN2 @@ -730,13 +756,14 @@ void AutoAnalog::dacSetup(void){ /****************************************************************************/ void AutoAnalog::disableDAC(bool withinTask){ - if(useI2S > 0){ + if(enableDAC == 2){ NRF_I2S->TASKS_STOP = 1; NRF_I2S->ENABLE = 0; - }else{ + }else + if(enableDAC == 1){ NRF_PWM0->TASKS_STOP = 1; } -} +} /****************************************************************************/ diff --git a/src/avr/AutoAnalogAudio.cpp b/src/avr/AutoAnalogAudio.cpp index ca610d2..8b9695d 100644 --- a/src/avr/AutoAnalogAudio.cpp +++ b/src/avr/AutoAnalogAudio.cpp @@ -59,7 +59,7 @@ AutoAnalog::AutoAnalog(){ adcSampleCounter = 0; } -void AutoAnalog::begin(bool enADC, bool enDAC, uint8_t _useI2S){ +void AutoAnalog::begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S){ if(enADC){ analogRead(A0); diff --git a/src/esp32/AutoAnalogAudio.cpp b/src/esp32/AutoAnalogAudio.cpp index c5d3493..9cd376b 100644 --- a/src/esp32/AutoAnalogAudio.cpp +++ b/src/esp32/AutoAnalogAudio.cpp @@ -110,7 +110,7 @@ void dacTask(void *args){ /****************************************************************************/ -void AutoAnalog::begin(bool enADC, bool enDAC, uint8_t _useI2S){ +void AutoAnalog::begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S){ i2s_mode_t myMode = (i2s_mode_t)I2S_MODE_MASTER; diff --git a/src/sam/AutoAnalogAudio.cpp b/src/sam/AutoAnalogAudio.cpp index f260fbd..4dbd076 100644 --- a/src/sam/AutoAnalogAudio.cpp +++ b/src/sam/AutoAnalogAudio.cpp @@ -54,7 +54,7 @@ AutoAnalog::AutoAnalog(){ adcNumSamples = 0; } -void AutoAnalog::begin(bool enADC, bool enDAC, uint8_t _useI2S){ +void AutoAnalog::begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S){ if(enADC){ adcSetup();