Hello,
I am trying to use the SAADC peripheral on my nrf5340dk without using the zephyr API; I am writing my program bare-metal. My goal is to set up the ADC in continuous mode (using the internal timer) with a constant sample rate, and I want an interrupt to be triggered after each read. Here is the code that I am running:
#include "zephyr/sys/printk.h"
#include "nrf.h"
#define ADC NRF_SAADC_S
#define SAMPLE_RATE (10000) // Hz
#define ADC_CLOCK_SPEED (16000000) // Hz
static uint16_t adc_data_buf[1]; // Single sample buffer
static void init_saadc();
static void start_saadc();
int main(void)
{
init_saadc();
start_saadc();
printk("Ready\n");
while (1); // Infinite loop
return 0;
}
static void init_saadc()
{
// Set resolution to 10-bit
ADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
// Configure channel 0 for A0 (AIN0)
ADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0;
ADC->CH[0].CONFIG =
(SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) | // 1/6 gain
(SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) | // internal reference (0.6V)
(SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) | // single-ended mode
(SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos); // 3us acquisition time
// Set result buffer
ADC->RESULT.PTR = (uint32_t)(adc_data_buf);
ADC->RESULT.MAXCNT = 1;
// Configure sampling rate
uint32_t cc = ADC_CLOCK_SPEED / SAMPLE_RATE;
ADC->SAMPLERATE = (cc << SAADC_SAMPLERATE_CC_Pos) |
SAADC_SAMPLERATE_MODE_Timers;
// Enable interrupts for END event
__enable_irq();
ADC->INTENSET = SAADC_INTENSET_END_Set;
NVIC_EnableIRQ(SAADC_IRQn);
NVIC_ClearPendingIRQ(SAADC_IRQn);
NVIC_SetPriority(SAADC_IRQn, 1);
// Enable SAADC
ADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled;
printk("SAADC initialized\n");
}
static void start_saadc()
{
ADC->TASKS_START = 1;
while(!ADC->EVENTS_STARTED);
ADC->EVENTS_STARTED = 0;
ADC->TASKS_SAMPLE = 1;
printk("SAADC started\n");
}
void SAADC_IRQHandler()
{
if (ADC->EVENTS_END)
{
ADC->EVENTS_END = 0; // Clear the END event
printk("ADC Value: %u\n", adc_data_buf[0]);
}
}
I have printk statements throughout the initialization process so that I can see what is being executed. When I run this, I see "SAADC initialized", but I do not see "SAADC started" or "ready"; to me, this indicates that execution is stuck in the infinite loop in my start_saadc() function:
while(!ADC->EVENTS_STARTED); ADC->EVENTS_STARTED = 0;
when I remove these two lines, all of the printk statements are successfully printed to the console, but my interrupt is never triggered, as I do not see it printed to the console.
The only line I have in my prj.conf file is CONFIG_ADC=y, and I am not sure if I need anything else in prj.conf to make this work.
I am new to both ADC and interrupts on nordic, so any help and guidance to solve this issue will be greatly appreciated!
-Taylor