Is there any ADC examples for nRF Connect SDK?

Hello,

I can see there are some ADC examples on Github https://github.com/NordicPlayground/nRF52-ADC-examples But those examples are nRF SDK5. Are there any ADC examples for the nRF Connect SDK?

I am using the NCS 2.2.0 on Window

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/adc.h>

//LOG_MODULE_REGISTER(sensor, LOG_LEVEL_DBG);
LOG_MODULE_REGISTER(ctrl, LOG_LEVEL_DBG);

#define SLEEP_INTERVAL 30000
#define ADC_NODE DT_NODELABEL(adc)
static const struct device *adc_dev = DEVICE_DT_GET(ADC_NODE);

// nRF52840 AnalogInput0 - pin
// AIN0 p0.02
// AIN1 p0.03
// AIN2 p0.04
// AIN3 p0.05
// AIN4 p0.028
// AIN5 p0.029
// AIN6 p0.030
// AIN7 p0.031
#define ADC_RESOLUTION 10                                // the reading value range is 0 to 1023
#define ADC_CHANNEL    0
#define ADC_PORT       SAADC_CH_PSELP_PSELP_AnalogInput2 // AIN2
#define ADC_REFERENCE  ADC_REF_INTERNAL                  // 0.6v
#define ADC_GAIN       ADC_GAIN_1_5                      // ADC_REFERENCE*5

struct adc_channel_cfg ch0_cfg = 
{
	.gain = ADC_GAIN,
	.reference = ADC_REFERENCE,
	.acquisition_time = ADC_ACQ_TIME_DEFAULT,
	.channel_id = ADC_CHANNEL,
#ifdef CONFIG_ADC_NRFX_SAADC
	.input_positive = ADC_PORT
#endif
};

int16_t buffer[1];
struct adc_sequence seq = {
	.channels    = BIT(ADC_CHANNEL),
	.buffer      = buffer,
	.buffer_size = sizeof(buffer),
	.resolution  = ADC_RESOLUTION
};

void main(void)
{
	int err = 0;

	if(!device_is_ready(adc_dev)) {
		LOG_ERR("ADC device is not ready");
		return;
	}

	err = adc_channel_setup(adc_dev, &ch0_cfg);

	while (1)
	{
	    err = adc_read(adc_dev, &seq)
		if(0 != err) {
			LOG_ERR("adc device read erro %dr, terminating", err);
			return;
		}
		int32_t mv = buffer[0];
		int32_t adv_vref = adc_ref_internal(adc_dev);
		adc_raw_to_millivolts(adv_vref, ADC_GAIN, ADC_RESOLUTION, &mv);
		LOG_INF("ADC value, ADC voltage: %d mV", mv);
		k_msleep(SLEEP_INTERVAL);
	}
}

I tried to read the voltage from AIN2 but the code has the following compile error:

c:/ncs/toolchains/v2.2.0/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.1.0/../../../../arm-zephyr-eabi/bin/ld.exe: app/libapp.a(main.c.obj): in function `adc_raw_to_millivolts':
C:\ncs\v2.2.0\zephyr\include\zephyr\drivers\adc.h:750: undefined reference to `adc_gain_invert'
c:/ncs/toolchains/v2.2.0/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.1.0/../../../../arm-zephyr-eabi/bin/ld.exe: app/libapp.a(main.c.obj): in function `main':
D:\projects\Nordic\2.2.0\ADC_Controller\build\zephyr\include\generated\syscalls\kernel.h:100: undefined reference to `__device_dts_ord_72'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
FATAL ERROR: command exited with status 1: 'c:\ncs\toolchains\v2.2.0\opt\bin\cmake.EXE' --build 'd:\projects\Nordic\2.2.0\ADC_Controller\build'

It seems that I need to link a library. Any suggestions? Cheers

  • I found the fix for the compile error. I need CONFIG_ADC=y in the prj.conf :) But I am still looking for the ADC examples for nRF Connect SDK, Cheers and Happy long holiday Slight smile

  • Hello  , 

    r0n9 said:
    I found the fix for the compile error. I need CONFIG_ADC=y in the prj.conf 


    Good to hear you found the solution to that issue Slight smile

    r0n9 said:
    looking for the ADC examples for nRF Connect SDK

    There are some in the Zephyr repository, e.g. the Battery Voltage Measurement sample  or the Analog-to-Digital Converter (ADC) driver sample.

    Let me know how these work for you Slight smile

    Cheers and happy holiday!

    Kind regards,
    Øyvind

  • Solution for Thingy:53

    Basic Solution

    1. Add to prj.comf

    CONFIG_ADC=y
    2. Code snipped
    ...
    
    #include <zephyr/drivers/adc.h>
    
    ...
    
    #define ADC_NODE DT_NODELABEL(adc)
    static const struct device *adc_dev;
    
    ...
    
    static int init_adc(void)
    {
        int err;
    
        adc_channel_cfg.channel_id = 1;
        adc_channel_cfg.gain = ADC_GAIN_1;
        adc_channel_cfg.reference = ADC_REF_INTERNAL;
        adc_channel_cfg.acquisition_time = ADC_ACQ_TIME_DEFAULT;
        adc_channel_cfg.input_positive = 1;
    
        err = adc_channel_setup(adc_dev, &adc_channel_cfg);
        if (err)
        {
            printk("Error in ADC channel setup: %d\n", err);
            return err;
        }
    
        return 0;
    }
    
    static int read_battery_level(void)
    {
        struct adc_sequence sequence = {
            .channels = BIT(1),
            .buffer = &adc_buffer,
            .buffer_size = sizeof(adc_buffer),
            .resolution = 12,
        };
    
        int err = adc_read(adc_dev, &sequence);
        if (err)
        {
            printk("Error in ADC read: %d\n", err);
            return err;
        }
    
        return adc_buffer;
    }
    
    ...
    
    int main(void)
    {
    
    ...
    
        adc_dev = DEVICE_DT_GET(ADC_NODE);
        if (!device_is_ready(adc_dev))
        {
            printk("adc: device not ready.\n");
            return 0;
        }
    
        ret = init_adc();
        if (ret < 0)
        {
            printk("error on adc init");
            return ret;
        }
        
        ...
        
        int battery_level = read_battery_level();
    
    ...
    
    }
    Percentage
    Code differs in that case
    ...
    
    #include <zephyr/drivers/adc.h>
    
    ...
    
    #define ADC_NODE DT_NODELABEL(adc)
    static const struct device *adc_dev;
    
    #define ADC_RESOLUTION 12
    #define ADC_GAIN ADC_GAIN_1_4
    #define ADC_REFERENCE ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
    #define ADC_CHANNEL 1
    
    #define BATTERY_MAX_VOLTAGE 4.2
    #define BATTERY_MIN_VOLTAGE 3.0
    
    static struct adc_channel_cfg adc_channel_cfg;
    static int16_t adc_buffer;
    
    ...
    
    static int init_adc(void)
    {
        int err;
    
        adc_channel_cfg.channel_id = 1;
        adc_channel_cfg.gain = ADC_GAIN_1;
        adc_channel_cfg.reference = ADC_REF_INTERNAL;
        adc_channel_cfg.acquisition_time = ADC_ACQ_TIME_DEFAULT;
        adc_channel_cfg.input_positive = 1;
    
        err = adc_channel_setup(adc_dev, &adc_channel_cfg);
        if (err)
        {
            printk("Error in ADC channel setup: %d\n", err);
            return err;
        }
    
        return 0;
    }
    
    static float read_battery_voltage(void)
    {
        struct adc_sequence sequence = {
            .channels = BIT(ADC_CHANNEL),
            .buffer = &adc_buffer,
            .buffer_size = sizeof(adc_buffer),
            .resolution = ADC_RESOLUTION,
        };
    
        int err = adc_read(adc_dev, &sequence);
        if (err)
        {
            printk("Error in ADC read: %d\n", err);
            return -1;
        }
    
        float adc_voltage = (float)adc_buffer / (1 << ADC_RESOLUTION) * 3.6f; // 3.6V Referenzspannung
        return adc_voltage * 4;                                               // Wegen ADC_GAIN_1_4
    }
    
    static int battery_voltage_to_percent(float voltage)
    {
        if (voltage >= BATTERY_MAX_VOLTAGE)
        {
            return 100;
        }
        else if (voltage <= BATTERY_MIN_VOLTAGE)
        {
            return 0;
        }
        else
        {
            return (int)((voltage - BATTERY_MIN_VOLTAGE) / (BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE) * 100);
        }
    }
    
    ...
    
    int main(void)
    {
    
    ...
    
        adc_dev = DEVICE_DT_GET(ADC_NODE);
        if (!device_is_ready(adc_dev))
        {
            printk("adc: device not ready.\n");
            return 0;
        }
    
        ret = init_adc();
        if (ret < 0)
        {
            printk("error on adc init");
            return ret;
        }
        
        ...
        
        float battery_voltage = read_battery_voltage();
        int battery_percent = battery_voltage_to_percent(battery_voltage);
    
    ...
    
    }
    
Related