ADC setup for nRF52832 DK board.

I have an nRF52 DK board with a nRF52832 processor. I need to be able to read the analog voltage input on P0.02/AIN0. what is the simplest way to setup and read from the ADC for the nRF52 DK board. I would appreciate any help you can give since this is a requirement for our project.

  • I am using V2.5.0 with the nRF52DK (nrf52832). I copied the code I have been running for years with the nRF9160 but it fails to build with several errors. any idea what I am doing wrong? This code works with the nRF9160.

    prj.conf
    #TJM Added
    CONFIG_I2C=y
    CONFIG_ADC=y
    CONFIG_ADC_ASYNC=y
    CONFIG_ADC_LOG_LEVEL_INF=y
    CONFIG_ADC_NRFX_SAADC=y
    CONFIG_SPI=y
    CONFIG_SPI_ASYNC=y
    CONFIG_SPI_LOG_LEVEL_INF=y

    ***************************************************************************

    in main.c


    /* start ADC test */
    #include <zephyr/drivers/adc.h>
    #include "../../../v2.5.0/modules/hal/nordic/nrfx/hal/nrf_saadc.h"
    //#include "C:/Nordic1/v2.5.0/modules/hal/nordic/nrfx/hal/nrf_saadc.h"
    #include <math.h>
    #define ADC_BUFFER_SIZE 1  //!< number of ADC channels to read

    #if DT_NODE_HAS_STATUS(DT_ALIAS(adc), okay)
    #define ADC_DEV_NODE DT_ALIAS(adc)
    #elif
    #error "Please set the correct ADC device"
    #endif

    ////#define ADC_DEVICE_NAME DT_ADC_0_NAME
    #define ADC_RESOLUTION 10
    #define ADC_GAIN ADC_GAIN_1_6
    #define ADC_REFERENCE ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10)
    #define ADC_1ST_CHANNEL_ID 0
    #define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN0
    #define ADC_2ND_CHANNEL_ID 1
    #define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1
    #define ADC_3RD_CHANNEL_ID 2
    #define ADC_3RD_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2
    #define ADC_4TH_CHANNEL_ID 3
    #define ADC_4TH_CHANNEL_INPUT NRF_SAADC_INPUT_AIN3
    #define ADC_5TH_CHANNEL_ID 4
    #define ADC_5TH_CHANNEL_INPUT NRF_SAADC_INPUT_AIN4
    #define ADC_6ST_CHANNEL_ID 5
    #define ADC_6ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN5

    const struct device *const adc_dev = DEVICE_DT_GET(ADC_DEV_NODE);

    #if 0
    static const struct adc_channel_cfg m_4th_channel_cfg =   //!< ADC config for ADC input
    {
        .gain = ADC_GAIN,
        .reference = ADC_REFERENCE,
        .acquisition_time = ADC_ACQUISITION_TIME,
        .channel_id = ADC_4TH_CHANNEL_ID,
    #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
        .input_positive = ADC_4TH_CHANNEL_INPUT,
    #endif
    };
    #endif

    #if 0
    static const struct adc_channel_cfg m_3rd_channel_cfg =
    {
        .gain = ADC_GAIN,
        .reference = ADC_REFERENCE,
        .acquisition_time = ADC_ACQUISITION_TIME,
        .channel_id = ADC_3RD_CHANNEL_ID,
    #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
        .input_positive = ADC_3RD_CHANNEL_INPUT,
    #endif
    };
    #endif

    #if 0
    static const struct adc_channel_cfg m_2nd_channel_cfg =   //!< ADC config for Battery input
    {
        .gain = ADC_GAIN,
        .reference = ADC_REFERENCE,
        .acquisition_time = ADC_ACQUISITION_TIME,
        .channel_id = ADC_2ND_CHANNEL_ID,
    #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
        .input_positive = ADC_2ND_CHANNEL_INPUT,
    #endif
    };
    #endif

    #if 1
    static const struct adc_channel_cfg m_1st_channel_cfg =
    {
        .gain = ADC_GAIN,
        .reference = ADC_REFERENCE,
        .acquisition_time = ADC_ACQUISITION_TIME,
        .channel_id = ADC_1ST_CHANNEL_ID,
    #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
        .input_positive = ADC_1ST_CHANNEL_INPUT,
    #endif
    };
    #endif

    static int16_t m_sample_buffer[ADC_BUFFER_SIZE];  //!< buffer to receive ADC data from configured channels

    /*!
     * \fn int adc_sample(void)
     *
     * \brief get a single reading from ADC channel
     *
     * will read ADC_4TH_CHANNEL_ID\n
     * resoultion set to ADC_RESOLUTION in millivolts\n
     * will printout floating point value based on 3.6V max\n
     *
     * \return ADC_RESOLUTION value on ADC_4TH_CHANNEL_ID if pass or -1 if failed\n
     */
    int adc_sample(void)
    {
        int ret;

        const struct adc_sequence sequence =
        {
            .channels = BIT(ADC_1ST_CHANNEL_ID),
    //      .channels = BIT(ADC_1ST_CHANNEL_ID) | BIT(ADC_2ND_CHANNEL_ID) | BIT(ADC_3RD_CHANNEL_ID) | BIT(ADC_4TH_CHANNEL_ID),
    //      .channels =  BIT(ADC_2ND_CHANNEL_ID) | BIT(ADC_4TH_CHANNEL_ID),
            .buffer = m_sample_buffer,
            .buffer_size = sizeof(m_sample_buffer),
            .resolution = ADC_RESOLUTION,
        };

        if (!adc_dev)
        {
            return -1;
        }

    //    jfet_dk_set_led(BATMONENB,1);
    //    k_sleep(K_MSEC(500));
    // k_sleep(K_MSEC(1000));
        ret = adc_read(adc_dev, &sequence);
        if(ret !=0)
          printk("ADC read err: %d\n", ret);

             /* Print the AIN0 values */
        for (int i = 0; i < BUFFER_SIZE; i++)
        {
    //      adc_voltage = (float)(((float)m_sample_buffer[i] / 1023.0f) * 3600.0f);
    //      printf("Measured voltage: %3.2f V\n", adc_voltage);
    //        printf("den: %3.2f\r\n",((pow(2,ADC_RESOLUTION) -1 ) * 1.0)  * 3600.0f);
            adc_voltage[i] = (float)(((float)m_sample_buffer[i] / ((pow(2,ADC_RESOLUTION) -1 ) * 1.0) ) * 3600.0f);
    //      printf("Measured voltage: %3.2f V\n", adc_voltage);
    //        adc_voltage[i] = adc_voltage[i]/1000.0;
            adc_voltage[i] = adc_voltage[i]/10000.0;
    //      printf("ADC raw value: %d 0x%03X\n", m_sample_buffer[i], m_sample_buffer[i]);
    //      printf("Measured voltage: %3.2f V\n", adc_voltage[i] * 10);
        }
    //    jfet_dk_set_led(BATMONENB,0);

        return ret;
    }

    /* end ADC test */

    ****************** in main() ****************************

    /* start ADC test */



        printf("*** ADC Init ***\r\n");

        if (!device_is_ready(adc_dev))      /* check if ADC peripheral ready */
        {
            myPrintfE("ADC device is not ready\n");
            return FALSE;
        }
        myPrintfI("ADC device is ready\n");

     
    #if 1
       err = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
        if (err)
        {
            sprintf(str,"Error in adc AIN0 setup: %d\n", err);
            myPrintfE(str);
        }          
        myPrintfI("ADC AIN0 is ready\n");

        printf("ADC Test Running\r\n");
        while(1)
        {
            err = adc_sample();
            printf("ADC: %3.2f\r\n",adc_voltage[0]);
            k_sleep(K_MSEC(5000));
        }
    #endif

    /* end ADC test */
  • Hello,

    Timothy said:
    I copied the code I have been running for years with the nRF9160 but it fails to build with several errors. any idea what I am doing wrong? This code works with the nRF9160.

    Please share the build log with the errors so that I may take a look at what's going wrong.

    Please take a look at these samples to see demonstrations of how you most easily can use the SAADC in NCS.

    Best regards,
    Karl

  • I have included the output from the build. I wi8ll look at the samples you indicated.

    Building BLE_Prototype
    west build --build-dir c:/Nordic1/test/BLE_Prototype/build c:/Nordic1/test/BLE_Prototype

    [2/9] Building C object CMakeFiles/app.dir/src/main.c.obj
    FAILED: CMakeFiles/app.dir/src/main.c.obj
    C:\Nordic1\toolchains\c57af46cb7\opt\zephyr-sdk\arm-zephyr-eabi\bin\arm-zephyr-eabi-gcc.exe -DKERNEL -DNRF52832_XXAA -D_ANSI_SOURCE -D_FORTIFY_SOURCE=1 -D__LINUX_ERRNO_EXTENSIONS__ -D__PROGRAM_START -D__ZEPHYR__=1 -I../src -I../. -IC:/Nordic1/v2.5.0/nrf/drivers/mpsl/clock_control -IC:/Nordic1/v2.5.0/zephyr/include -Izephyr/include/generated -IC:/Nordic1/v2.5.0/zephyr/soc/arm/nordic_nrf/nrf52 -IC:/Nordic1/v2.5.0/zephyr/lib/libc/newlib/include -IC:/Nordic1/v2.5.0/zephyr/soc/arm/nordic_nrf/common/. -IC:/Nordic1/v2.5.0/zephyr/subsys/bluetooth -IC:/Nordic1/v2.5.0/zephyr/subsys/settings/include -IC:/Nordic1/v2.5.0/nrf/include -IC:/Nordic1/v2.5.0/nrf/lib/multithreading_lock/. -IC:/Nordic1/v2.5.0/nrf/subsys/bluetooth/controller/. -IC:/Nordic1/v2.5.0/zephyr/drivers/flash -IC:/Nordic1/v2.5.0/nrf/tests/include -IC:/Nordic1/v2.5.0/modules/hal/cmsis/CMSIS/Core/Include -IC:/Nordic1/v2.5.0/zephyr/modules/cmsis/. -IC:/Nordic1/v2.5.0/modules/hal/nordic/nrfx -IC:/Nordic1/v2.5.0/modules/hal/nordic/nrfx/drivers/include -IC:/Nordic1/v2.5.0/modules/hal/nordic/nrfx/mdk -IC:/Nordic1/v2.5.0/zephyr/modules/hal_nordic/nrfx/. -IC:/Nordic1/v2.5.0/modules/debug/segger/SEGGER -IC:/Nordic1/v2.5.0/modules/debug/segger/Config -IC:/Nordic1/v2.5.0/modules/crypto/tinycrypt/lib/include -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/fem/common/include -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/fem/nrf21540_gpio/include -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/fem/nrf21540_gpio_spi/include -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/fem/simple_gpio/include -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/fem/include -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/fem/include/protocol -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/include -IC:/Nordic1/v2.5.0/nrfxlib/mpsl/include/protocol -IC:/Nordic1/v2.5.0/nrfxlib/softdevice_controller/include -fno-strict-aliasing -Os -imacros C:/Nordic1/test/BLE_Prototype/build/zephyr/include/generated/autoconf.h -fno-common -g -gdwarf-4 -fdiagnostics-color=always -mcpu=cortex-m4 -mthumb -mabi=aapcs -mfp16-format=ieee --sysroot=C:/Nordic1/toolchains/c57af46cb7/opt/zephyr-sdk/arm-zephyr-eabi/arm-zephyr-eabi -imacros C:/Nordic1/v2.5.0/zephyr/include/zephyr/toolchain/zephyr_stdint.h -Wall -Wformat -Wformat-security -Wno-format-zero-length -Wno-pointer-sign -Wpointer-arith -Wexpansion-to-defined -Wno-unused-but-set-variable -Werror=implicit-int -fno-pic -fno-pie -fno-asynchronous-unwind-tables -fno-reorder-functions --param=min-pagesize=0 -fno-defer-pop -fmacro-prefix-map=C:/Nordic1/test/BLE_Prototype=CMAKE_SOURCE_DIR -fmacro-prefix-map=C:/Nordic1/v2.5.0/zephyr=ZEPHYR_BASE -fmacro-prefix-map=C:/Nordic1/v2.5.0=WEST_TOPDIR -ffunction-sections -fdata-sections -specs=nano.specs -std=c99 -MD -MT CMakeFiles/app.dir/src/main.c.obj -MF CMakeFiles\app.dir\src\main.c.obj.d -o CMakeFiles/app.dir/src/main.c.obj -c ../src/main.c
    In file included from ../src/main.c:40:
    c:\nordic1\v2.5.0\modules\hal\nordic\nrfx\hal\nrf_saadc.h: In function 'nrf_saadc_channel_init':
    ../src/jfet_files/HDC2080.h:66:16: error: expected identifier before numeric constant
    66 | #define CONFIG 0x0E
    | ^~~~
    c:\nordic1\v2.5.0\modules\hal\nordic\nrfx\hal\nrf_saadc.h:1080:24: note: in expansion of macro 'CONFIG'
    1080 | p_reg->CH[channel].CONFIG =
    | ^~~~~~
    c:\nordic1\v2.5.0\modules\hal\nordic\nrfx\hal\nrf_saadc.h: In function 'nrf_saadc_burst_set':
    ../src/jfet_files/HDC2080.h:66:16: error: expected identifier before numeric constant
    66 | #define CONFIG 0x0E
    | ^~~~
    c:\nordic1\v2.5.0\modules\hal\nordic\nrfx\hal\nrf_saadc.h:1099:24: note: in expansion of macro 'CONFIG'
    1099 | p_reg->CH[channel].CONFIG = (p_reg->CH[channel].CONFIG & ~SAADC_CH_CONFIG_BURST_Msk) |
    | ^~~~~~
    ninja: build stopped: subcommand failed.
    FATAL ERROR: command exited with status 1: 'C:\Nordic1\toolchains\c57af46cb7\opt\bin\cmake.EXE' --build 'c:\Nordic1\test\BLE_Prototype\build'

    * The terminal process terminated with exit code: 1.
    * Terminal will be reused by tasks, press any key to close it.

  • Karl I found the problem. I had '#define CONFIG 0x0E' in another source file. I changed it to '#define HDC_CONFIG 0x0E' and now the program builds with no errors and the ADC works. I have no idea what caused this but my code works exactly as it did for the nRF9160. Does any of this make sense? I will test for a bit before we close this. Thanks for you support.

  • Hello,

    I am glad to read that you were able to find the root of the issue, and that everything works as expected now! :) 

    I suppose the CONFIG could be ambiguous in this case, leading to the issue, but I do not immediately see how that would work for the nRF9160 project and not the nRF52832 in this case.

    Please do not hesitate to open another ticket if you should encounter any other issues or questions in the future!

    Best regards,
    Karl

Related