Configuring ADC for multichannel using nrfx driver in nrf connect sdk

Hello. I am facing an issue in configuring ADC for multichannels. I was looking at the Nordic fundamentals course Lesson 6 Exercise 2.In this example, the adc is configured to scan single channel when I changed some settings to scan 4 channels I got this error and my code is not working.

Serial output

I don't know what am I doing wrong. I want adc to scan in interrupt. Here is my code.

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <nrfx_saadc.h>
#include <stdint.h>

/* STEP 3.1 - Declare the struct to hold the configuration for the SAADC channel used to sample the battery voltage */
static nrfx_saadc_channel_t channel[4] = {
	NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, 0),
	NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN1, 1),
	NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN2, 2),
	NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN3, 3)
};

/* STEP 3.2 - Declare the buffer to hold the SAAD sample value */
static int16_t sample[4];
static uint32_t counter = 0;

/* STEP 4.1 - Define the battery sample interval */
#define BATTERY_SAMPLE_INTERVAL_MS 1000

/* STEP 4.3 - Add forward declaration of timer callback handler */
static void battery_sample_timer_handler(struct k_timer *timer);

/* STEP 4.2 - Define the battery sample timer instance */
K_TIMER_DEFINE(battery_sample_timer, battery_sample_timer_handler, NULL);

/* STEP 7.1 - Implement timer callback handler function */
void battery_sample_timer_handler(struct k_timer *timer)
{
	/* STEP 7.2 - Trigger the sampling */
	nrfx_err_t err = nrfx_saadc_mode_trigger();
	if (err != NRFX_SUCCESS)
	{
		printk("nrfx_saadc_mode_trigger error: %08x", err);
		return;
	}

	printk("\n-------------------Reading - %d-------------------\n", counter++);
	for (int i = 0; i < 4; i++)
	{
		printk("SAADC%d sample: %d    \n", i, sample[i]);
	}
}

static void configure_saadc(void)
{
	/* STEP 5.1 - Connect ADC interrupt to nrfx interrupt handler */
	IRQ_CONNECT(DT_IRQN(DT_NODELABEL(adc)), DT_IRQ(DT_NODELABEL(adc), priority), nrfx_isr, nrfx_saadc_irq_handler, 0);

	/* STEP 5.2 - Connect ADC interrupt to nrfx interrupt handler */
	nrfx_err_t err = nrfx_saadc_init(DT_IRQ(DT_NODELABEL(adc), priority));
	if (err != NRFX_SUCCESS)
	{
		printk("nrfx_saadc_mode_trigger error: %08x", err);
		return;
	}

	/* STEP 5.3 - Configure the SAADC channel */
	for (int i = 0; i < 4; i++)
	{
		channel[i].channel_config.gain = NRF_SAADC_GAIN1_4;
		channel[i].channel_config.acq_time = NRF_SAADC_ACQTIME_40US;
		channel[i].channel_config.reference = NRF_SAADC_REFERENCE_VDD4;

		err = nrfx_saadc_channels_config(&channel[i], (i + 1));
		if (err != NRFX_SUCCESS)
		{
			printk("nrfx_saadc_channels_config error: %08x", err);
			return;
		}
	}

	/* STEP 5.4 - Configure nrfx_SAADC driver in simple and blocking mode */
	err = nrfx_saadc_simple_mode_set(BIT(0) | BIT(1) | BIT(2) | BIT(3),
									 NRF_SAADC_RESOLUTION_12BIT,
									 NRF_SAADC_OVERSAMPLE_DISABLED,
									 NULL);
	if (err != NRFX_SUCCESS)
	{
		printk("nrfx_saadc_simple_mode_set error: %08x", err);
		return;
	}

	/* STEP 5.5 - Set buffer where sample will be stored */
	err = nrfx_saadc_buffer_set(&sample, 4);
	if (err != NRFX_SUCCESS)
	{
		printk("nrfx_saadc_buffer_set error: %08x", err);
		return;
	}

	/* STEP 6 - Start periodic timer for battery sampling */
	k_timer_start(&battery_sample_timer, K_NO_WAIT, K_MSEC(BATTERY_SAMPLE_INTERVAL_MS));
}

int main(void)
{
	configure_saadc();

	k_sleep(K_FOREVER);
	return 0;
}

Parents Reply
  • nrfx_saadc_simple_mode_set(BIT(0) | BIT(1) | BIT(2) | BIT(3),
                                         NRF_SAADC_RESOLUTION_12BIT,
                                         NRF_SAADC_OVERSAMPLE_DISABLED,
                                         NULL);
    this function, when I removed BIT(1) | BIT(2) | BIT(3)
    it is working or when I set it to only one bit like BIT(2) it is also working but with bit masking, it is not working.
Children
  • I somehow fixed the code and it is working fine. Scans 4 channels in interrupt. Here is the code

    #include <zephyr/kernel.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/sys/printk.h>
    
    /* STEP 2 - Include header for nrfx SAADC driver */
    #include <nrfx_saadc.h>
    
    #define SAADC_CHANNEL_COUNT     4
    #define GreenLED1_NODE          DT_ALIAS(greenled1)
    
    static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(GreenLED1_NODE, gpios);
    
    /* STEP 3.1 - Declare the struct to hold the configuration for the SAADC channel used to sample the battery voltage */
    static nrfx_saadc_channel_t channels[SAADC_CHANNEL_COUNT] = {
        NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, 0),
        NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN1, 1),
        NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN2, 2),
        NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN3, 3),
    };
    
    /* STEP 3.2 - Declare the buffer to hold the SAAD sample value */
    static int16_t sample[SAADC_CHANNEL_COUNT];
    
    /* STEP 4.1 - Define the battery sample interval */
    #define BATTERY_SAMPLE_INTERVAL_MS 50
    
    /* STEP 4.3 - Add forward declaration of timer callback handler */
    static void battery_sample_timer_handler(struct k_timer *timer);
    
    /* STEP 4.2 - Define the battery sample timer instance */
    K_TIMER_DEFINE(battery_sample_timer, battery_sample_timer_handler, NULL);
    
    static void saadc_event_handler(nrfx_saadc_evt_t const *p_event)
    {
        if (p_event->type == NRFX_SAADC_EVT_DONE)
        {
            nrfx_err_t err;
    
            // Retrieve the sampled data from the buffer
            for (int i = 0; i < p_event->data.done.size; i++)
            {
                sample[i] = p_event->data.done.p_buffer[i];
            }
    
            // Print voltage values
            float voltage[4] = {0.0f};
            for (int i = 0; i < SAADC_CHANNEL_COUNT; i++)
            {
                sample[i] = MAX(sample[i], 0);
                voltage[i] = (sample[i] / 4096.0f * 3.3f);
                printk("Channel %d sample: %d    %.3f\n", i, sample[i], voltage[i]);
            }
    
            printk("\n\n");
    
            // Re-set the buffer and start another sampling cycle
            err = nrfx_saadc_buffer_set(p_event->data.done.p_buffer, SAADC_CHANNEL_COUNT);
            if (err != NRFX_SUCCESS)
            {
                printk("nrfx_saadc_buffer_set error: %08x", err);
            }
        }
    }
    
    /* STEP 7.1 - Implement timer callback handler function */
    void battery_sample_timer_handler(struct k_timer *timer)
    {
        /* STEP 7.2 - Trigger the sampling */
        nrfx_err_t err = nrfx_saadc_mode_trigger();
        if (err != NRFX_SUCCESS)
        {
            printk("nrfx_saadc_mode_trigger error: %08x", err);
            return;
        }
    
        /* STEP 7.3 - Calculate and print voltage */
        // int battery_voltage = ((600 * 6) * sample) / ((1 << 12));
    
        float voltage[4] = { 0.0f };
    
        for (int i = 0; i < SAADC_CHANNEL_COUNT; i++)
        {
            voltage[i] = (sample[i] / 4096.0f * 3.3f);
            printk("Channel %d sample: %d    %.3f\n", i, sample[i], voltage[i]);
        }
    
        printk("\n\n");
        // printk("Battery Voltage: %d mV\n", battery_voltage);
    }
    
    static void configure_saadc(void)
    {
        /* STEP 5.1 - Connect ADC interrupt to nrfx interrupt handler */
        IRQ_CONNECT(DT_IRQN(DT_NODELABEL(adc)),
                    DT_IRQ(DT_NODELABEL(adc), priority),
                    nrfx_isr, nrfx_saadc_irq_handler, 0);
    
        /* STEP 5.2 - Connect ADC interrupt to nrfx interrupt handler */
        nrfx_err_t err = nrfx_saadc_init(DT_IRQ(DT_NODELABEL(adc), priority));
        if (err != NRFX_SUCCESS)
        {
            printk("nrfx_saadc_mode_trigger error: %08x", err);
            return;
        }
    
        /* STEP 5.3 - Configure the SAADC channel */
        for (int i = 0; i < SAADC_CHANNEL_COUNT; i++)
        {
            channels[i].channel_config.gain = NRF_SAADC_GAIN1_4;
            channels[i].channel_config.reference = NRF_SAADC_REFERENCE_VDD4;
            channels[i].channel_config.acq_time = NRF_SAADC_ACQTIME_40US;
        }
        err = nrfx_saadc_channels_config(&channels[0], 4);
        if (err != NRFX_SUCCESS)
        {
            printk("nrfx_saadc_channel_init error for channel %08x\n", err);
            return;
        }
    
        /* STEP 5.4 - Configure nrfx_SAADC driver in simple and blocking mode */
        err = nrfx_saadc_simple_mode_set(BIT(0) | BIT(1) | BIT(2) | BIT(3),
                                         NRF_SAADC_RESOLUTION_12BIT,
                                         NRF_SAADC_OVERSAMPLE_DISABLED,
                                         saadc_event_handler);
        if (err != NRFX_SUCCESS)
        {
            printk("nrfx_saadc_simple_mode_set error: %08x", err);
            return;
        }
    
        /* STEP 5.5 - Set buffer where sample will be stored */
        err = nrfx_saadc_buffer_set(&sample, 4);
        if (err != NRFX_SUCCESS)
        {
            printk("nrfx_saadc_buffer_set error: %08x", err);
            return;
        }
    
        /* STEP 6 - Start periodic timer for battery sampling */
        k_timer_start(&battery_sample_timer, K_NO_WAIT, K_MSEC(BATTERY_SAMPLE_INTERVAL_MS));
    }
    
    int configureLED(void)
    {
        int ret;
    
        if (!device_is_ready(led1.port))
        {
            printk("Device %s is not ready\n", &led1.port->name);
            return -1;
        }
        ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_INACTIVE);
        if (ret)
        {
            printk("%s failed init (err %d)\n", "LED1", ret);
            return -1;
        } 
    }
    
    int main(void)
    {
        int ret;
    
        printk("ADC Multichannel scan\n");
        configureLED();
        configure_saadc();
    
        while(1)
        {
            ret = gpio_pin_toggle_dt(&led1);
            if (ret < 0)
            {
                return 0;
            }
            k_msleep(100);
        }
    
        return 0;
    }

    Thanks for your help.

Related