From b4ac0622d258ae6666ba9fbae5bc675e1e0d8b36 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Sun, 2 Aug 2026 11:27:05 -0600 Subject: [PATCH 01/16] Initial Uno R4 support - Support 8-bit and 16-bit audio playback via DAC on A0 --- src/AutoAnalogAudio.h | 32 +- src/AutoAnalog_config.h | 4 + src/RA41M/AutoAnalogAudio.cpp | 1104 +++++++++++++++++++++++++++++++++ 3 files changed, 1135 insertions(+), 5 deletions(-) create mode 100644 src/RA41M/AutoAnalogAudio.cpp diff --git a/src/AutoAnalogAudio.h b/src/AutoAnalogAudio.h index 8f69930..02f374a 100644 --- a/src/AutoAnalogAudio.h +++ b/src/AutoAnalogAudio.h @@ -91,14 +91,17 @@ class AutoAnalog * 8-bit user samples are loaded directly into this buffer before calling feedDAC()
* @see dacBitsPerSample */ + #if !defined ARDUINO_ARCH_RENESAS uint8_t dacBuffer[MAX_BUFFER_SIZE]; - + #else + static uint8_t dacBuffer[MAX_BUFFER_SIZE]; + #endif /** ADC Data buffer for 8-bit samples * * 8-bit samples are read directly from this buffer after calling getADC()
* @see adcBitsPerSample */ - #if !defined(ARDUINO_ARCH_NRF52840) && !defined(ARDUINO_ARCH_NRF52) && !defined ARDUINO_NRF52840_FEATHER && !defined ARDUINO_NRF54L15 + #if !defined(ARDUINO_ARCH_NRF52840) && !defined(ARDUINO_ARCH_NRF52) && !defined ARDUINO_NRF52840_FEATHER && !defined ARDUINO_NRF54L15 && !defined ARDUINO_ARCH_RENESAS uint8_t adcBuffer[MAX_BUFFER_SIZE]; #elif defined __MBED__ inline static uint8_t adcBuffer[MAX_BUFFER_SIZE]; @@ -118,7 +121,7 @@ class AutoAnalog * 10 or 12-bit samples are read directly from this buffer after calling getADC()
* @see adcBitsPerSample */ - #if !defined(ARDUINO_ARCH_NRF52840) && !defined(ARDUINO_ARCH_NRF52) && !defined ARDUINO_NRF52840_FEATHER && !defined ARDUINO_NRF54L15 + #if !defined(ARDUINO_ARCH_NRF52840) && !defined(ARDUINO_ARCH_NRF52) && !defined ARDUINO_NRF52840_FEATHER && !defined ARDUINO_NRF54L15 && !defined ARDUINO_ARCH_RENESAS uint16_t adcBuffer16[MAX_BUFFER_SIZE]; #elif defined __MBED__ inline static uint16_t adcBuffer16[MAX_BUFFER_SIZE]; @@ -149,7 +152,7 @@ class AutoAnalog * adcBuffer[] is an 8-bit buffer used solely for your 8-bit samples
* adcBuffer16[] is a 16-bit buffer used solely for placing your 10 and 12-bit samples
**/ - #if !defined(ARDUINO_ARCH_NRF52840) && !defined(ARDUINO_ARCH_NRF52) && !defined ARDUINO_NRF52840_FEATHER && !defined ARDUINO_NRF54L15 + #if !defined(ARDUINO_ARCH_NRF52840) && !defined(ARDUINO_ARCH_NRF52) && !defined ARDUINO_NRF52840_FEATHER && !defined ARDUINO_NRF54L15 && !defined ARDUINO_ARCH_RENESAS uint8_t adcBitsPerSample; #elif defined __MBED__ inline static uint8_t adcBitsPerSample; @@ -245,9 +248,28 @@ class AutoAnalog uint8_t enableDAC; bool whichBuf; static bool adcWhichBuf; + + #elif defined ARDUINO_ARCH_RENESAS + static volatile uint16_t* dacBuf0; + static volatile uint16_t* dacBuf1; + volatile static uint8_t aCtr; + static volatile uint32_t aSize; + static uint16_t* adcBuf0; + static uint16_t* adcBuf1; + static void (*_onReceive)(uint16_t* buf, uint32_t buf_len); + static void adcCallback(uint16_t* buf, uint32_t buf_len); + void set_callback(void (*function)(uint16_t* buf, uint32_t buf_len)); + static bool adcReady; + uint32_t sampleCounter; + uint8_t enableADC; + uint8_t enableDAC; + bool whichBuf; + static bool adcWhichBuf; + static volatile uint32_t sCounter; + #endif - #if defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52) || defined ARDUINO_NRF54L15 || defined(DOXYGEN_FORCED) + #if defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52) || defined ARDUINO_NRF54L15 || defined ARDUINO_ARCH_RENESAS || defined(DOXYGEN_FORCED) /**@}*/ /** * @name Section for nRF52 Devices Only diff --git a/src/AutoAnalog_config.h b/src/AutoAnalog_config.h index 9af245e..bea06e7 100644 --- a/src/AutoAnalog_config.h +++ b/src/AutoAnalog_config.h @@ -22,6 +22,10 @@ #define MAX_BUFFER_SIZE 256 + #elif defined (ARDUINO_ARCH_RENESAS) + + #define MAX_BUFFER_SIZE 256 + #elif defined ESP32 || defined ARDUINO_ARCH_NRF52840 || defined (ARDUINO_ARCH_NRF52) || defined ARDUINO_NRF52840_FEATHER || defined ARDUINO_NRF54L15 #define MAX_BUFFER_SIZE 6400 diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp new file mode 100644 index 0000000..968fa97 --- /dev/null +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -0,0 +1,1104 @@ +/* +AutoAnalogAudio streaming via DAC & ADC by TMRh20 +Copyright (C) 2016 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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/****************************************************************************/ + +#if defined(ARDUINO_ARCH_RENESAS) + + #include "../AutoAnalogAudio.h" + #include "FspTimer.h" + #include "r_timer_api.h" + FspTimer high_speed_timer; + volatile bool toggle_state = false; + +uint16_t AutoAnalog::adcBuffer16[MAX_BUFFER_SIZE]; +uint8_t AutoAnalog::adcBuffer[MAX_BUFFER_SIZE]; +bool AutoAnalog::adcReady; +bool AutoAnalog::adcWhichBuf; +uint8_t AutoAnalog::adcBitsPerSample; +volatile uint32_t AutoAnalog::aSize; +volatile uint8_t AutoAnalog::aCtr; +uint16_t* AutoAnalog::adcBuf0; +uint16_t* AutoAnalog::adcBuf1; +volatile uint16_t* AutoAnalog::dacBuf0; +volatile uint16_t* AutoAnalog::dacBuf1; +void (*AutoAnalog::_onReceive)(uint16_t* buf, uint32_t buf_len); +uint8_t AutoAnalog::dacBuffer[MAX_BUFFER_SIZE]; +volatile uint32_t AutoAnalog::sCounter = 0; +void dac_callback(timer_callback_args_t *p_args); + +/******************* USER DEFINES - Configure pins etc here *****************/ + #define DEFAULT_PDM_GAIN 40 + + /* I2s default config MAX98357A Breakout also needs SD pin set HIGH + I2S_PIN_MCK 2 // Not used with MAX98357A + I2S_PORT_MCK 0 + I2S_PIN_SCK 3 // BCLK + I2S_PORT_SCK 0 + I2S_PIN_LRCK 29 // LRCK + I2S_PORT_LRCK 0 + I2S_PIN_SDOUT 5 // GPIO Pin numbers + I2S_PORT_SDOUT 0 + */ + + /* PWM Config */ + #define DEFAULT_PWM_PIN 11 // GPIO Pin number + #define DEFAULT_PWM_PORT 1 // On XIAO port 0 is for pins 1-5 port 1 is for all higher pins + //#define DEFAULT_PWM_PIN2 4 //Enable a second output pin + //#define DEFAULT_PWM_PORT2 0 + + #ifndef PIN_PDM_DIN // Arduino pin numbers + #define PIN_PDM_DIN 35 + //#define PIN_PDM_CLK 36 + #define PIN_PDM_PWR -1 + #endif + +/****************************************************************************/ +/* Public Functions */ +/****************************************************************************/ + +uint8_t analogCounter = 0; +uint16_t mycounter = 0; + +extern "C" { + void SAADC_IRQHandler(void); +} + + +AutoAnalog::AutoAnalog() +{ + + adcReady = true; + adcBitsPerSample = 8; + //pwrPin = PIN_PDM_PWR; + //dinPin = PIN_PDM_DIN; + //clkPin = PIN_PDM_CLK; + gain = -1; + + dacBitsPerSample = 8; + autoAdjust = true; + for (int i = 0; i < MAX_BUFFER_SIZE; i++) { + dacBuffer[i] = 0; + } + + aSize = MAX_BUFFER_SIZE; + aCtr = 0; + sampleCounter = 0; + maxBufferSize = 0; + dacBuffersAllocated = false; + I2S_PIN_MCK = 8; + I2S_PORT_MCK = 2; + I2S_PIN_SCK = 5; + I2S_PORT_SCK = 1; + I2S_PIN_LRCK = 7; + I2S_PORT_LRCK = 1; + I2S_PIN_SDOUT = 11; + I2S_PORT_SDOUT = 1; + I2S_PIN_SDIN = 10; + I2S_PORT_SDIN = 1; + manualI2S = false; +} + + + +void AutoAnalog::begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S) +{ + + maxBufferSize = maxBufferSize > 0 ? maxBufferSize : MAX_BUFFER_SIZE; + + // 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) { + if (!adcBuffersAllocated) { + adcBuffersAllocated = true; + adcBuf0 = reinterpret_cast(malloc(maxBufferSize * 2)); + memset(adcBuf0, 0, maxBufferSize * 2); + adcBuf1 = reinterpret_cast(malloc(maxBufferSize * 2)); + memset(adcBuf1, 0, maxBufferSize * 2); + } + adcSetup(); + } + + if (enDAC) { + if (!dacBuffersAllocated) { + dacBuffersAllocated = true; + dacBuf0 = reinterpret_cast(malloc(maxBufferSize * 2)); + memset(const_cast(reinterpret_cast(dacBuf0)), 0, maxBufferSize * 2); + dacBuf1 = reinterpret_cast(malloc(maxBufferSize * 2)); + memset(const_cast(reinterpret_cast(dacBuf1)), 0, maxBufferSize * 2); + } + dacSetup(); + Serial.println("Dac is setup"); + } +} + +/****************************************************************************/ + +void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo) +{ + + if (enableDAC == 3) { + high_speed_timer.stop(); + + uint8_t timer_type = GPT_TIMER; + int8_t timer_channel = 3; + + high_speed_timer.begin( + TIMER_MODE_PERIODIC, // Fire continuously at the specified interval + timer_type, // Use the General PWM Timer peripheral block + timer_channel, // Selected hardware channel channel + sampRate * (stereo + 1), // Target Frequency in Hz (16 kHz) + 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) + dac_callback // Name of your ISR function to execute + ); + + high_speed_timer.setup_overflow_irq(); + high_speed_timer.open(); + high_speed_timer.start(); + } + + + /*if (enableDAC == 1) { + NRF_PWM20->TASKS_STOP = 1; + uint32_t timer = millis(); + while (NRF_PWM20->EVENTS_STOPPED == 0) { + if (millis() - timer > 1000) { + break; + } + } + + NRF_PWM20->COUNTERTOP = (((uint16_t)((16000000 / sampRate))) << PWM_COUNTERTOP_COUNTERTOP_Pos); + NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; + } + + if (enableDAC == 2 || enableADC == 2) { + + if (stereo) { + NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Stereo << I2S_CONFIG_CHANNELS_CHANNELS_Pos; + } + else { + NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Left << I2S_CONFIG_CHANNELS_CHANNELS_Pos; + } + + if (sampRate <= 16000) { + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; + } + else if (sampRate <= 22500) { + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV15 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; + } + else if (sampRate <= 24000) { + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV11 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; + } + else if (sampRate <= 32000) { + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_64X << I2S_CONFIG_RATIO_RATIO_Pos; + } + else if (sampRate <= 45000) { + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV23 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_32X << I2S_CONFIG_RATIO_RATIO_Pos; + } + + } + + if (enableADC == 1) { + struct PwmTiming* myTiming; + computePwmTiming(sampRate, myTiming); + myPDM->PRESCALER = myTiming->prescaler; + } + + if (enableADC == 3) { + NRF_SAADC->SAMPLERATE = 16000000 / sampRate / 2 | SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos; + }*/ +} + +/****************************************************************************/ + +void AutoAnalog::triggerADC() +{ +} + +/****************************************************************************/ + +void AutoAnalog::enableAdcChannel(uint8_t pinAx) +{ + #if defined __MBED__ + //nrf_pdm_enable(); + #else + //nrf_pdm_enable(myPDM); + #endif +} + +/****************************************************************************/ + +void AutoAnalog::disableAdcChannel(uint8_t pinAx) +{ + #if defined __MBED__ + //nrf_pdm_disable(); + #else + //nrf_pdm_disable(myPDM); + #endif +} + +/****************************************************************************/ + +void AutoAnalog::getADC(uint32_t samples) +{ + + /*if (enableADC == 2) { + + bool started = false; + if (NRF_I2S->ENABLE == 0) { + NRF_I2S->ENABLE = 1; + started = true; + } + else { + uint32_t timeout = millis() + 1000; + while (NRF_I2S->EVENTS_RXPTRUPD == 0) { + if (millis() > timeout) { + return; + } + } + } + + if (adcWhichBuf == 0) { + NRF_I2S->RXD.PTR = (uint32_t)&adcBuf0[0]; + } + else { + NRF_I2S->RXD.PTR = (uint32_t)&adcBuf1[0]; + } + uint8_t divider = 2; + if (adcBitsPerSample == 24 || adcBitsPerSample == 32) { + divider = 4; + } + else if (adcBitsPerSample == 8) { + divider = 1; + } + + if (enableDAC != 2) { // Only update MAXCNT if I2S output is disabled + NRF_I2S->RXTXD.MAXCNT = samples * divider; + } + + NRF_I2S->EVENTS_RXPTRUPD = 0; + + if (adcBitsPerSample == 24 || adcBitsPerSample == 32) { + if (adcBitsPerSample == 24 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + }else + if (adcBitsPerSample == 32 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + } + + if (adcWhichBuf == 0) { + memcpy(adcBuffer16, adcBuf0, samples * 4); + } + else { + memcpy(adcBuffer16, adcBuf1, samples * 4); + } + } + else if (adcBitsPerSample == 16) { + if (adcWhichBuf == 0) { + memcpy(adcBuffer16, adcBuf0, samples * 2); + } + else { + memcpy(adcBuffer16, adcBuf1, samples * 2); + } + } + else if (adcBitsPerSample == 8) { + if (adcWhichBuf == 0) { + //memcpy(adcBuffer, adcBuf0, samples); + for(int i=0; i> 6) - 127; + } + } + else { + //memcpy(adcBuffer, adcBuf1, samples); + for(int i=0; i> 6) - 127; + } + } + } + + adcWhichBuf = !adcWhichBuf; + if (started) { + NRF_I2S->TASKS_START = 1; + } + } + else if (enableADC == 1) { + while (!adcReady) { + __WFE(); + }; + aSize = samples; + adcReady = false; + } + else if (enableADC == 3) { + while (!adcReady) {Serial.println("p"); + } + aSize = samples; + }*/ +} + +/****************************************************************************/ + +void AutoAnalog::feedDAC(uint8_t dacChannel, uint32_t samples, bool startInterrupts) +{ + + if(enableDAC == 3){ + + //memcpy(dacBuf0,dacBuffer,samples); + if(aCtr == 1){ + if(dacBitsPerSample == 8){ + for(int i=0; i> 4) + 2048; + } + } + }else{ + if(dacBitsPerSample == 8){ + for(int i=0; i> 4) + 2048; + } + } + } + while(sCounter < samples){} + aCtr = (aCtr + 1) % 2; + aSize = samples; + sCounter = 0; + } + + /*if (enableDAC == 2) { + + bool started = false; + if (NRF_I2S->ENABLE == 0) { + NRF_I2S->ENABLE = 1; + started = true; + } + else { + uint32_t timeout = millis() + 1000; + while (NRF_I2S->EVENTS_TXPTRUPD == 0) { + if (millis() > timeout) { + return; + } + } + } + + if (dacBitsPerSample == 8) { + if (whichBuf) { + for (uint32_t i = 0; i < samples; i++) { + dacBuf0[i] = dacBuffer[i] << 7; + } + NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; + } + else { + for (uint32_t i = 0; i < samples; i++) { + dacBuf1[i] = dacBuffer[i] << 7; + } + NRF_I2S->TXD.PTR = (uint32_t)&dacBuf1[0]; + } + } + else if (dacBitsPerSample == 16) { + if (whichBuf) { + memcpy(dacBuf0, dacBuffer16, samples * 2); + NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; + } + else { + memcpy(dacBuf1, dacBuffer16, samples * 2); + NRF_I2S->TXD.PTR = (uint32_t)&dacBuf1[0]; + } + } + else if (dacBitsPerSample == 24 || dacBitsPerSample == 32) { + if (dacBitsPerSample == 24 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + }else + if (dacBitsPerSample == 32 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + }else + if (dacBitsPerSample == 16 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + } + + if (whichBuf) { + memcpy(dacBuf0, dacBuffer16, samples * 4); + NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; + } + else { + memcpy(dacBuf1, dacBuffer16, samples * 4); + NRF_I2S->TXD.PTR = (uint32_t)&dacBuf1[0]; + } + } + + whichBuf = !whichBuf; + + uint8_t divider = 2; + if (dacBitsPerSample == 16) { + divider = 2; + } + else if (dacBitsPerSample == 24 || dacBitsPerSample == 32) { + divider = 4; + } + + NRF_I2S->RXTXD.MAXCNT = samples * divider; + NRF_I2S->EVENTS_TXPTRUPD = 0; + + if (started) { + NRF_I2S->TASKS_START = 1; + } + } + else if (enableDAC == 1) { + uint32_t timer = millis() + 1000; + while (NRF_PWM20->EVENTS_DMA.SEQ[0].END == 0) { + if (millis() > timer) { + NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; + return; + } + } + NRF_PWM20->EVENTS_DMA.SEQ[0].END = 0; + + if (dacBitsPerSample > 8) { + if (whichBuf) { + memcpy(dacBuf0, dacBuffer16, samples * 2); + } + else { + memcpy(dacBuf1, dacBuffer16, samples * 2); + } + } + else { + if (whichBuf) { + for (uint32_t i = 0; i < samples; i++) { + dacBuf0[i] = (uint16_t)(dacBuffer[i] << 1); + } + } + else { + for (uint32_t i = 0; i < samples; i++) { + dacBuf1[i] = (uint16_t)(dacBuffer[i] << 1); + } + } + } + if (whichBuf) { + NRF_PWM20->DMA.SEQ[0].PTR = ((uint32_t)(&dacBuf0[0]) << PWM_DMA_SEQ_PTR_PTR_Pos); + } + else { + NRF_PWM20->DMA.SEQ[0].PTR = ((uint32_t)(&dacBuf1[0]) << PWM_DMA_SEQ_PTR_PTR_Pos); + } + whichBuf = !whichBuf; + + NRF_PWM20->DMA.SEQ[0].MAXCNT = (samples << PWM_DMA_SEQ_MAXCNT_MAXCNT_Pos); + NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; + }*/ +} + +/****************************************************************************/ +/* Private Functions */ +/****************************************************************************/ + +void AutoAnalog::dacBufferStereo(uint8_t dacChannel) +{ +} + +/****************************************************************************/ + +uint32_t AutoAnalog::frequencyToTimerCount(uint32_t frequency) +{ + + return 1; +} + +/****************************************************************************/ + +void AutoAnalog::startPwmI2sTimers() +{ + /* // 1. Setup BCLK (WS * 64) + NRF_PWM20->PSEL.OUT[0] = I2S_PIN_SCK | I2S_PORT_SCK << 5 | 0 << 31; + NRF_PWM20->ENABLE = 1; + NRF_PWM20->MODE = PWM_MODE_UPDOWN_Up; + NRF_PWM20->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // 16MHz + NRF_PWM20->COUNTERTOP = 8; // 16MHz / 8 = 2MHz + static uint16_t bclk_seq[] = {4}; // 50% duty cycle + NRF_PWM20->DECODER = PWM_DECODER_LOAD_Common; + NRF_PWM20->DMA.SEQ[0].PTR = (uint32_t)bclk_seq; + NRF_PWM20->DMA.SEQ[0].MAXCNT = 1; + NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; + + // 2. Setup WS (31.25kHz) + NRF_PWM21->PSEL.OUT[0] = I2S_PIN_LRCK | I2S_PORT_LRCK << 5 | 0 << 31; + NRF_PWM21->ENABLE = 1; + NRF_PWM21->MODE = PWM_MODE_UPDOWN_Up; + NRF_PWM21->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; + NRF_PWM21->COUNTERTOP = 512; // 16MHz / 512 = 31.25kHz + static uint16_t ws_seq[] = {128}; // 50% duty cycle + NRF_PWM21->DECODER = PWM_DECODER_LOAD_Common; + NRF_PWM21->DMA.SEQ[0].PTR = (uint32_t)ws_seq; + NRF_PWM21->DMA.SEQ[0].MAXCNT = 1; + NRF_PWM21->TASKS_DMA.SEQ[0].START = 1; + */ +} + +/****************************************************************************/ +#define ARM_VTOR (*((volatile uint32_t *)0xE000ED08)) + +void AutoAnalog::adcSetup(void) +{ +/* + if (enableADC == 2) { + NRF_I2S->TASKS_STOP = 1; + NRF_I2S->ENABLE = 0; + + NRF_I2S->CONFIG.RXEN = (I2S_CONFIG_RXEN_RXEN_Enabled << I2S_CONFIG_RXEN_RXEN_Pos); + + if (enableDAC != 2) { + NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_Disabled << I2S_CONFIG_TXEN_TXEN_Pos); + } + + if (manualI2S) { + // Slave mode, 16Bit, left aligned + NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; + NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Right << I2S_CONFIG_ALIGN_ALIGN_Pos; + NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; + } + else { + NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; + NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left << I2S_CONFIG_ALIGN_ALIGN_Pos; + NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; + } + + NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Left << I2S_CONFIG_CHANNELS_CHANNELS_Pos; + + // Configure pins + 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); + 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); + 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); + NRF_I2S->PSEL.SDIN = (I2S_PIN_SDIN << I2S_PSEL_SDIN_PIN_Pos) | (I2S_PSEL_SDIN_CONNECT_Connected << I2S_PSEL_SDIN_CONNECT_Pos) | (I2S_PORT_SDIN << I2S_PSEL_SDIN_PORT_Pos); + + // Configure data pointer + NRF_I2S->RXD.PTR = (uint32_t)adcBuf0; + NRF_I2S->RXTXD.MAXCNT = 16; // / sizeof(uint32_t); + } + /*else if (enableADC == 1) { + + set_callback(adcCallback); + + // Enable high frequency oscillator if not already enabled + if (NRF_CLOCK->EVENTS_XOSTARTED == 0) { + NRF_CLOCK->TASKS_XOSTART = 1; + while (NRF_CLOCK->EVENTS_XOSTARTED == 0) { + } + } + + // Set default 16khz sample rate + NRF_PDM->RATIO = ((PDM_RATIO_RATIO_Ratio80 << PDM_RATIO_RATIO_Pos) & PDM_RATIO_RATIO_Msk); + + #if defined __MBED__ + + nrf_pdm_clock_set(NRF_PDM_FREQ_1280K); + // Set default channel mono + nrf_pdm_mode_set(NRF_PDM_MODE_MONO, NRF_PDM_EDGE_LEFTFALLING); + if (gain == -1) { + gain = DEFAULT_PDM_GAIN; + } + nrf_pdm_gain_set(gain, gain); + + pinMode(clkPin, OUTPUT); + digitalWrite(clkPin, LOW); + + pinMode(dinPin, INPUT); + + nrf_pdm_psel_connect(digitalPinToPinName(clkPin), digitalPinToPinName(dinPin)); + + // Enable PDM interrupts and clear events + nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); + nrf_pdm_event_clear(NRF_PDM_EVENT_END); + nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED); + nrf_pdm_int_enable(NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED); + + // Turn on the mic + if (pwrPin > -1) { + pinMode(pwrPin, OUTPUT); + digitalWrite(pwrPin, HIGH); + } + else { + } + + // set the PDM IRQ priority and enable + NVIC_SetPriority(PDM_IRQn, PDM_IRQ_PRIORITY); + NVIC_ClearPendingIRQ(PDM_IRQn); + NVIC_EnableIRQ(PDM_IRQn); + + // enable and trigger start task + nrf_pdm_enable(); + nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); + nrf_pdm_task_trigger(NRF_PDM_TASK_START); + + #else // MBED / Non-Mbed + + nrf_pdm_clock_set(myPDM, NRF_PDM_FREQ_1280K); + + // Set default channel mono + nrf_pdm_mode_set(myPDM, NRF_PDM_MODE_MONO, NRF_PDM_EDGE_LEFTFALLING); + if (gain == -1) { + gain = DEFAULT_PDM_GAIN; + } + nrf_pdm_gain_set(myPDM, gain, gain); + + pinMode(clkPin, OUTPUT); + digitalWrite(clkPin, LOW); + + pinMode(dinPin, INPUT); + + nrf_pdm_psel_connect(myPDM, digitalPinToPinName(clkPin), digitalPinToPinName(dinPin)); + + // Enable PDM interrupts and clear events + nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STARTED); + nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_END); + nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STOPPED); + nrf_pdm_int_enable(myPDM, NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED); + + // Turn on the mic + if (pwrPin > -1) { + pinMode(pwrPin, OUTPUT); + digitalWrite(pwrPin, HIGH); + } + else { + } + + // set the PDM IRQ priority and enable + NVIC_SetPriority(PDM_IRQn, PDM_IRQ_PRIORITY); + NVIC_ClearPendingIRQ(PDM_IRQn); + NVIC_EnableIRQ(PDM_IRQn); + + // enable and trigger start task + nrf_pdm_enable(myPDM); + nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STARTED); + nrf_pdm_task_trigger(myPDM, NRF_PDM_TASK_START); + + #endif + }*/ + /*else if (enableADC == 3) { + + NRF_SAADC->CH[0].PSELP = 4 << SAADC_CH_PSELP_PIN_Pos | 1 << SAADC_CH_PSELP_PORT_Pos | 1 << SAADC_CH_PSELP_CONNECT_Pos | 0 << SAADC_CH_PSELP_INTERNAL_Pos; + NRF_SAADC->CH[0].PSELN = 4 << SAADC_CH_PSELN_PIN_Pos | 1 << SAADC_CH_PSELN_PORT_Pos | 1 << SAADC_CH_PSELN_CONNECT_Pos | 0 << SAADC_CH_PSELN_INTERNAL_Pos; + NRF_SAADC->CH[0].CONFIG = SAADC_CH_CONFIG_GAIN_Gain2 << SAADC_CH_CONFIG_GAIN_Pos | SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos | 40 << SAADC_CH_CONFIG_TACQ_Pos | SAADC_CH_CONFIG_MODE_Diff << SAADC_CH_CONFIG_MODE_Pos | SAADC_CH_CONFIG_BURST_Disabled << SAADC_CH_CONFIG_BURST_Pos; + NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit << SAADC_RESOLUTION_VAL_Pos; + NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over2x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos; + NRF_SAADC->SAMPLERATE = 16000000 / 16000 / 2 | SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos; + NRF_SAADC->RESULT.PTR = (uint32_t)adcBuf0; + NRF_SAADC->RESULT.MAXCNT = 16; + NRF_SAADC->ENABLE = true; + + NRF_SAADC->TASKS_CALIBRATEOFFSET = true; + while (!NRF_SAADC->EVENTS_CALIBRATEDONE) { + } + + NRF_SAADC->EVENTS_STARTED = 0; + NRF_SAADC->TASKS_START = 1; + while (!NRF_SAADC->EVENTS_STARTED) { + }; + while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos)) + ; + + uint32_t *vector_table = (uint32_t *)ARM_VTOR; + vector_table[SAADC_IRQn + 16] = (uint32_t)SAADC_IRQHandler; + NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk | SAADC_INTENSET_STARTED_Msk; + NVIC_SetPriority(SAADC_IRQn, 7); + NVIC_ClearPendingIRQ(SAADC_IRQn); + NVIC_EnableIRQ(SAADC_IRQn); + __enable_irq(); +Serial.println("enable IRQ"); + NRF_SAADC->TASKS_SAMPLE = 1; + } // USE_I2S + */ +} + +/****************************************************************************/ + +void AutoAnalog::adcInterrupts(bool enabled) +{ +} + +/****************************************************************************/ + +void AutoAnalog::dacSetup(void) +{ + + if(enableDAC == 3){ + Serial.println("En DAC"); + //R_PORT1->PODR ^= bit(2); + //delay(1000); + + analogWriteResolution(12); + analogWrite(A0, 0); + + R_DAC->DACR = 0x5F; // enable + R_DAC->DADPR = 0; // Right justified + R_DAC->DAADSCR = 1 << 7; // Sync ADC14 and DAC12 + //R_DAC->DAVREFCR = 1 << 3 | 1 << 2; // VREFH/VREFL + Serial.println("DAC SETUP 2"); + + uint8_t timer_type = GPT_TIMER; + int8_t timer_channel = 3; + + high_speed_timer.begin( + TIMER_MODE_PERIODIC, // Fire continuously at the specified interval + timer_type, // Use the General PWM Timer peripheral block + timer_channel, // Selected hardware channel channel + 16000.0, // Target Frequency in Hz (16 kHz) + 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) + dac_callback // Name of your ISR function to execute + ); + + high_speed_timer.setup_overflow_irq(); + high_speed_timer.open(); + high_speed_timer.start(); + + + } + + /*if (enableDAC == 2) { + NRF_I2S->TASKS_STOP = 1; + NRF_I2S->ENABLE = 0; + // Enable transmission + + if (enableADC != 2) { + NRF_I2S->CONFIG.RXEN = (I2S_CONFIG_RXEN_RXEN_Disabled << I2S_CONFIG_RXEN_RXEN_Pos); + //NRF_PWM0->TASKS_STOP = 1; + //NRF_PWM1->TASKS_STOP = 1; + } + NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_Enabled << I2S_CONFIG_TXEN_TXEN_Pos); + + + if (manualI2S) { + NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; + NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Right << I2S_CONFIG_ALIGN_ALIGN_Pos; + NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; + + }else{ + // Enable MCK generator + NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); + + // Master mode, 16Bit, left aligned + NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; + + NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; + NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; + NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; + NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left << I2S_CONFIG_ALIGN_ALIGN_Pos; + // Format = I2S + NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; + } + + + // Use left channel + NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Left << I2S_CONFIG_CHANNELS_CHANNELS_Pos; + + // Configure pins + 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); + 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); + 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); + 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); + + // NRF_I2S->INTENSET = I2S_INTEN_TXPTRUPD_Enabled << I2S_INTEN_TXPTRUPD_Pos; + // NVIC_EnableIRQ(I2S_IRQn); + + // Configure data pointer + NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; + //NRF_I2S->RXD.PTR = (uint32_t)dacBuf1; + NRF_I2S->RXTXD.MAXCNT = 16; // / sizeof(uint32_t); + } + else if (enableDAC == 1) { + + NRF_PWM20->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 + NRF_PWM20->PSEL.OUT[1] = (DEFAULT_PWM_PIN2 << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos | DEFAULT_PWM_PORT2 << PWM_PSEL_OUT_PORT_Pos); + #endif + NRF_PWM20->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos); + NRF_PWM20->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos); + NRF_PWM20->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); + NRF_PWM20->COUNTERTOP = (((uint16_t)((16000000 / DEFAULT_FREQUENCY))) << PWM_COUNTERTOP_COUNTERTOP_Pos); // 1 msec + NRF_PWM20->LOOP = (0 << PWM_LOOP_CNT_Pos); + NRF_PWM20->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) | (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos); + NRF_PWM20->DMA.SEQ[0].PTR = ((uint32_t)(&dacBuf0[0]) << PWM_DMA_SEQ_PTR_PTR_Pos); + NRF_PWM20->DMA.SEQ[0].MAXCNT = 1 << PWM_DMA_SEQ_MAXCNT_MAXCNT_Pos; //((sizeof(dacBuf0) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos); + NRF_PWM20->SEQ[0].REFRESH = 0; + NRF_PWM20->SEQ[0].ENDDELAY = 0; + + // NRF_PWM0->INTENSET = PWM_INTENSET_SEQEND0_Enabled << PWM_INTENSET_SEQEND0_Pos; + // NVIC_EnableIRQ(PWM0_IRQn); + NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; + }*/ +} + +/****************************************************************************/ + +void AutoAnalog::disableDAC(bool withinTask) +{ + if (enableDAC == 2) { + /*NRF_I2S->TASKS_STOP = 1; + NRF_I2S->ENABLE = 0;*/ + } + else if (enableDAC == 1) { + //NRF_PWM0->TASKS_STOP = 1; + } +} + +/****************************************************************************/ + +void AutoAnalog::dacHandler(void) +{ +} + +/****************************************************************************/ + +void AutoAnalog::tcSetup(uint32_t sampRate) +{ +} + +/****************************************************************************/ + +void AutoAnalog::tc2Setup(uint32_t sampRate) +{ +} +extern "C" { +__attribute__((__used__)) void I2S_IRQHandler_v(void) +{ +} +} + +extern "C" { +__attribute__((__used__)) void SAADC_IRQHandler(void) +{ +/* + uint32_t samples = AutoAnalog::aSize; + + if (NRF_SAADC->EVENTS_END) + { + if (!AutoAnalog::adcWhichBuf) { + NRF_SAADC->RESULT.PTR = (uint32_t)AutoAnalog::adcBuf1; + } + else { + NRF_SAADC->RESULT.PTR = (uint32_t)AutoAnalog::adcBuf0; + } + NRF_SAADC->RESULT.MAXCNT = samples; + NRF_SAADC->EVENTS_END = 0; + NRF_SAADC->TASKS_START = 1; + + if (AutoAnalog::adcBitsPerSample == 16) { + if (!AutoAnalog::adcWhichBuf) { + for (uint32_t i = 0; i < samples; i++) { + AutoAnalog::adcBuffer16[i] = AutoAnalog::adcBuf0[i] << 2; + } + } + else { + for (uint32_t i = 0; i < samples; i++) { + AutoAnalog::adcBuffer16[i] = AutoAnalog::adcBuf1[i] << 2; + } + } + } + else if (AutoAnalog::adcBitsPerSample == 8) { + if (!AutoAnalog::adcWhichBuf) { + for (uint32_t i = 0; i < samples; i++) { + AutoAnalog::adcBuffer[i] = AutoAnalog::adcBuf0[i] >> 6; + } + } + else { + for (uint32_t i = 0; i < samples; i++) { + AutoAnalog::adcBuffer[i] = AutoAnalog::adcBuf1[i] >> 6; + } + } + } + AutoAnalog::adcWhichBuf = !AutoAnalog::adcWhichBuf; + AutoAnalog::adcReady = true; + } + + if (NRF_SAADC->EVENTS_STARTED) + { + NRF_SAADC->EVENTS_STARTED = 0; + } + __DSB(); +*/ +} +} + + /****************************************************************************/ +/* #if defined __MBED__ +extern "C" { +__attribute__((__used__)) void PDM_IRQHandler_v(void) +{ + if (nrf_pdm_event_check(NRF_PDM_EVENT_STARTED)) { + nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); + + // switch to fill + + if (AutoAnalog::aCtr) { + nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::adcBuf0), AutoAnalog::aSize); + if (AutoAnalog::_onReceive) { + NVIC_DisableIRQ(PDM_IRQn); + AutoAnalog::_onReceive(AutoAnalog::adcBuf1, AutoAnalog::aSize); + NVIC_EnableIRQ(PDM_IRQn); + } + } + else { + nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::adcBuf1), AutoAnalog::aSize); + if (AutoAnalog::_onReceive) { + NVIC_DisableIRQ(PDM_IRQn); + AutoAnalog::_onReceive(AutoAnalog::adcBuf0, AutoAnalog::aSize); + NVIC_EnableIRQ(PDM_IRQn); + } + } + + // Flip to next buffer + AutoAnalog::aCtr = (AutoAnalog::aCtr + 1) % 2; + } + else if (nrf_pdm_event_check(NRF_PDM_EVENT_STOPPED)) { + nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED); + } + else if (nrf_pdm_event_check(NRF_PDM_EVENT_END)) { + nrf_pdm_event_clear(NRF_PDM_EVENT_END); + } +} +} + + #elif !defined MBED + +extern "C" { +__attribute__((__used__)) void PDM_IRQHandler(void) +{ + if (nrf_pdm_event_check(myPDM, NRF_PDM_EVENT_STARTED)) { + nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STARTED); + + // switch to fill + + if (AutoAnalog::aCtr) { + nrf_pdm_buffer_set(myPDM, (uint32_t*)(AutoAnalog::adcBuf0), AutoAnalog::aSize); + if (AutoAnalog::_onReceive) { + NVIC_DisableIRQ(PDM_IRQn); + AutoAnalog::_onReceive(AutoAnalog::adcBuf1, AutoAnalog::aSize); + NVIC_EnableIRQ(PDM_IRQn); + } + } + else { + nrf_pdm_buffer_set(myPDM, (uint32_t*)(AutoAnalog::adcBuf1), AutoAnalog::aSize); + if (AutoAnalog::_onReceive) { + NVIC_DisableIRQ(PDM_IRQn); + AutoAnalog::_onReceive(AutoAnalog::adcBuf0, AutoAnalog::aSize); + NVIC_EnableIRQ(PDM_IRQn); + } + } + + // Flip to next buffer + AutoAnalog::aCtr = (AutoAnalog::aCtr + 1) % 2; + } + else if (nrf_pdm_event_check(myPDM, NRF_PDM_EVENT_STOPPED)) { + nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STOPPED); + } + else if (nrf_pdm_event_check(myPDM, NRF_PDM_EVENT_END)) { + nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_END); + } +} +} + +extern "C" { +__attribute__((__used__)) void PWM0_IRQHandler(void) +{ + + // AutoAnalog::sampleCounter++; +} +} + #endif // defined __MBED__ +*/ + + +volatile uint32_t intCtr = 0; + +void dac_callback(timer_callback_args_t *p_args) { + + intCtr++; + + + if(intCtr >= 16000){ + intCtr = 0; + } + + if(AutoAnalog::sCounter < AutoAnalog::aSize){ + + if(AutoAnalog::aCtr == 0){ + R_DAC->DADR[0] = AutoAnalog::dacBuf0[AutoAnalog::sCounter]; + + }else{ + R_DAC->DADR[0] = AutoAnalog::dacBuf1[AutoAnalog::sCounter]; + } + } + AutoAnalog::sCounter++; +} + + +void AutoAnalog::set_callback(void (*function)(uint16_t* buf, uint32_t buf_len)) +{ + _onReceive = function; +} + +void AutoAnalog::adcCallback(uint16_t* buf, uint32_t buf_len) +{ + + memcpy(adcBuffer16, buf, buf_len * 2); + adcReady = true; +} + + +#endif //#if defined (ARDUINO_ARCH_SAM) \ No newline at end of file From 593543dbfe36c0133e1810cdc49aaf60f5684cd6 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Sun, 2 Aug 2026 11:45:11 -0600 Subject: [PATCH 02/16] Add example for Uno R4 --- .../SD_Playback_DAC_Auto_UnoR4.ino | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 examples/Platforms/UnoR4/SD_Playback_DAC_Auto_UnoR4/SD_Playback_DAC_Auto_UnoR4.ino diff --git a/examples/Platforms/UnoR4/SD_Playback_DAC_Auto_UnoR4/SD_Playback_DAC_Auto_UnoR4.ino b/examples/Platforms/UnoR4/SD_Playback_DAC_Auto_UnoR4/SD_Playback_DAC_Auto_UnoR4.ino new file mode 100644 index 0000000..8efc562 --- /dev/null +++ b/examples/Platforms/UnoR4/SD_Playback_DAC_Auto_UnoR4/SD_Playback_DAC_Auto_UnoR4.ino @@ -0,0 +1,127 @@ +/* + AutoAnalogAudio streaming via DAC & ADC by TMRh20 + Copyright (C) 2016 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Auto Analog Audio (Automatic DAC, ADC & Timer) library + + Auto Analog Audio Library Information: + http://github.com/TMRh20 + http://tmrh20.blogspot.com + + This example automatically determines the format of WAV files & + attempts to play them. +*/ + +#include +#include +#include + +AutoAnalog aaAudio; + + +float volumeControl = 0.2; +#define BUFFER_SIZE 256 + +void setup() { + + Serial.begin(115200); + + Serial.print("Init SD card..."); + if (!SD.begin(2)) { + Serial.println("init failed!"); + return; + } + Serial.println("init ok"); + Serial.println("Analog Audio Begin"); + aaAudio.begin(0, 3); //Setup aaAudio using DAC and I2S + + pinMode(6, OUTPUT); //Connected to SD pin of MAX98357A + digitalWrite(6, HIGH); + + playAudio("brick/brick24.wav"); // 24kHz @ 16-bits is about the maximum when reading from SD card + +} + +void loop() { + + loadBuffer(); + + + if (Serial.available()) { + char c = Serial.read(); + if (c == '=') { + volumeControl += 0.1; + } else if (c == '-') { + volumeControl -= 0.1; + volumeControl = max(0.0, volumeControl); + } else if (c == 'p') { + playAudio("libra/lb16b44k.wav"); + } + Serial.println(volumeControl); + } +} + +/*********************************************************/ +/* A simple function to handle playing audio files +/*********************************************************/ + +File myFile; + +void playAudio(char *audioFile) { + + if (myFile) { + myFile.close(); + } + //Open the designated file + myFile = SD.open(audioFile); + + myFile.seek(22); + uint16_t var; + uint32_t var2; + myFile.read(&var, 2); // Get channels (Stereo or Mono) + myFile.read(&var2, 4); // Get Sample Rate + aaAudio.setSampleRate(var2, var - 1); + myFile.seek(34); + myFile.read(&var, 2); // Get Bits Per Sample + aaAudio.dacBitsPerSample = var; + + myFile.seek(44); //Skip past the WAV header +} + +void loadBuffer() { + + if (myFile.available()) { + + if (aaAudio.dacBitsPerSample == 8) { + myFile.read(aaAudio.dacBuffer, BUFFER_SIZE); // Change this to dacBuffer16 for 16-bit samples + for (uint32_t i = 0; i < BUFFER_SIZE; i++) { + aaAudio.dacBuffer[i] *= volumeControl; + } + aaAudio.feedDAC(0, BUFFER_SIZE); // change this to 3200 for 16-bit samples + } else { + myFile.read(aaAudio.dacBuffer16, BUFFER_SIZE); // Change this to dacBuffer16 for 16-bit samples + for (uint32_t i = 0; i < BUFFER_SIZE / 2; i++) { + int16_t sample = aaAudio.dacBuffer16[i]; + sample *= volumeControl; + aaAudio.dacBuffer16[i] = (uint16_t)sample; + } + aaAudio.feedDAC(0, BUFFER_SIZE / 2); // change this to 3200 for 16-bit samples + } + + } else { + myFile.seek(44); + } +} From 944b19808b1cab2d54d46fbe3ba04fa38f4f6754 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Mon, 3 Aug 2026 09:00:48 -0600 Subject: [PATCH 03/16] ADC support for Uno R4 - ADC support for Uno R4 - Add example for ADC to DAC --- .../UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino | 34 ++++++ src/AutoAnalogAudio.h | 6 +- src/RA41M/AutoAnalogAudio.cpp | 110 +++++++++++++++++- 3 files changed, 142 insertions(+), 8 deletions(-) create mode 100644 examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino diff --git a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino new file mode 100644 index 0000000..a83f7f6 --- /dev/null +++ b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino @@ -0,0 +1,34 @@ + +#include +AutoAnalog aaAudio; + + +void setup() { + Serial.begin(115200); + Serial.println("Analog Audio Begin"); + + //Set pins low for MAX9814 microphone AR and GAIN pins + pinMode(7,OUTPUT); + digitalWrite(7,LOW); + + pinMode(8,OUTPUT); + digitalWrite(8,LOW); + + + aaAudio.begin(3, 3); //Setup aaAudio using DAC and ADC + aaAudio.dacBitsPerSample = 16; + aaAudio.adcBitsPerSample = 16; + aaAudio.setSampleRate(44000); + +} + +void loop() { + + aaAudio.getADC(256); + + // Copy our 14-bit ADC data to the DAC buffer which is only 12-bit + for(int i=0; i<256; i++){ + aaAudio.dacBuffer16[i] = aaAudio.adcBuffer16[i] >> 2; + } + aaAudio.feedDAC(0,256); +} diff --git a/src/AutoAnalogAudio.h b/src/AutoAnalogAudio.h index 02f374a..480c555 100644 --- a/src/AutoAnalogAudio.h +++ b/src/AutoAnalogAudio.h @@ -259,12 +259,12 @@ class AutoAnalog static void (*_onReceive)(uint16_t* buf, uint32_t buf_len); static void adcCallback(uint16_t* buf, uint32_t buf_len); void set_callback(void (*function)(uint16_t* buf, uint32_t buf_len)); - static bool adcReady; - uint32_t sampleCounter; + static volatile bool adcReady; + static volatile uint32_t sampleCounter; uint8_t enableADC; uint8_t enableDAC; bool whichBuf; - static bool adcWhichBuf; + static volatile bool adcWhichBuf; static volatile uint32_t sCounter; #endif diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index 968fa97..62f40fc 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -23,13 +23,20 @@ along with this program. If not, see . #include "../AutoAnalogAudio.h" #include "FspTimer.h" #include "r_timer_api.h" + #include "r_adc.h" FspTimer high_speed_timer; + FspTimer adc_timer; volatile bool toggle_state = false; - + #define ADC_IRQ_NUMBER ((IRQn_Type)15) + volatile uint16_t latestAdcValue = 0; + volatile bool newDataAvailable = false; + extern "C" void my_adc_isr(timer_callback_args_t *p_args); + uint16_t AutoAnalog::adcBuffer16[MAX_BUFFER_SIZE]; uint8_t AutoAnalog::adcBuffer[MAX_BUFFER_SIZE]; -bool AutoAnalog::adcReady; -bool AutoAnalog::adcWhichBuf; +volatile bool AutoAnalog::adcReady; +volatile uint32_t AutoAnalog::sampleCounter; +volatile bool AutoAnalog::adcWhichBuf; uint8_t AutoAnalog::adcBitsPerSample; volatile uint32_t AutoAnalog::aSize; volatile uint8_t AutoAnalog::aCtr; @@ -191,7 +198,23 @@ void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo) high_speed_timer.open(); high_speed_timer.start(); } - + if(enableADC == 3){ + adc_timer.stop(); + + uint8_t timerType = GPT_TIMER; + int8_t timerIndex = 4;//FspTimer::get_available_timer(timerType); + if (timerIndex < 0) { + FspTimer::force_use_of_pwm_reserved_timer(); + timerType = GPT_TIMER; + timerIndex = FspTimer::get_available_timer(timerType); + } + adc_timer.begin(TIMER_MODE_PERIODIC, timerType, timerIndex, sampRate * (stereo + 1), 0.0f, my_adc_isr); + adc_timer.setup_overflow_irq(); + adc_timer.open(); + adc_timer.start(); + + + } /*if (enableDAC == 1) { NRF_PWM20->TASKS_STOP = 1; @@ -281,7 +304,13 @@ void AutoAnalog::disableAdcChannel(uint8_t pinAx) void AutoAnalog::getADC(uint32_t samples) { - + + //if(!enableDAC){ + while(!adcReady){} + //} + + adcReady = false; + aSize = samples; /*if (enableADC == 2) { bool started = false; @@ -584,6 +613,46 @@ void AutoAnalog::startPwmI2sTimers() void AutoAnalog::adcSetup(void) { + + + if(enableADC == 3) { + + analogReadResolution(14); + pinMode(A1, INPUT); + analogRead(A1); + //analogReference(AR_INTERNAL); + + R_MSTP->MSTPCRD &= ~(1UL << 16); // MSTPD16 = 0 -> ADC140 enabled + __asm volatile ("nop"); + __asm volatile ("nop"); + + R_ADC0->ADCSR_b.ADST = 0; + while (R_ADC0->ADCSR_b.ADST) {} + + R_ADC0->ADCSR = 0x8000; + R_ADC0->ADANSA[0] = 0x0001; + //R_ADC0->ADANSA_b[0].ANSA0 = 1; // AN001 + + + // Optional sample time + R_ADC0->ADSSTR[0] = 1; + + + uint8_t timerType = GPT_TIMER; + int8_t timerIndex = FspTimer::get_available_timer(timerType); + if (timerIndex < 0) { + FspTimer::force_use_of_pwm_reserved_timer(); + timerType = GPT_TIMER; + timerIndex = FspTimer::get_available_timer(timerType); + } + adc_timer.begin(TIMER_MODE_PERIODIC, timerType, timerIndex, 16000, 0.0f, my_adc_isr); + adc_timer.setup_overflow_irq(); + adc_timer.open(); + adc_timer.start(); + + + Serial.println("ADC Configured"); + } /* if (enableADC == 2) { NRF_I2S->TASKS_STOP = 1; @@ -1087,6 +1156,37 @@ void dac_callback(timer_callback_args_t *p_args) { AutoAnalog::sCounter++; } +extern "C" void my_adc_isr(timer_callback_args_t *p_args) { + + (void)p_args; + + + // Read the 14-bit data register from Channel 0 (A0) + // This automatically clears the hardware interrupt condition inside the ADC0 block + if(AutoAnalog::adcWhichBuf == 0){ + AutoAnalog::adcBuf0[AutoAnalog::sampleCounter] = R_ADC0->ADDR[0]; //analogRead(A1); + }else{ + AutoAnalog::adcBuf1[AutoAnalog::sampleCounter] = R_ADC0->ADDR[0]; + } + + + AutoAnalog::sampleCounter++; + + if(AutoAnalog::sampleCounter >= AutoAnalog::aSize){ + if(AutoAnalog::adcWhichBuf == 0){ + memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf0, AutoAnalog::aSize * 2); + }else{ + memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf1, AutoAnalog::aSize *2 ); + } + AutoAnalog::sampleCounter = 0; + AutoAnalog::adcReady = true; + AutoAnalog::adcWhichBuf = !AutoAnalog::adcWhichBuf; + } + + // Set a flag for the main loop + R_ADC0->ADCSR_b.ADST = 1; +} + void AutoAnalog::set_callback(void (*function)(uint16_t* buf, uint32_t buf_len)) { From c2e6a2f78e8af577ea2c8bfede26faaddce8e72e Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Tue, 4 Aug 2026 05:12:51 -0600 Subject: [PATCH 04/16] Allocate timers dynamically Uno R4: Allocate timers dynamically & store values in global vars --- src/RA41M/AutoAnalogAudio.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index 62f40fc..674d2a2 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -26,6 +26,8 @@ along with this program. If not, see . #include "r_adc.h" FspTimer high_speed_timer; FspTimer adc_timer; + uint8_t high_speed_timer_index; + uint8_t adc_timer_index; volatile bool toggle_state = false; #define ADC_IRQ_NUMBER ((IRQn_Type)15) volatile uint16_t latestAdcValue = 0; @@ -183,12 +185,11 @@ void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo) high_speed_timer.stop(); uint8_t timer_type = GPT_TIMER; - int8_t timer_channel = 3; high_speed_timer.begin( TIMER_MODE_PERIODIC, // Fire continuously at the specified interval timer_type, // Use the General PWM Timer peripheral block - timer_channel, // Selected hardware channel channel + high_speed_timer_index, // Selected hardware channel channel sampRate * (stereo + 1), // Target Frequency in Hz (16 kHz) 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) dac_callback // Name of your ISR function to execute @@ -202,13 +203,8 @@ void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo) adc_timer.stop(); uint8_t timerType = GPT_TIMER; - int8_t timerIndex = 4;//FspTimer::get_available_timer(timerType); - if (timerIndex < 0) { - FspTimer::force_use_of_pwm_reserved_timer(); - timerType = GPT_TIMER; - timerIndex = FspTimer::get_available_timer(timerType); - } - adc_timer.begin(TIMER_MODE_PERIODIC, timerType, timerIndex, sampRate * (stereo + 1), 0.0f, my_adc_isr); + + adc_timer.begin(TIMER_MODE_PERIODIC, timerType, adc_timer_index, sampRate * (stereo + 1), 0.0f, my_adc_isr); adc_timer.setup_overflow_irq(); adc_timer.open(); adc_timer.start(); @@ -639,13 +635,13 @@ void AutoAnalog::adcSetup(void) uint8_t timerType = GPT_TIMER; - int8_t timerIndex = FspTimer::get_available_timer(timerType); - if (timerIndex < 0) { + adc_timer_index = FspTimer::get_available_timer(timerType); + if (adc_timer_index < 0) { FspTimer::force_use_of_pwm_reserved_timer(); timerType = GPT_TIMER; - timerIndex = FspTimer::get_available_timer(timerType); + adc_timer_index = FspTimer::get_available_timer(timerType); } - adc_timer.begin(TIMER_MODE_PERIODIC, timerType, timerIndex, 16000, 0.0f, my_adc_isr); + adc_timer.begin(TIMER_MODE_PERIODIC, timerType, adc_timer_index, 16000, 0.0f, my_adc_isr); adc_timer.setup_overflow_irq(); adc_timer.open(); adc_timer.start(); @@ -857,15 +853,20 @@ void AutoAnalog::dacSetup(void) Serial.println("DAC SETUP 2"); uint8_t timer_type = GPT_TIMER; - int8_t timer_channel = 3; + high_speed_timer_index = FspTimer::get_available_timer(timer_type); + if (high_speed_timer_index < 0) { + FspTimer::force_use_of_pwm_reserved_timer(); + timer_type = GPT_TIMER; + high_speed_timer_index = FspTimer::get_available_timer(timer_type); + } high_speed_timer.begin( TIMER_MODE_PERIODIC, // Fire continuously at the specified interval timer_type, // Use the General PWM Timer peripheral block - timer_channel, // Selected hardware channel channel + high_speed_timer_index,// Selected hardware channel channel 16000.0, // Target Frequency in Hz (16 kHz) 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) - dac_callback // Name of your ISR function to execute + dac_callback // Name of your ISR function to execute ); high_speed_timer.setup_overflow_irq(); From bdd269ad660794e271b289647dc9dde739f282b4 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Tue, 4 Aug 2026 05:32:39 -0600 Subject: [PATCH 05/16] Uno R4: Support 8-bit ADC --- src/RA41M/AutoAnalogAudio.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index 674d2a2..dbf1fc3 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -1175,9 +1175,21 @@ extern "C" void my_adc_isr(timer_callback_args_t *p_args) { if(AutoAnalog::sampleCounter >= AutoAnalog::aSize){ if(AutoAnalog::adcWhichBuf == 0){ - memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf0, AutoAnalog::aSize * 2); + if(AutoAnalog::adcBitsPerSample == 8){ + for(uint32_t i=0; i> 6; + } + }else{ + memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf0, AutoAnalog::aSize * 2); + } }else{ - memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf1, AutoAnalog::aSize *2 ); + if(AutoAnalog::adcBitsPerSample == 8){ + for(uint32_t i=0; i> 6; + } + }else{ + memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf1, AutoAnalog::aSize *2 ); + } } AutoAnalog::sampleCounter = 0; AutoAnalog::adcReady = true; From edaa0b8734f1ad219af3ef02d81e87692ed0cf6e Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Tue, 4 Aug 2026 07:07:17 -0600 Subject: [PATCH 06/16] Update ADCtoDAC_UnoR4.ino --- .../UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino index a83f7f6..408f29b 100644 --- a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino +++ b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino @@ -2,6 +2,7 @@ #include AutoAnalog aaAudio; +#define bufferSize 256 void setup() { Serial.begin(115200); @@ -18,17 +19,18 @@ void setup() { aaAudio.begin(3, 3); //Setup aaAudio using DAC and ADC aaAudio.dacBitsPerSample = 16; aaAudio.adcBitsPerSample = 16; - aaAudio.setSampleRate(44000); + aaAudio.setSampleRate(44100); } void loop() { - aaAudio.getADC(256); + aaAudio.getADC(bufferSize); // Copy our 14-bit ADC data to the DAC buffer which is only 12-bit - for(int i=0; i<256; i++){ - aaAudio.dacBuffer16[i] = aaAudio.adcBuffer16[i] >> 2; + // The dac input expects signed 12-bit samples + for(int i=0; i> 2; } - aaAudio.feedDAC(0,256); + aaAudio.feedDAC(0,bufferSize); } From 71288e0b244393929c78f84ffa38bcd08c7ddf9f Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Tue, 4 Aug 2026 07:12:08 -0600 Subject: [PATCH 07/16] Update ADCtoDAC_UnoR4.ino --- examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino index 408f29b..f71e71e 100644 --- a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino +++ b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino @@ -28,9 +28,9 @@ void loop() { aaAudio.getADC(bufferSize); // Copy our 14-bit ADC data to the DAC buffer which is only 12-bit - // The dac input expects signed 12-bit samples + // The dac input expects signed 16-bit samples for(int i=0; i> 2; + aaAudio.dacBuffer16[i] = (aaAudio.adcBuffer16[i] ^ 0x8000); } aaAudio.feedDAC(0,bufferSize); } From 7b3b6f5bef3eb7d570d2216f100be904d61b07e0 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Wed, 5 Aug 2026 03:15:00 -0600 Subject: [PATCH 08/16] Update ADCtoDAC_UnoR4.ino --- examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino index f71e71e..e9a5277 100644 --- a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino +++ b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino @@ -30,7 +30,8 @@ void loop() { // Copy our 14-bit ADC data to the DAC buffer which is only 12-bit // The dac input expects signed 16-bit samples for(int i=0; i Date: Wed, 5 Aug 2026 04:50:32 -0600 Subject: [PATCH 09/16] Minor changes - Add functionality to disable/enable DAC output - Remove internal Serial.prints --- src/AutoAnalogAudio.h | 2 +- src/RA41M/AutoAnalogAudio.cpp | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/AutoAnalogAudio.h b/src/AutoAnalogAudio.h index 480c555..50d4c7c 100644 --- a/src/AutoAnalogAudio.h +++ b/src/AutoAnalogAudio.h @@ -266,7 +266,7 @@ class AutoAnalog bool whichBuf; static volatile bool adcWhichBuf; static volatile uint32_t sCounter; - + bool dacDisabled; #endif #if defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52) || defined ARDUINO_NRF54L15 || defined ARDUINO_ARCH_RENESAS || defined(DOXYGEN_FORCED) diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index dbf1fc3..62767e7 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -172,7 +172,6 @@ void AutoAnalog::begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S) memset(const_cast(reinterpret_cast(dacBuf1)), 0, maxBufferSize * 2); } dacSetup(); - Serial.println("Dac is setup"); } } @@ -407,6 +406,12 @@ void AutoAnalog::feedDAC(uint8_t dacChannel, uint32_t samples, bool startInterru if(enableDAC == 3){ + if(dacDisabled){ + R_DAC->DACR = 0x5F; + high_speed_timer.start(); + dacDisabled = false; + } + //memcpy(dacBuf0,dacBuffer,samples); if(aCtr == 1){ if(dacBitsPerSample == 8){ @@ -647,7 +652,6 @@ void AutoAnalog::adcSetup(void) adc_timer.start(); - Serial.println("ADC Configured"); } /* if (enableADC == 2) { @@ -839,9 +843,6 @@ void AutoAnalog::dacSetup(void) { if(enableDAC == 3){ - Serial.println("En DAC"); - //R_PORT1->PODR ^= bit(2); - //delay(1000); analogWriteResolution(12); analogWrite(A0, 0); @@ -850,7 +851,6 @@ void AutoAnalog::dacSetup(void) R_DAC->DADPR = 0; // Right justified R_DAC->DAADSCR = 1 << 7; // Sync ADC14 and DAC12 //R_DAC->DAVREFCR = 1 << 3 | 1 << 2; // VREFH/VREFL - Serial.println("DAC SETUP 2"); uint8_t timer_type = GPT_TIMER; high_speed_timer_index = FspTimer::get_available_timer(timer_type); @@ -958,6 +958,10 @@ void AutoAnalog::dacSetup(void) void AutoAnalog::disableDAC(bool withinTask) { + if (enableDAC == 3){ + high_speed_timer.stop(); + R_DAC->DACR = 0x4F; + }else if (enableDAC == 2) { /*NRF_I2S->TASKS_STOP = 1; NRF_I2S->ENABLE = 0;*/ @@ -1160,17 +1164,13 @@ void dac_callback(timer_callback_args_t *p_args) { extern "C" void my_adc_isr(timer_callback_args_t *p_args) { (void)p_args; - - // Read the 14-bit data register from Channel 0 (A0) - // This automatically clears the hardware interrupt condition inside the ADC0 block if(AutoAnalog::adcWhichBuf == 0){ AutoAnalog::adcBuf0[AutoAnalog::sampleCounter] = R_ADC0->ADDR[0]; //analogRead(A1); }else{ AutoAnalog::adcBuf1[AutoAnalog::sampleCounter] = R_ADC0->ADDR[0]; } - AutoAnalog::sampleCounter++; if(AutoAnalog::sampleCounter >= AutoAnalog::aSize){ @@ -1188,7 +1188,7 @@ extern "C" void my_adc_isr(timer_callback_args_t *p_args) { AutoAnalog::adcBuffer[i] = AutoAnalog::adcBuf1[i] >> 6; } }else{ - memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf1, AutoAnalog::aSize *2 ); + memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf1, AutoAnalog::aSize * 2 ); } } AutoAnalog::sampleCounter = 0; @@ -1196,7 +1196,6 @@ extern "C" void my_adc_isr(timer_callback_args_t *p_args) { AutoAnalog::adcWhichBuf = !AutoAnalog::adcWhichBuf; } - // Set a flag for the main loop R_ADC0->ADCSR_b.ADST = 1; } From 5ea84666b8a2f8fd471fe643228aad72dea776d8 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Thu, 6 Aug 2026 05:33:40 -0600 Subject: [PATCH 10/16] Set var in disableDAC function - Forgot to set dacDisabled var in disableDAC() function --- src/RA41M/AutoAnalogAudio.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index 62767e7..fbc297b 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -961,6 +961,7 @@ void AutoAnalog::disableDAC(bool withinTask) if (enableDAC == 3){ high_speed_timer.stop(); R_DAC->DACR = 0x4F; + dacDisabled = true; }else if (enableDAC == 2) { /*NRF_I2S->TASKS_STOP = 1; From 3b65a483b1dcb7eec6c60612a3bf0cefd509dfae Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Fri, 7 Aug 2026 10:27:19 -0600 Subject: [PATCH 11/16] Channel selection Select ADC channel to use, 1 corresponds with channel AN000 or pin A1, 2 is channel AN001 or pin A2 etc --- src/AutoAnalogAudio.h | 1 + src/RA41M/AutoAnalogAudio.cpp | 50 ++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/AutoAnalogAudio.h b/src/AutoAnalogAudio.h index 50d4c7c..c39bf39 100644 --- a/src/AutoAnalogAudio.h +++ b/src/AutoAnalogAudio.h @@ -267,6 +267,7 @@ class AutoAnalog static volatile bool adcWhichBuf; static volatile uint32_t sCounter; bool dacDisabled; + static volatile uint8_t analogChannel; #endif #if defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52) || defined ARDUINO_NRF54L15 || defined ARDUINO_ARCH_RENESAS || defined(DOXYGEN_FORCED) diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index fbc297b..fbf701a 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -33,6 +33,7 @@ along with this program. If not, see . volatile uint16_t latestAdcValue = 0; volatile bool newDataAvailable = false; extern "C" void my_adc_isr(timer_callback_args_t *p_args); + volatile uint8_t AutoAnalog::analogChannel = 0; uint16_t AutoAnalog::adcBuffer16[MAX_BUFFER_SIZE]; uint8_t AutoAnalog::adcBuffer[MAX_BUFFER_SIZE]; @@ -277,22 +278,33 @@ void AutoAnalog::triggerADC() void AutoAnalog::enableAdcChannel(uint8_t pinAx) { - #if defined __MBED__ - //nrf_pdm_enable(); - #else - //nrf_pdm_enable(myPDM); - #endif + adc_timer.stop(); + + pinMode(pinAx + 15, INPUT); + analogRead(pinAx + 15); + + R_ADC0->ADCSR_b.ADST = 0; + while (R_ADC0->ADCSR_b.ADST) {} + + R_ADC0->ADANSA[0] = 1 << pinAx; + + analogChannel = pinAx; + + adc_timer.start(); } /****************************************************************************/ void AutoAnalog::disableAdcChannel(uint8_t pinAx) { - #if defined __MBED__ - //nrf_pdm_disable(); - #else - //nrf_pdm_disable(myPDM); - #endif + + adc_timer.stop(); + + R_ADC0->ADCSR_b.ADST = 0; + while (R_ADC0->ADCSR_b.ADST) {} + + R_ADC0->ADANSA[0] = 0; + } /****************************************************************************/ @@ -619,8 +631,8 @@ void AutoAnalog::adcSetup(void) if(enableADC == 3) { analogReadResolution(14); - pinMode(A1, INPUT); - analogRead(A1); + pinMode(15 + analogChannel, INPUT); + analogRead(15 + analogChannel); //analogReference(AR_INTERNAL); R_MSTP->MSTPCRD &= ~(1UL << 16); // MSTPD16 = 0 -> ADC140 enabled @@ -631,8 +643,8 @@ void AutoAnalog::adcSetup(void) while (R_ADC0->ADCSR_b.ADST) {} R_ADC0->ADCSR = 0x8000; - R_ADC0->ADANSA[0] = 0x0001; - //R_ADC0->ADANSA_b[0].ANSA0 = 1; // AN001 + R_ADC0->ADANSA[0] = 1 << analogChannel; + //R_ADC0->ADANSA_b[1].ANSA0 = 2; // AN001 // Optional sample time @@ -1139,16 +1151,16 @@ __attribute__((__used__)) void PWM0_IRQHandler(void) */ -volatile uint32_t intCtr = 0; +//volatile uint32_t intCtr = 0; void dac_callback(timer_callback_args_t *p_args) { - intCtr++; + /*intCtr++; if(intCtr >= 16000){ intCtr = 0; - } + }*/ if(AutoAnalog::sCounter < AutoAnalog::aSize){ @@ -1167,9 +1179,9 @@ extern "C" void my_adc_isr(timer_callback_args_t *p_args) { (void)p_args; if(AutoAnalog::adcWhichBuf == 0){ - AutoAnalog::adcBuf0[AutoAnalog::sampleCounter] = R_ADC0->ADDR[0]; //analogRead(A1); + AutoAnalog::adcBuf0[AutoAnalog::sampleCounter] = R_ADC0->ADDR[AutoAnalog::analogChannel]; //analogRead(A1); }else{ - AutoAnalog::adcBuf1[AutoAnalog::sampleCounter] = R_ADC0->ADDR[0]; + AutoAnalog::adcBuf1[AutoAnalog::sampleCounter] = R_ADC0->ADDR[AutoAnalog::analogChannel]; } AutoAnalog::sampleCounter++; From 0e5b4c19f0c381f93e57a74a4395ec989c2ac6a4 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Fri, 7 Aug 2026 17:54:24 -0600 Subject: [PATCH 12/16] Match datatypes in buffers - Match adcBuffer16 and dacBuffer16 so that both types will input or output 16-bit signed samples - Modify examples to match changes above --- .../Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino | 5 ++--- src/RA41M/AutoAnalogAudio.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino index e9a5277..e00efc3 100644 --- a/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino +++ b/examples/Platforms/UnoR4/ADCtoDAC_UnoR4/ADCtoDAC_UnoR4.ino @@ -28,10 +28,9 @@ void loop() { aaAudio.getADC(bufferSize); // Copy our 14-bit ADC data to the DAC buffer which is only 12-bit - // The dac input expects signed 16-bit samples + // The dac input expects signed 16-bit samples, and the ADC will output signed 16-bit samples for(int i=0; i> 6; } }else{ - memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf0, AutoAnalog::aSize * 2); + for(uint32_t i=0; i> 6; } }else{ - memcpy(AutoAnalog::adcBuffer16,AutoAnalog::adcBuf1, AutoAnalog::aSize * 2 ); + for(uint32_t i=0; i Date: Sat, 8 Aug 2026 10:02:57 -0600 Subject: [PATCH 13/16] Clang format - Clang formatting - R_ADC0->ADSSTR[analogChannel] = 12; instead of R_ADC0->ADSSTR[0] = 1 --- src/RA41M/AutoAnalogAudio.cpp | 1025 +++++---------------------------- 1 file changed, 139 insertions(+), 886 deletions(-) diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index 70a1493..8f30757 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -24,17 +24,15 @@ along with this program. If not, see . #include "FspTimer.h" #include "r_timer_api.h" #include "r_adc.h" - FspTimer high_speed_timer; - FspTimer adc_timer; - uint8_t high_speed_timer_index; - uint8_t adc_timer_index; - volatile bool toggle_state = false; - #define ADC_IRQ_NUMBER ((IRQn_Type)15) - volatile uint16_t latestAdcValue = 0; - volatile bool newDataAvailable = false; - extern "C" void my_adc_isr(timer_callback_args_t *p_args); - volatile uint8_t AutoAnalog::analogChannel = 0; - + +FspTimer high_speed_timer; +FspTimer adc_timer; +uint8_t high_speed_timer_index; +uint8_t adc_timer_index; + +extern "C" void my_adc_isr(timer_callback_args_t* p_args); +volatile uint8_t AutoAnalog::analogChannel = 0; + uint16_t AutoAnalog::adcBuffer16[MAX_BUFFER_SIZE]; uint8_t AutoAnalog::adcBuffer[MAX_BUFFER_SIZE]; volatile bool AutoAnalog::adcReady; @@ -50,56 +48,17 @@ volatile uint16_t* AutoAnalog::dacBuf1; void (*AutoAnalog::_onReceive)(uint16_t* buf, uint32_t buf_len); uint8_t AutoAnalog::dacBuffer[MAX_BUFFER_SIZE]; volatile uint32_t AutoAnalog::sCounter = 0; -void dac_callback(timer_callback_args_t *p_args); - -/******************* USER DEFINES - Configure pins etc here *****************/ - #define DEFAULT_PDM_GAIN 40 - - /* I2s default config MAX98357A Breakout also needs SD pin set HIGH - I2S_PIN_MCK 2 // Not used with MAX98357A - I2S_PORT_MCK 0 - I2S_PIN_SCK 3 // BCLK - I2S_PORT_SCK 0 - I2S_PIN_LRCK 29 // LRCK - I2S_PORT_LRCK 0 - I2S_PIN_SDOUT 5 // GPIO Pin numbers - I2S_PORT_SDOUT 0 - */ - - /* PWM Config */ - #define DEFAULT_PWM_PIN 11 // GPIO Pin number - #define DEFAULT_PWM_PORT 1 // On XIAO port 0 is for pins 1-5 port 1 is for all higher pins - //#define DEFAULT_PWM_PIN2 4 //Enable a second output pin - //#define DEFAULT_PWM_PORT2 0 - - #ifndef PIN_PDM_DIN // Arduino pin numbers - #define PIN_PDM_DIN 35 - //#define PIN_PDM_CLK 36 - #define PIN_PDM_PWR -1 - #endif +void dac_callback(timer_callback_args_t* p_args); /****************************************************************************/ /* Public Functions */ /****************************************************************************/ -uint8_t analogCounter = 0; -uint16_t mycounter = 0; - -extern "C" { - void SAADC_IRQHandler(void); -} - - AutoAnalog::AutoAnalog() { adcReady = true; adcBitsPerSample = 8; - //pwrPin = PIN_PDM_PWR; - //dinPin = PIN_PDM_DIN; - //clkPin = PIN_PDM_CLK; - gain = -1; - dacBitsPerSample = 8; autoAdjust = true; for (int i = 0; i < MAX_BUFFER_SIZE; i++) { @@ -111,21 +70,9 @@ AutoAnalog::AutoAnalog() sampleCounter = 0; maxBufferSize = 0; dacBuffersAllocated = false; - I2S_PIN_MCK = 8; - I2S_PORT_MCK = 2; - I2S_PIN_SCK = 5; - I2S_PORT_SCK = 1; - I2S_PIN_LRCK = 7; - I2S_PORT_LRCK = 1; - I2S_PIN_SDOUT = 11; - I2S_PORT_SDOUT = 1; - I2S_PIN_SDIN = 10; - I2S_PORT_SDIN = 1; manualI2S = false; } - - void AutoAnalog::begin(uint8_t enADC, uint8_t enDAC, uint8_t _useI2S) { @@ -183,89 +130,32 @@ void AutoAnalog::setSampleRate(uint32_t sampRate, bool stereo) if (enableDAC == 3) { high_speed_timer.stop(); - + uint8_t timer_type = GPT_TIMER; - + high_speed_timer.begin( - TIMER_MODE_PERIODIC, // Fire continuously at the specified interval - timer_type, // Use the General PWM Timer peripheral block - high_speed_timer_index, // Selected hardware channel channel - sampRate * (stereo + 1), // Target Frequency in Hz (16 kHz) - 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) - dac_callback // Name of your ISR function to execute + TIMER_MODE_PERIODIC, // Fire continuously at the specified interval + timer_type, // Use the General PWM Timer peripheral block + high_speed_timer_index, // Selected hardware channel channel + sampRate * (stereo + 1), // Target Frequency in Hz (16 kHz) + 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) + dac_callback // Name of your ISR function to execute ); high_speed_timer.setup_overflow_irq(); high_speed_timer.open(); high_speed_timer.start(); } - if(enableADC == 3){ + if (enableADC == 3) { adc_timer.stop(); - - uint8_t timerType = GPT_TIMER; + + uint8_t timerType = GPT_TIMER; adc_timer.begin(TIMER_MODE_PERIODIC, timerType, adc_timer_index, sampRate * (stereo + 1), 0.0f, my_adc_isr); adc_timer.setup_overflow_irq(); adc_timer.open(); adc_timer.start(); - - - } - - /*if (enableDAC == 1) { - NRF_PWM20->TASKS_STOP = 1; - uint32_t timer = millis(); - while (NRF_PWM20->EVENTS_STOPPED == 0) { - if (millis() - timer > 1000) { - break; - } - } - - NRF_PWM20->COUNTERTOP = (((uint16_t)((16000000 / sampRate))) << PWM_COUNTERTOP_COUNTERTOP_Pos); - NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; } - - if (enableDAC == 2 || enableADC == 2) { - - if (stereo) { - NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Stereo << I2S_CONFIG_CHANNELS_CHANNELS_Pos; - } - else { - NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Left << I2S_CONFIG_CHANNELS_CHANNELS_Pos; - } - - if (sampRate <= 16000) { - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; - } - else if (sampRate <= 22500) { - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV15 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; - } - else if (sampRate <= 24000) { - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV11 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; - } - else if (sampRate <= 32000) { - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_64X << I2S_CONFIG_RATIO_RATIO_Pos; - } - else if (sampRate <= 45000) { - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV23 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_32X << I2S_CONFIG_RATIO_RATIO_Pos; - } - - } - - if (enableADC == 1) { - struct PwmTiming* myTiming; - computePwmTiming(sampRate, myTiming); - myPDM->PRESCALER = myTiming->prescaler; - } - - if (enableADC == 3) { - NRF_SAADC->SAMPLERATE = 16000000 / sampRate / 2 | SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos; - }*/ } /****************************************************************************/ @@ -279,17 +169,18 @@ void AutoAnalog::triggerADC() void AutoAnalog::enableAdcChannel(uint8_t pinAx) { adc_timer.stop(); - + pinMode(pinAx + 15, INPUT); analogRead(pinAx + 15); - + R_ADC0->ADCSR_b.ADST = 0; - while (R_ADC0->ADCSR_b.ADST) {} + while (R_ADC0->ADCSR_b.ADST) { + } R_ADC0->ADANSA[0] = 1 << pinAx; - + analogChannel = pinAx; - + adc_timer.start(); } @@ -297,118 +188,26 @@ void AutoAnalog::enableAdcChannel(uint8_t pinAx) void AutoAnalog::disableAdcChannel(uint8_t pinAx) { - + adc_timer.stop(); - + R_ADC0->ADCSR_b.ADST = 0; - while (R_ADC0->ADCSR_b.ADST) {} - + while (R_ADC0->ADCSR_b.ADST) { + } + R_ADC0->ADANSA[0] = 0; - } /****************************************************************************/ void AutoAnalog::getADC(uint32_t samples) { - - //if(!enableDAC){ - while(!adcReady){} - //} - - adcReady = false; - aSize = samples; - /*if (enableADC == 2) { - - bool started = false; - if (NRF_I2S->ENABLE == 0) { - NRF_I2S->ENABLE = 1; - started = true; - } - else { - uint32_t timeout = millis() + 1000; - while (NRF_I2S->EVENTS_RXPTRUPD == 0) { - if (millis() > timeout) { - return; - } - } - } - - if (adcWhichBuf == 0) { - NRF_I2S->RXD.PTR = (uint32_t)&adcBuf0[0]; - } - else { - NRF_I2S->RXD.PTR = (uint32_t)&adcBuf1[0]; - } - uint8_t divider = 2; - if (adcBitsPerSample == 24 || adcBitsPerSample == 32) { - divider = 4; - } - else if (adcBitsPerSample == 8) { - divider = 1; - } - - if (enableDAC != 2) { // Only update MAXCNT if I2S output is disabled - NRF_I2S->RXTXD.MAXCNT = samples * divider; - } - - NRF_I2S->EVENTS_RXPTRUPD = 0; - - if (adcBitsPerSample == 24 || adcBitsPerSample == 32) { - if (adcBitsPerSample == 24 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - }else - if (adcBitsPerSample == 32 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - } - - if (adcWhichBuf == 0) { - memcpy(adcBuffer16, adcBuf0, samples * 4); - } - else { - memcpy(adcBuffer16, adcBuf1, samples * 4); - } - } - else if (adcBitsPerSample == 16) { - if (adcWhichBuf == 0) { - memcpy(adcBuffer16, adcBuf0, samples * 2); - } - else { - memcpy(adcBuffer16, adcBuf1, samples * 2); - } - } - else if (adcBitsPerSample == 8) { - if (adcWhichBuf == 0) { - //memcpy(adcBuffer, adcBuf0, samples); - for(int i=0; i> 6) - 127; - } - } - else { - //memcpy(adcBuffer, adcBuf1, samples); - for(int i=0; i> 6) - 127; - } - } - } - adcWhichBuf = !adcWhichBuf; - if (started) { - NRF_I2S->TASKS_START = 1; - } - } - else if (enableADC == 1) { - while (!adcReady) { - __WFE(); - }; - aSize = samples; - adcReady = false; + while (!adcReady) { } - else if (enableADC == 3) { - while (!adcReady) {Serial.println("p"); - } - aSize = samples; - }*/ + + adcReady = false; + aSize = samples; } /****************************************************************************/ @@ -416,163 +215,44 @@ void AutoAnalog::getADC(uint32_t samples) void AutoAnalog::feedDAC(uint8_t dacChannel, uint32_t samples, bool startInterrupts) { - if(enableDAC == 3){ - - if(dacDisabled){ + if (enableDAC == 3) { + + if (dacDisabled) { R_DAC->DACR = 0x5F; high_speed_timer.start(); dacDisabled = false; } - - //memcpy(dacBuf0,dacBuffer,samples); - if(aCtr == 1){ - if(dacBitsPerSample == 8){ - for(int i=0; i> 4) + 2048; - } } - }else{ - if(dacBitsPerSample == 8){ - for(int i=0; i> 4) + 2048; + else if (dacBitsPerSample == 16) { + for (int i = 0; i < samples; i++) { + dacBuf0[i] = (dacBuffer16[i] >> 4) + 2048; } } } - while(sCounter < samples){} - aCtr = (aCtr + 1) % 2; - aSize = samples; - sCounter = 0; - } - - /*if (enableDAC == 2) { - - bool started = false; - if (NRF_I2S->ENABLE == 0) { - NRF_I2S->ENABLE = 1; - started = true; - } else { - uint32_t timeout = millis() + 1000; - while (NRF_I2S->EVENTS_TXPTRUPD == 0) { - if (millis() > timeout) { - return; - } - } - } - - if (dacBitsPerSample == 8) { - if (whichBuf) { - for (uint32_t i = 0; i < samples; i++) { - dacBuf0[i] = dacBuffer[i] << 7; + if (dacBitsPerSample == 8) { + for (int i = 0; i < samples; i++) { + dacBuf1[i] = dacBuffer[i] << 4; } - NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; } - else { - for (uint32_t i = 0; i < samples; i++) { - dacBuf1[i] = dacBuffer[i] << 7; + else if (dacBitsPerSample == 16) { + for (int i = 0; i < samples; i++) { + dacBuf1[i] = (dacBuffer16[i] >> 4) + 2048; } - NRF_I2S->TXD.PTR = (uint32_t)&dacBuf1[0]; - } - } - else if (dacBitsPerSample == 16) { - if (whichBuf) { - memcpy(dacBuf0, dacBuffer16, samples * 2); - NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; - } - else { - memcpy(dacBuf1, dacBuffer16, samples * 2); - NRF_I2S->TXD.PTR = (uint32_t)&dacBuf1[0]; - } - } - else if (dacBitsPerSample == 24 || dacBitsPerSample == 32) { - if (dacBitsPerSample == 24 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_24Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - }else - if (dacBitsPerSample == 32 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - }else - if (dacBitsPerSample == 16 && NRF_I2S->CONFIG.SWIDTH != I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos) { - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; } - - if (whichBuf) { - memcpy(dacBuf0, dacBuffer16, samples * 4); - NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; - } - else { - memcpy(dacBuf1, dacBuffer16, samples * 4); - NRF_I2S->TXD.PTR = (uint32_t)&dacBuf1[0]; - } - } - - whichBuf = !whichBuf; - - uint8_t divider = 2; - if (dacBitsPerSample == 16) { - divider = 2; - } - else if (dacBitsPerSample == 24 || dacBitsPerSample == 32) { - divider = 4; } - - NRF_I2S->RXTXD.MAXCNT = samples * divider; - NRF_I2S->EVENTS_TXPTRUPD = 0; - - if (started) { - NRF_I2S->TASKS_START = 1; + while (sCounter < samples) { } + aCtr = (aCtr + 1) % 2; + aSize = samples; + sCounter = 0; } - else if (enableDAC == 1) { - uint32_t timer = millis() + 1000; - while (NRF_PWM20->EVENTS_DMA.SEQ[0].END == 0) { - if (millis() > timer) { - NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; - return; - } - } - NRF_PWM20->EVENTS_DMA.SEQ[0].END = 0; - - if (dacBitsPerSample > 8) { - if (whichBuf) { - memcpy(dacBuf0, dacBuffer16, samples * 2); - } - else { - memcpy(dacBuf1, dacBuffer16, samples * 2); - } - } - else { - if (whichBuf) { - for (uint32_t i = 0; i < samples; i++) { - dacBuf0[i] = (uint16_t)(dacBuffer[i] << 1); - } - } - else { - for (uint32_t i = 0; i < samples; i++) { - dacBuf1[i] = (uint16_t)(dacBuffer[i] << 1); - } - } - } - if (whichBuf) { - NRF_PWM20->DMA.SEQ[0].PTR = ((uint32_t)(&dacBuf0[0]) << PWM_DMA_SEQ_PTR_PTR_Pos); - } - else { - NRF_PWM20->DMA.SEQ[0].PTR = ((uint32_t)(&dacBuf1[0]) << PWM_DMA_SEQ_PTR_PTR_Pos); - } - whichBuf = !whichBuf; - - NRF_PWM20->DMA.SEQ[0].MAXCNT = (samples << PWM_DMA_SEQ_MAXCNT_MAXCNT_Pos); - NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; - }*/ } /****************************************************************************/ @@ -595,252 +275,45 @@ uint32_t AutoAnalog::frequencyToTimerCount(uint32_t frequency) void AutoAnalog::startPwmI2sTimers() { - /* // 1. Setup BCLK (WS * 64) - NRF_PWM20->PSEL.OUT[0] = I2S_PIN_SCK | I2S_PORT_SCK << 5 | 0 << 31; - NRF_PWM20->ENABLE = 1; - NRF_PWM20->MODE = PWM_MODE_UPDOWN_Up; - NRF_PWM20->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // 16MHz - NRF_PWM20->COUNTERTOP = 8; // 16MHz / 8 = 2MHz - static uint16_t bclk_seq[] = {4}; // 50% duty cycle - NRF_PWM20->DECODER = PWM_DECODER_LOAD_Common; - NRF_PWM20->DMA.SEQ[0].PTR = (uint32_t)bclk_seq; - NRF_PWM20->DMA.SEQ[0].MAXCNT = 1; - NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; - - // 2. Setup WS (31.25kHz) - NRF_PWM21->PSEL.OUT[0] = I2S_PIN_LRCK | I2S_PORT_LRCK << 5 | 0 << 31; - NRF_PWM21->ENABLE = 1; - NRF_PWM21->MODE = PWM_MODE_UPDOWN_Up; - NRF_PWM21->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; - NRF_PWM21->COUNTERTOP = 512; // 16MHz / 512 = 31.25kHz - static uint16_t ws_seq[] = {128}; // 50% duty cycle - NRF_PWM21->DECODER = PWM_DECODER_LOAD_Common; - NRF_PWM21->DMA.SEQ[0].PTR = (uint32_t)ws_seq; - NRF_PWM21->DMA.SEQ[0].MAXCNT = 1; - NRF_PWM21->TASKS_DMA.SEQ[0].START = 1; - */ } -/****************************************************************************/ -#define ARM_VTOR (*((volatile uint32_t *)0xE000ED08)) + /****************************************************************************/ void AutoAnalog::adcSetup(void) { - - - if(enableADC == 3) { - - analogReadResolution(14); + + if (enableADC == 3) { + + analogReadResolution(14); pinMode(15 + analogChannel, INPUT); analogRead(15 + analogChannel); //analogReference(AR_INTERNAL); - - R_MSTP->MSTPCRD &= ~(1UL << 16); // MSTPD16 = 0 -> ADC140 enabled - __asm volatile ("nop"); - __asm volatile ("nop"); - + + R_MSTP->MSTPCRD &= ~(1UL << 16); // MSTPD16 = 0 -> ADC140 enabled + __asm volatile("nop"); + __asm volatile("nop"); + R_ADC0->ADCSR_b.ADST = 0; - while (R_ADC0->ADCSR_b.ADST) {} + while (R_ADC0->ADCSR_b.ADST) { + } R_ADC0->ADCSR = 0x8000; R_ADC0->ADANSA[0] = 1 << analogChannel; - //R_ADC0->ADANSA_b[1].ANSA0 = 2; // AN001 - - - // Optional sample time - R_ADC0->ADSSTR[0] = 1; - - - uint8_t timerType = GPT_TIMER; + + R_ADC0->ADSSTR[analogChannel] = 12; + + uint8_t timerType = GPT_TIMER; adc_timer_index = FspTimer::get_available_timer(timerType); if (adc_timer_index < 0) { - FspTimer::force_use_of_pwm_reserved_timer(); - timerType = GPT_TIMER; - adc_timer_index = FspTimer::get_available_timer(timerType); + FspTimer::force_use_of_pwm_reserved_timer(); + timerType = GPT_TIMER; + adc_timer_index = FspTimer::get_available_timer(timerType); } adc_timer.begin(TIMER_MODE_PERIODIC, timerType, adc_timer_index, 16000, 0.0f, my_adc_isr); adc_timer.setup_overflow_irq(); adc_timer.open(); adc_timer.start(); - - } -/* - if (enableADC == 2) { - NRF_I2S->TASKS_STOP = 1; - NRF_I2S->ENABLE = 0; - - NRF_I2S->CONFIG.RXEN = (I2S_CONFIG_RXEN_RXEN_Enabled << I2S_CONFIG_RXEN_RXEN_Pos); - - if (enableDAC != 2) { - NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_Disabled << I2S_CONFIG_TXEN_TXEN_Pos); - } - - if (manualI2S) { - // Slave mode, 16Bit, left aligned - NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; - NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Right << I2S_CONFIG_ALIGN_ALIGN_Pos; - NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; - } - else { - NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; - NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left << I2S_CONFIG_ALIGN_ALIGN_Pos; - NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; - } - - NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Left << I2S_CONFIG_CHANNELS_CHANNELS_Pos; - - // Configure pins - 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); - 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); - 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); - NRF_I2S->PSEL.SDIN = (I2S_PIN_SDIN << I2S_PSEL_SDIN_PIN_Pos) | (I2S_PSEL_SDIN_CONNECT_Connected << I2S_PSEL_SDIN_CONNECT_Pos) | (I2S_PORT_SDIN << I2S_PSEL_SDIN_PORT_Pos); - - // Configure data pointer - NRF_I2S->RXD.PTR = (uint32_t)adcBuf0; - NRF_I2S->RXTXD.MAXCNT = 16; // / sizeof(uint32_t); - } - /*else if (enableADC == 1) { - - set_callback(adcCallback); - - // Enable high frequency oscillator if not already enabled - if (NRF_CLOCK->EVENTS_XOSTARTED == 0) { - NRF_CLOCK->TASKS_XOSTART = 1; - while (NRF_CLOCK->EVENTS_XOSTARTED == 0) { - } - } - - // Set default 16khz sample rate - NRF_PDM->RATIO = ((PDM_RATIO_RATIO_Ratio80 << PDM_RATIO_RATIO_Pos) & PDM_RATIO_RATIO_Msk); - - #if defined __MBED__ - - nrf_pdm_clock_set(NRF_PDM_FREQ_1280K); - // Set default channel mono - nrf_pdm_mode_set(NRF_PDM_MODE_MONO, NRF_PDM_EDGE_LEFTFALLING); - if (gain == -1) { - gain = DEFAULT_PDM_GAIN; - } - nrf_pdm_gain_set(gain, gain); - - pinMode(clkPin, OUTPUT); - digitalWrite(clkPin, LOW); - - pinMode(dinPin, INPUT); - - nrf_pdm_psel_connect(digitalPinToPinName(clkPin), digitalPinToPinName(dinPin)); - - // Enable PDM interrupts and clear events - nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); - nrf_pdm_event_clear(NRF_PDM_EVENT_END); - nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED); - nrf_pdm_int_enable(NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED); - - // Turn on the mic - if (pwrPin > -1) { - pinMode(pwrPin, OUTPUT); - digitalWrite(pwrPin, HIGH); - } - else { - } - - // set the PDM IRQ priority and enable - NVIC_SetPriority(PDM_IRQn, PDM_IRQ_PRIORITY); - NVIC_ClearPendingIRQ(PDM_IRQn); - NVIC_EnableIRQ(PDM_IRQn); - - // enable and trigger start task - nrf_pdm_enable(); - nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); - nrf_pdm_task_trigger(NRF_PDM_TASK_START); - - #else // MBED / Non-Mbed - - nrf_pdm_clock_set(myPDM, NRF_PDM_FREQ_1280K); - - // Set default channel mono - nrf_pdm_mode_set(myPDM, NRF_PDM_MODE_MONO, NRF_PDM_EDGE_LEFTFALLING); - if (gain == -1) { - gain = DEFAULT_PDM_GAIN; - } - nrf_pdm_gain_set(myPDM, gain, gain); - - pinMode(clkPin, OUTPUT); - digitalWrite(clkPin, LOW); - - pinMode(dinPin, INPUT); - - nrf_pdm_psel_connect(myPDM, digitalPinToPinName(clkPin), digitalPinToPinName(dinPin)); - - // Enable PDM interrupts and clear events - nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STARTED); - nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_END); - nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STOPPED); - nrf_pdm_int_enable(myPDM, NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED); - - // Turn on the mic - if (pwrPin > -1) { - pinMode(pwrPin, OUTPUT); - digitalWrite(pwrPin, HIGH); - } - else { - } - - // set the PDM IRQ priority and enable - NVIC_SetPriority(PDM_IRQn, PDM_IRQ_PRIORITY); - NVIC_ClearPendingIRQ(PDM_IRQn); - NVIC_EnableIRQ(PDM_IRQn); - - // enable and trigger start task - nrf_pdm_enable(myPDM); - nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STARTED); - nrf_pdm_task_trigger(myPDM, NRF_PDM_TASK_START); - - #endif - }*/ - /*else if (enableADC == 3) { - - NRF_SAADC->CH[0].PSELP = 4 << SAADC_CH_PSELP_PIN_Pos | 1 << SAADC_CH_PSELP_PORT_Pos | 1 << SAADC_CH_PSELP_CONNECT_Pos | 0 << SAADC_CH_PSELP_INTERNAL_Pos; - NRF_SAADC->CH[0].PSELN = 4 << SAADC_CH_PSELN_PIN_Pos | 1 << SAADC_CH_PSELN_PORT_Pos | 1 << SAADC_CH_PSELN_CONNECT_Pos | 0 << SAADC_CH_PSELN_INTERNAL_Pos; - NRF_SAADC->CH[0].CONFIG = SAADC_CH_CONFIG_GAIN_Gain2 << SAADC_CH_CONFIG_GAIN_Pos | SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos | 40 << SAADC_CH_CONFIG_TACQ_Pos | SAADC_CH_CONFIG_MODE_Diff << SAADC_CH_CONFIG_MODE_Pos | SAADC_CH_CONFIG_BURST_Disabled << SAADC_CH_CONFIG_BURST_Pos; - NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit << SAADC_RESOLUTION_VAL_Pos; - NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over2x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos; - NRF_SAADC->SAMPLERATE = 16000000 / 16000 / 2 | SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos; - NRF_SAADC->RESULT.PTR = (uint32_t)adcBuf0; - NRF_SAADC->RESULT.MAXCNT = 16; - NRF_SAADC->ENABLE = true; - - NRF_SAADC->TASKS_CALIBRATEOFFSET = true; - while (!NRF_SAADC->EVENTS_CALIBRATEDONE) { - } - - NRF_SAADC->EVENTS_STARTED = 0; - NRF_SAADC->TASKS_START = 1; - while (!NRF_SAADC->EVENTS_STARTED) { - }; - while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos)) - ; - - uint32_t *vector_table = (uint32_t *)ARM_VTOR; - vector_table[SAADC_IRQn + 16] = (uint32_t)SAADC_IRQHandler; - NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk | SAADC_INTENSET_STARTED_Msk; - NVIC_SetPriority(SAADC_IRQn, 7); - NVIC_ClearPendingIRQ(SAADC_IRQn); - NVIC_EnableIRQ(SAADC_IRQn); - __enable_irq(); -Serial.println("enable IRQ"); - NRF_SAADC->TASKS_SAMPLE = 1; - } // USE_I2S - */ } /****************************************************************************/ @@ -853,129 +326,50 @@ void AutoAnalog::adcInterrupts(bool enabled) void AutoAnalog::dacSetup(void) { - - if(enableDAC == 3){ - analogWriteResolution(12); + if (enableDAC == 3) { + + analogWriteResolution(12); analogWrite(A0, 0); - - R_DAC->DACR = 0x5F; // enable - R_DAC->DADPR = 0; // Right justified + + R_DAC->DACR = 0x5F; // enable + R_DAC->DADPR = 0; // Right justified R_DAC->DAADSCR = 1 << 7; // Sync ADC14 and DAC12 //R_DAC->DAVREFCR = 1 << 3 | 1 << 2; // VREFH/VREFL - + uint8_t timer_type = GPT_TIMER; high_speed_timer_index = FspTimer::get_available_timer(timer_type); if (high_speed_timer_index < 0) { - FspTimer::force_use_of_pwm_reserved_timer(); - timer_type = GPT_TIMER; - high_speed_timer_index = FspTimer::get_available_timer(timer_type); + FspTimer::force_use_of_pwm_reserved_timer(); + timer_type = GPT_TIMER; + high_speed_timer_index = FspTimer::get_available_timer(timer_type); } - + high_speed_timer.begin( - TIMER_MODE_PERIODIC, // Fire continuously at the specified interval - timer_type, // Use the General PWM Timer peripheral block - high_speed_timer_index,// Selected hardware channel channel - 16000.0, // Target Frequency in Hz (16 kHz) - 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) - dac_callback // Name of your ISR function to execute + TIMER_MODE_PERIODIC, // Fire continuously at the specified interval + timer_type, // Use the General PWM Timer peripheral block + high_speed_timer_index, // Selected hardware channel channel + 16000.0, // Target Frequency in Hz (16 kHz) + 0.0, // Duty cycle (unused for generic interrupts, keep 0.0) + dac_callback // Name of your ISR function to execute ); - + high_speed_timer.setup_overflow_irq(); high_speed_timer.open(); high_speed_timer.start(); - - - } - - /*if (enableDAC == 2) { - NRF_I2S->TASKS_STOP = 1; - NRF_I2S->ENABLE = 0; - // Enable transmission - - if (enableADC != 2) { - NRF_I2S->CONFIG.RXEN = (I2S_CONFIG_RXEN_RXEN_Disabled << I2S_CONFIG_RXEN_RXEN_Pos); - //NRF_PWM0->TASKS_STOP = 1; - //NRF_PWM1->TASKS_STOP = 1; - } - NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_Enabled << I2S_CONFIG_TXEN_TXEN_Pos); - - - if (manualI2S) { - NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_32Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; - NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Right << I2S_CONFIG_ALIGN_ALIGN_Pos; - NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; - - }else{ - // Enable MCK generator - NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos); - - // Master mode, 16Bit, left aligned - NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master << I2S_CONFIG_MODE_MODE_Pos; - - NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos; - NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos; - NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos; - NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left << I2S_CONFIG_ALIGN_ALIGN_Pos; - // Format = I2S - NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos; - } - - - // Use left channel - NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Left << I2S_CONFIG_CHANNELS_CHANNELS_Pos; - - // Configure pins - 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); - 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); - 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); - 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); - - // NRF_I2S->INTENSET = I2S_INTEN_TXPTRUPD_Enabled << I2S_INTEN_TXPTRUPD_Pos; - // NVIC_EnableIRQ(I2S_IRQn); - - // Configure data pointer - NRF_I2S->TXD.PTR = (uint32_t)&dacBuf0[0]; - //NRF_I2S->RXD.PTR = (uint32_t)dacBuf1; - NRF_I2S->RXTXD.MAXCNT = 16; // / sizeof(uint32_t); } - else if (enableDAC == 1) { - - NRF_PWM20->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 - NRF_PWM20->PSEL.OUT[1] = (DEFAULT_PWM_PIN2 << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos | DEFAULT_PWM_PORT2 << PWM_PSEL_OUT_PORT_Pos); - #endif - NRF_PWM20->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos); - NRF_PWM20->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos); - NRF_PWM20->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); - NRF_PWM20->COUNTERTOP = (((uint16_t)((16000000 / DEFAULT_FREQUENCY))) << PWM_COUNTERTOP_COUNTERTOP_Pos); // 1 msec - NRF_PWM20->LOOP = (0 << PWM_LOOP_CNT_Pos); - NRF_PWM20->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) | (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos); - NRF_PWM20->DMA.SEQ[0].PTR = ((uint32_t)(&dacBuf0[0]) << PWM_DMA_SEQ_PTR_PTR_Pos); - NRF_PWM20->DMA.SEQ[0].MAXCNT = 1 << PWM_DMA_SEQ_MAXCNT_MAXCNT_Pos; //((sizeof(dacBuf0) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos); - NRF_PWM20->SEQ[0].REFRESH = 0; - NRF_PWM20->SEQ[0].ENDDELAY = 0; - - // NRF_PWM0->INTENSET = PWM_INTENSET_SEQEND0_Enabled << PWM_INTENSET_SEQEND0_Pos; - // NVIC_EnableIRQ(PWM0_IRQn); - NRF_PWM20->TASKS_DMA.SEQ[0].START = 1; - }*/ } /****************************************************************************/ void AutoAnalog::disableDAC(bool withinTask) { - if (enableDAC == 3){ + if (enableDAC == 3) { high_speed_timer.stop(); R_DAC->DACR = 0x4F; dacDisabled = true; - }else - if (enableDAC == 2) { + } + else if (enableDAC == 2) { /*NRF_I2S->TASKS_STOP = 1; NRF_I2S->ENABLE = 0;*/ } @@ -1010,214 +404,74 @@ __attribute__((__used__)) void I2S_IRQHandler_v(void) extern "C" { __attribute__((__used__)) void SAADC_IRQHandler(void) { -/* - uint32_t samples = AutoAnalog::aSize; - - if (NRF_SAADC->EVENTS_END) - { - if (!AutoAnalog::adcWhichBuf) { - NRF_SAADC->RESULT.PTR = (uint32_t)AutoAnalog::adcBuf1; - } - else { - NRF_SAADC->RESULT.PTR = (uint32_t)AutoAnalog::adcBuf0; - } - NRF_SAADC->RESULT.MAXCNT = samples; - NRF_SAADC->EVENTS_END = 0; - NRF_SAADC->TASKS_START = 1; - - if (AutoAnalog::adcBitsPerSample == 16) { - if (!AutoAnalog::adcWhichBuf) { - for (uint32_t i = 0; i < samples; i++) { - AutoAnalog::adcBuffer16[i] = AutoAnalog::adcBuf0[i] << 2; - } - } - else { - for (uint32_t i = 0; i < samples; i++) { - AutoAnalog::adcBuffer16[i] = AutoAnalog::adcBuf1[i] << 2; - } - } - } - else if (AutoAnalog::adcBitsPerSample == 8) { - if (!AutoAnalog::adcWhichBuf) { - for (uint32_t i = 0; i < samples; i++) { - AutoAnalog::adcBuffer[i] = AutoAnalog::adcBuf0[i] >> 6; - } - } - else { - for (uint32_t i = 0; i < samples; i++) { - AutoAnalog::adcBuffer[i] = AutoAnalog::adcBuf1[i] >> 6; - } - } - } - AutoAnalog::adcWhichBuf = !AutoAnalog::adcWhichBuf; - AutoAnalog::adcReady = true; - } - - if (NRF_SAADC->EVENTS_STARTED) - { - NRF_SAADC->EVENTS_STARTED = 0; - } - __DSB(); -*/ } } - /****************************************************************************/ -/* #if defined __MBED__ -extern "C" { -__attribute__((__used__)) void PDM_IRQHandler_v(void) +/****************************************************************************/ + +void dac_callback(timer_callback_args_t* p_args) { - if (nrf_pdm_event_check(NRF_PDM_EVENT_STARTED)) { - nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); - // switch to fill + if (AutoAnalog::sCounter < AutoAnalog::aSize) { - if (AutoAnalog::aCtr) { - nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::adcBuf0), AutoAnalog::aSize); - if (AutoAnalog::_onReceive) { - NVIC_DisableIRQ(PDM_IRQn); - AutoAnalog::_onReceive(AutoAnalog::adcBuf1, AutoAnalog::aSize); - NVIC_EnableIRQ(PDM_IRQn); - } + if (AutoAnalog::aCtr == 0) { + R_DAC->DADR[0] = AutoAnalog::dacBuf0[AutoAnalog::sCounter]; } else { - nrf_pdm_buffer_set((uint32_t*)(AutoAnalog::adcBuf1), AutoAnalog::aSize); - if (AutoAnalog::_onReceive) { - NVIC_DisableIRQ(PDM_IRQn); - AutoAnalog::_onReceive(AutoAnalog::adcBuf0, AutoAnalog::aSize); - NVIC_EnableIRQ(PDM_IRQn); - } + R_DAC->DADR[0] = AutoAnalog::dacBuf1[AutoAnalog::sCounter]; } - - // Flip to next buffer - AutoAnalog::aCtr = (AutoAnalog::aCtr + 1) % 2; - } - else if (nrf_pdm_event_check(NRF_PDM_EVENT_STOPPED)) { - nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED); - } - else if (nrf_pdm_event_check(NRF_PDM_EVENT_END)) { - nrf_pdm_event_clear(NRF_PDM_EVENT_END); } + AutoAnalog::sCounter++; } -} - - #elif !defined MBED -extern "C" { -__attribute__((__used__)) void PDM_IRQHandler(void) +extern "C" void my_adc_isr(timer_callback_args_t* p_args) { - if (nrf_pdm_event_check(myPDM, NRF_PDM_EVENT_STARTED)) { - nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STARTED); - - // switch to fill - if (AutoAnalog::aCtr) { - nrf_pdm_buffer_set(myPDM, (uint32_t*)(AutoAnalog::adcBuf0), AutoAnalog::aSize); - if (AutoAnalog::_onReceive) { - NVIC_DisableIRQ(PDM_IRQn); - AutoAnalog::_onReceive(AutoAnalog::adcBuf1, AutoAnalog::aSize); - NVIC_EnableIRQ(PDM_IRQn); - } - } - else { - nrf_pdm_buffer_set(myPDM, (uint32_t*)(AutoAnalog::adcBuf1), AutoAnalog::aSize); - if (AutoAnalog::_onReceive) { - NVIC_DisableIRQ(PDM_IRQn); - AutoAnalog::_onReceive(AutoAnalog::adcBuf0, AutoAnalog::aSize); - NVIC_EnableIRQ(PDM_IRQn); - } - } + (void)p_args; - // Flip to next buffer - AutoAnalog::aCtr = (AutoAnalog::aCtr + 1) % 2; + if (AutoAnalog::adcWhichBuf == 0) { + AutoAnalog::adcBuf0[AutoAnalog::sampleCounter] = R_ADC0->ADDR[AutoAnalog::analogChannel]; } - else if (nrf_pdm_event_check(myPDM, NRF_PDM_EVENT_STOPPED)) { - nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_STOPPED); + else { + AutoAnalog::adcBuf1[AutoAnalog::sampleCounter] = R_ADC0->ADDR[AutoAnalog::analogChannel]; } - else if (nrf_pdm_event_check(myPDM, NRF_PDM_EVENT_END)) { - nrf_pdm_event_clear(myPDM, NRF_PDM_EVENT_END); - } -} -} - -extern "C" { -__attribute__((__used__)) void PWM0_IRQHandler(void) -{ - - // AutoAnalog::sampleCounter++; -} -} - #endif // defined __MBED__ -*/ - - -//volatile uint32_t intCtr = 0; - -void dac_callback(timer_callback_args_t *p_args) { - - /*intCtr++; + AutoAnalog::sampleCounter++; - if(intCtr >= 16000){ - intCtr = 0; - }*/ - - if(AutoAnalog::sCounter < AutoAnalog::aSize){ - - if(AutoAnalog::aCtr == 0){ - R_DAC->DADR[0] = AutoAnalog::dacBuf0[AutoAnalog::sCounter]; - - }else{ - R_DAC->DADR[0] = AutoAnalog::dacBuf1[AutoAnalog::sCounter]; - } - } - AutoAnalog::sCounter++; -} - -extern "C" void my_adc_isr(timer_callback_args_t *p_args) { - - (void)p_args; - - if(AutoAnalog::adcWhichBuf == 0){ - AutoAnalog::adcBuf0[AutoAnalog::sampleCounter] = R_ADC0->ADDR[AutoAnalog::analogChannel]; //analogRead(A1); - }else{ - AutoAnalog::adcBuf1[AutoAnalog::sampleCounter] = R_ADC0->ADDR[AutoAnalog::analogChannel]; - } - - AutoAnalog::sampleCounter++; - - if(AutoAnalog::sampleCounter >= AutoAnalog::aSize){ - if(AutoAnalog::adcWhichBuf == 0){ - if(AutoAnalog::adcBitsPerSample == 8){ - for(uint32_t i=0; i> 6; - } - }else{ - for(uint32_t i=0; i= AutoAnalog::aSize) { + if (AutoAnalog::adcWhichBuf == 0) { + if (AutoAnalog::adcBitsPerSample == 8) { + for (uint32_t i = 0; i < AutoAnalog::aSize; i++) { + AutoAnalog::adcBuffer[i] = AutoAnalog::adcBuf0[i] >> 6; + } + } + else { + for (uint32_t i = 0; i < AutoAnalog::aSize; i++) { + int16_t sample = AutoAnalog::adcBuf0[i] - 8192; + AutoAnalog::adcBuffer16[i] = sample << 2; + } } } - }else{ - if(AutoAnalog::adcBitsPerSample == 8){ - for(uint32_t i=0; i> 6; + else { + if (AutoAnalog::adcBitsPerSample == 8) { + for (uint32_t i = 0; i < AutoAnalog::aSize; i++) { + AutoAnalog::adcBuffer[i] = AutoAnalog::adcBuf1[i] >> 6; + } } - }else{ - for(uint32_t i=0; iADCSR_b.ADST = 1; -} + AutoAnalog::sampleCounter = 0; + AutoAnalog::adcReady = true; + AutoAnalog::adcWhichBuf = !AutoAnalog::adcWhichBuf; + } + R_ADC0->ADCSR_b.ADST = 1; +} void AutoAnalog::set_callback(void (*function)(uint16_t* buf, uint32_t buf_len)) { @@ -1231,5 +485,4 @@ void AutoAnalog::adcCallback(uint16_t* buf, uint32_t buf_len) adcReady = true; } - #endif //#if defined (ARDUINO_ARCH_SAM) \ No newline at end of file From c511628e42d56c85b271afb326a5cee160a9869b Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Sat, 8 Aug 2026 13:13:39 -0600 Subject: [PATCH 14/16] Add radio examples for R4 --- .../UnoR4/RadioRX_UnoR4/RadioRX_UnoR4.ino | 42 +++++++++++++++++++ .../UnoR4/RadioTX_UnoR4/RadioTX_UnoR4.ino | 42 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 examples/Platforms/UnoR4/RadioRX_UnoR4/RadioRX_UnoR4.ino create mode 100644 examples/Platforms/UnoR4/RadioTX_UnoR4/RadioTX_UnoR4.ino diff --git a/examples/Platforms/UnoR4/RadioRX_UnoR4/RadioRX_UnoR4.ino b/examples/Platforms/UnoR4/RadioRX_UnoR4/RadioRX_UnoR4.ino new file mode 100644 index 0000000..722bcc7 --- /dev/null +++ b/examples/Platforms/UnoR4/RadioRX_UnoR4/RadioRX_UnoR4.ino @@ -0,0 +1,42 @@ + +#include +#include + +AutoAnalog aaAudio; +RF24 radio(7,8); + +uint8_t address[6] = { "1Node" }; +#define bufferSize 16 + +void setup() { + Serial.begin(115200); + while(!Serial){} + Serial.println("Analog Audio Begin"); + + radio.begin(); + radio.setChannel(23); + radio.setPayloadSize(32); + radio.setAutoAck(0); + radio.openReadingPipe(1, address); + radio.startListening(); + + aaAudio.begin(0, 3); //Setup aaAudio using DAC and ADC + aaAudio.dacBitsPerSample = 16; + aaAudio.adcBitsPerSample = 16; + aaAudio.setSampleRate(44100); + +} + +uint32_t timer = millis(); + +void loop() { + + if(radio.available()){ + if(millis() - timer > 1000){ + Serial.println("Data received"); + timer = millis(); + } + radio.read(aaAudio.dacBuffer16, bufferSize * 2); // Each 16-bit sample takes up 2 bytes + aaAudio.feedDAC(0,bufferSize); + } +} diff --git a/examples/Platforms/UnoR4/RadioTX_UnoR4/RadioTX_UnoR4.ino b/examples/Platforms/UnoR4/RadioTX_UnoR4/RadioTX_UnoR4.ino new file mode 100644 index 0000000..23b5bba --- /dev/null +++ b/examples/Platforms/UnoR4/RadioTX_UnoR4/RadioTX_UnoR4.ino @@ -0,0 +1,42 @@ + +#include +#include + +AutoAnalog aaAudio; +RF24 radio(7,8); + +uint8_t address[6] = { "1Node" }; + +#define bufferSize 16 + +void setup() { + Serial.begin(115200); + Serial.println("Analog Audio Begin"); + + //Set pins low for MAX9814 microphone AR and GAIN pins + pinMode(5,OUTPUT); + digitalWrite(5,LOW); + + pinMode(6,OUTPUT); + digitalWrite(6,LOW); + + radio.begin(); + radio.setChannel(23); + radio.setPayloadSize(32); + radio.setAutoAck(0); + radio.openWritingPipe(address); + radio.stopListening(); + + aaAudio.begin(3, 0); //Setup aaAudio using DAC and ADC + aaAudio.dacBitsPerSample = 16; + aaAudio.adcBitsPerSample = 16; + aaAudio.setSampleRate(44100); + radio.printDetails(); +} + +void loop() { + + aaAudio.getADC(bufferSize); // Get buffersize of 16-bit samples + radio.writeFast(aaAudio.adcBuffer16, bufferSize * 2); // Each 16-bit sample takes up 2 bytes + +} From 1c5fbdd259e53dcd7d9507e1029669658235e3d2 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Sat, 8 Aug 2026 17:06:28 -0600 Subject: [PATCH 15/16] Add WiFi streaming example for R4 - Add WiFi streaming example for R4 - Update library.properties and json for R4 devices - Adjust buffer size to 512 from 256 for R4 devices --- .../UnoR4/WiFi_TX_UnoR4/WiFi_TX_UnoR4.ino | 151 ++++++++++++++++++ .../Platforms/UnoR4/WiFi_TX_UnoR4/secrets.h | 2 + library.json | 3 +- library.properties | 2 +- src/AutoAnalog_config.h | 2 +- 5 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 examples/Platforms/UnoR4/WiFi_TX_UnoR4/WiFi_TX_UnoR4.ino create mode 100644 examples/Platforms/UnoR4/WiFi_TX_UnoR4/secrets.h diff --git a/examples/Platforms/UnoR4/WiFi_TX_UnoR4/WiFi_TX_UnoR4.ino b/examples/Platforms/UnoR4/WiFi_TX_UnoR4/WiFi_TX_UnoR4.ino new file mode 100644 index 0000000..11c60bb --- /dev/null +++ b/examples/Platforms/UnoR4/WiFi_TX_UnoR4/WiFi_TX_UnoR4.ino @@ -0,0 +1,151 @@ +#include +#include "WiFiS3.h" +#include +#include "secrets.h" + +char ssid[] = SECRET_SSID; +char pass[] = SECRET_PASS; +int status = WL_IDLE_STATUS; + +/*********************** USER CONFIG ****************************/ +const char* myName = "Arduino-R4"; +const char* targetIP = "10.10.1.174"; +const uint16_t targetPort = 5004; + +// Set the above targetIP to the IP of your VLC machine +// In VLC open a Network Stream at rtp://@:5004 + +/********************************************************/ + +// RTP Configuration - 8-bit PCM at 8kHz +const uint8_t RTP_PAYLOAD_TYPE = 0; // PCMU (will work for raw PCM too) +const uint16_t SAMPLE_RATE = 8000; +const uint16_t SAMPLES_PER_PACKET = 512; + +uint16_t rtp_sequence = 0; +uint32_t rtp_timestamp = 0; +uint32_t rtp_ssrc = 0x12345678; + +AutoAnalog aaAudio; +WiFiUDP udp; + +#define bufferSize 512 + +void setup() { + Serial.begin(115200); + + modem.begin(); + WiFi.setHostname(myName); + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + status = WiFi.begin(ssid, pass); + delay(10000); + } + Serial.print("IP Address: "); + Serial.println(WiFi.localIP()); + + Serial.println("Analog Audio Begin"); + pinMode(5, OUTPUT); + digitalWrite(5, LOW); + pinMode(6, OUTPUT); + digitalWrite(6, LOW); + + aaAudio.begin(3, 0); + aaAudio.dacBitsPerSample = 16; + aaAudio.adcBitsPerSample = 16; + aaAudio.setSampleRate(8000); + + udp.begin(4444); +} + +uint32_t timer = millis(); +uint32_t packetCount = 0; + + +void loop() { + aaAudio.getADC(bufferSize); + + + uint8_t finalBuf[bufferSize]; + for(int i=0; i 1000){ + timer = millis(); + Serial.print("Packets/sec: "); + Serial.print(packetCount); + Serial.print(" | Seq: "); + Serial.print(rtp_sequence); + Serial.print(" | TS: "); + Serial.println(rtp_timestamp); + packetCount = 0; + } +} + +void sendRTPPacket(uint8_t* payload, int payload_len) { + uint8_t rtpPacket[12 + payload_len]; + + rtpPacket[0] = 0x80; + rtpPacket[1] = (0 << 7) | RTP_PAYLOAD_TYPE; + + rtpPacket[2] = (rtp_sequence >> 8) & 0xFF; + rtpPacket[3] = rtp_sequence & 0xFF; + rtp_sequence++; + + rtpPacket[4] = (rtp_timestamp >> 24) & 0xFF; + rtpPacket[5] = (rtp_timestamp >> 16) & 0xFF; + rtpPacket[6] = (rtp_timestamp >> 8) & 0xFF; + rtpPacket[7] = rtp_timestamp & 0xFF; + rtp_timestamp += SAMPLES_PER_PACKET; + + rtpPacket[8] = (rtp_ssrc >> 24) & 0xFF; + rtpPacket[9] = (rtp_ssrc >> 16) & 0xFF; + rtpPacket[10] = (rtp_ssrc >> 8) & 0xFF; + rtpPacket[11] = rtp_ssrc & 0xFF; + + memcpy(&rtpPacket[12], payload, payload_len); + + udp.beginPacket(targetIP, targetPort); + udp.write(rtpPacket, 12 + payload_len); + udp.endPacket(); +} + +uint8_t encodePcm16ToPcmu(int16_t sample) { + // 1. Extract sign bit (0x80 for negative, 0x00 for positive) + uint8_t sign = (sample < 0) ? 0x80 : 0x00; + if (sample < 0) { + // Convert to absolute value safely handling INT16_MIN + sample = (sample == INT16_MIN) ? INT16_MAX : -sample; + } + + // 2 & 3. Add G.711 bias and clip to max 15-bit value + sample += 33; + if (sample > 32767) { + sample = 32767; + } + + // 4. Determine exponent (chord) + // Find the position of the highest set bit + int16_t exponent = 7; + for (int16_t mask = 0x4000; (sample & mask) == 0 && exponent > 0; mask >>= 1) { + exponent--; + } + + // 5. Extract mantissa (step) - 4 bits following the leading 1 + uint8_t mantissa = (sample >> (exponent + 3)) & 0x0F; + + // 6. Combine and flip all bits (G.711 standard requirement) + return ~(sign | (exponent << 4) | mantissa); +} diff --git a/examples/Platforms/UnoR4/WiFi_TX_UnoR4/secrets.h b/examples/Platforms/UnoR4/WiFi_TX_UnoR4/secrets.h new file mode 100644 index 0000000..edaf36a --- /dev/null +++ b/examples/Platforms/UnoR4/WiFi_TX_UnoR4/secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "mySSID" +#define SECRET_PASS "myPassword" diff --git a/library.json b/library.json index 68fe80a..5f9e505 100644 --- a/library.json +++ b/library.json @@ -21,7 +21,8 @@ "atmelavr", "atmelsam", "espressifesp32", - "nordicnrf52" + "nordicnrf52", + "renesas-ra" ], "export": { "exclude": "examples/*/*.wav" diff --git a/library.properties b/library.properties index a6d518b..adb30f3 100644 --- a/library.properties +++ b/library.properties @@ -6,4 +6,4 @@ sentence=Automated analog reads and analog output (streaming) using Arduino DAC( paragraph=Simplified API for Arduino DAC, ADC, Timers & DMA, designed with radio & wireless communication in mind. Easily create a wide variety of audio related applications. category=Signal Input/Output url=https://github.com/TMRh20/AutoAnalogAudio -architectures=avr,sam,esp32,nrf52 +architectures=avr,sam,esp32,nrf52,renesas diff --git a/src/AutoAnalog_config.h b/src/AutoAnalog_config.h index bea06e7..ed2e7c6 100644 --- a/src/AutoAnalog_config.h +++ b/src/AutoAnalog_config.h @@ -24,7 +24,7 @@ #elif defined (ARDUINO_ARCH_RENESAS) - #define MAX_BUFFER_SIZE 256 + #define MAX_BUFFER_SIZE 512 #elif defined ESP32 || defined ARDUINO_ARCH_NRF52840 || defined (ARDUINO_ARCH_NRF52) || defined ARDUINO_NRF52840_FEATHER || defined ARDUINO_NRF54L15 From 8024752fa5e3449e2e196867aef81631af276ea0 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Sun, 9 Aug 2026 06:37:42 -0600 Subject: [PATCH 16/16] Minor changes - Keep wifi stack updated while waiting for ADC results - set adcReady to false in CTOR - simple code to handle adc overruns --- src/RA41M/AutoAnalogAudio.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/RA41M/AutoAnalogAudio.cpp b/src/RA41M/AutoAnalogAudio.cpp index 8f30757..bce8ec1 100644 --- a/src/RA41M/AutoAnalogAudio.cpp +++ b/src/RA41M/AutoAnalogAudio.cpp @@ -24,7 +24,9 @@ along with this program. If not, see . #include "FspTimer.h" #include "r_timer_api.h" #include "r_adc.h" - + #if defined ARDUINO_UNOR4_WIFI + #include "WiFiS3.h" + #endif FspTimer high_speed_timer; FspTimer adc_timer; uint8_t high_speed_timer_index; @@ -57,7 +59,7 @@ void dac_callback(timer_callback_args_t* p_args); AutoAnalog::AutoAnalog() { - adcReady = true; + adcReady = false; adcBitsPerSample = 8; dacBitsPerSample = 8; autoAdjust = true; @@ -203,7 +205,13 @@ void AutoAnalog::disableAdcChannel(uint8_t pinAx) void AutoAnalog::getADC(uint32_t samples) { - while (!adcReady) { + while (!adcReady) { + #if defined ARDUINO_UNOR4_WIFI + WiFi.status(); + delayMicroseconds(100); + #else + yield(); + #endif } adcReady = false; @@ -438,7 +446,7 @@ extern "C" void my_adc_isr(timer_callback_args_t* p_args) AutoAnalog::sampleCounter++; - if (AutoAnalog::sampleCounter >= AutoAnalog::aSize) { + if (AutoAnalog::sampleCounter >= AutoAnalog::aSize && AutoAnalog::adcReady == false) { if (AutoAnalog::adcWhichBuf == 0) { if (AutoAnalog::adcBitsPerSample == 8) { for (uint32_t i = 0; i < AutoAnalog::aSize; i++) { @@ -465,11 +473,16 @@ extern "C" void my_adc_isr(timer_callback_args_t* p_args) } } } - AutoAnalog::sampleCounter = 0; AutoAnalog::adcReady = true; + AutoAnalog::sampleCounter = 0; + AutoAnalog::adcWhichBuf = !AutoAnalog::adcWhichBuf; + }else + if (AutoAnalog::sampleCounter >= AutoAnalog::aSize){ + AutoAnalog::sampleCounter = 0; AutoAnalog::adcWhichBuf = !AutoAnalog::adcWhichBuf; } - + + R_ADC0->ADCSR_b.ADST = 1; }