SAADC will not start

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

Related