Basic ADC Example


#1

Would it be possible to get a simple ADC example or as simple as is possible? I mean something like the AnalogReadSerial Arduino example, read from AIN0 and output to the serial terminal.

I’ve been trying to get the SAADC example from the sdk to work but it seems every missing library I add creates more missing library errors.


#2

Hi there,
I have pushed a simple SAADC example to github repo. You can take that as a start point. Here is the example:

If you have any problem, just let me know. :grinning:

Zelin


#3

Thanks for the help, that made it much easier to understand :+1:

I modified it slightly to test a number of ADC pins during each cycle, here is my code in case it is useful to other beginners like me.

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#define SAMPLES_IN_BUFFER 5
volatile uint8_t state = 1;

static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t     m_ppi_channel;
static uint32_t              m_adc_evt_counter;

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}


void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every 400ms */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}


void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;

        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);


        NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);

        NRF_LOG_INFO("AIN0 = %d mV", p_event->data.done.p_buffer[0] * 3600 / 1024);
        NRF_LOG_INFO("AIN1 = %d mV", p_event->data.done.p_buffer[1] * 3600 / 1024);
        NRF_LOG_INFO("AIN2 = %d mV", p_event->data.done.p_buffer[2] * 3600 / 1024);
        NRF_LOG_INFO("AIN3 = %d mV", p_event->data.done.p_buffer[3] * 3600 / 1024);
        NRF_LOG_INFO("VDD = %d mV", p_event->data.done.p_buffer[4] * 3600 / 1024);

        m_adc_evt_counter++;

    }
}


void saadc_init(void)
{
    ret_code_t err_code;


    nrf_saadc_channel_config_t channel_0_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_1_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_2_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_3_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_VDD_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD); // set VDD as input, you can use AIN0~AIN7 instead.

	    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(3, &channel_3_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(4, &channel_VDD_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
    	APP_ERROR_CHECK(err_code);

}


/**
 * @brief Function for main application entry.
 */
int main(void)
{
    uint32_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    ret_code_t ret_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(ret_code);

    saadc_init();
    saadc_sampling_event_init();
    saadc_sampling_event_enable();
    NRF_LOG_INFO("SAADC HAL simple example started.");

    while (1)
    {
        nrf_pwr_mgmt_run();
        NRF_LOG_FLUSH();
    }
}