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