ADC configuration for nRF5340DK SDK Connect SES

I need twoADC channels. I tried to configure using :

CONFIG_ADC= y in prj file,

&adc{
#io-channel-cells = < 0x2 >;
};   in overlay file .. the compile error appears as shown in atteched iamge.

Gulzar Singh

Parents
  • Hello,

    SAADC supports 8 channels- One cannel per single-ended input and two channels per differential input. So, If you want two single-ended inputs- you need to create two separate channel configurations; one for AIN0 and one for AIN1 for instance. It has to be defined from the main.c file. Also if you intend to do periodic sample using PPI or collect the sample as part of interrupt handling like this example I linked before https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/reference/peripherals/adc.html?highlight=adc_channel_cfg#c.adc_channel_cfg ; you have to define this in C file.  

    Best Regards,

    Kazi Afroza Sultana

  • Hi, I created an application for testng the sampling of 2 channels on AIN0 and AIN1. The files are attached. I have few doubts.

    1. In the adc.h, is  #define  BUFFER_SIZE 2  right or wrong to sample 2 analog channels ? If in future, 3 chhannels are required, may I set #define  BUFFER_SIZE 3. 

    2. In the main file, I adc instantiated by binding and then, set up channels using err = adc_channel_setup() .. function. Is it proper way ?

    3. As, I copied the most coe from sample program, what is meaning of following ?

    #if defined (CONFIG_BOARD_BMS_NRF5340_CPUAPP)
    NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;

    4. I wrote two sample functions, as in adc.c. Is this proper way to add to sequence ? If, wrong any where, may you make changes and attache corrected code file ?

    5. I called adc sampling functions in repeatitive timer. Is the result of adc from AIN0 and AIN1 be avaialble at same index or at different indices in p_sample_buffer[].

    void my_work_handler(struct k_work *work)
    {int err;
        /* do the processing that needs to be done periodically */
    //********** AIN0 Sample part **************
           err = adc_sample1();
            if (err) {
    //            printk("Error in adc sampling: %d\n", err);
            }
            Var1 = p_sample_buffer[0];
    
    err = adc_sample2();
            if (err) {
    //            printk("Error in adc sampling: %d\n", err);
            }
            Var2 = p_sample_buffer[0];
    }
    K_WORK_DEFINE(my_work, my_work_handler);
    
    void my_timer_handler(struct k_timer *dummy)
    {
        k_work_submit(&my_work);
    }
    
    K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);
    //****************
    void main()
    {
    	//ADC setup
              adc_dev = device_get_binding(ADC_DEVICE_NAME);
                  if (!adc_dev) {
                  printk("device_get_binding ADC (=%s) failed\n", ADC_DEVICE_NAME);
              } 
        
              err = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
              if (err) {
                      printk("Error in adc AIN0 setup: %d\n", err);
                  }
    
              err = adc_channel_setup(adc_dev, &m_2nd_channel_cfg);
              if (err) {
                      printk("Error in adc AIN1 setup: %d\n", err);
                  }
    
              #if defined (CONFIG_BOARD_BMS_NRF5340_CPUAPP)
              NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
              #else
              #error "Choose supported board or add new board for the application"
              #endif
    
    }
    1145.adc.h
    // ADC.C File
    //****************
    static int adc_sample1(void)
    {
    	int ret;
    
    	const struct adc_sequence sequence = {
    		.channels = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer = p_sample_buffer,
    		.buffer_size = sizeof(p_sample_buffer),
    		.resolution = ADC_RESOLUTION,
    	};
    
    	if (!adc_dev) {
    		return -1;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	if (ret) {
    //        printk("adc_read() failed with code %d\n", ret);
    	}
    
    	for (int i = 0; i < BUFFER_SIZE; i++) {
    //                printk("ADC raw value: %d\n", p_sample_buffer[i]);                
            }
    	return ret;
    }
    
    static int adc_sample2(void)
    {
    	int ret;
    
    	const struct adc_sequence sequence = {
    		.channels = BIT(ADC_2ND_CHANNEL_ID),
    		.buffer = p_sample_buffer,
    		.buffer_size = sizeof(p_sample_buffer),
    		.resolution = ADC_RESOLUTION,
    	};
    
    	if (!adc_dev) {
    		return -1;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	if (ret) {
    //        printk("adc_read() failed with code %d\n", ret);
    	}
    
    	for (int i = 0; i < BUFFER_SIZE; i++) {
    //                printk("ADC raw value: %d\n", p_sample_buffer[i]);                
            }
    	return ret;
    }
    //****************
     

    Gulzar Singh  

  • Hello Gulzar,

    I have started looking at your files. Could you please send me the whole project so I can try to reproduce it?

    Best Regards,

    Kazi Afroza Sultana

  • Hi, here is the code in attached file.

    //**********************
    #include <hal/nrf_saadc.h>
    //**********
    #define ADC_DEVICE_NAME DT_LABEL(DT_INST(0, nordic_nrf_saadc))
    #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  BUFFER_SIZE 2
    int err;
    static int p_sample_buffer[BUFFER_SIZE];
    
    const struct device *adc_dev;
    
    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
    };
    
    static const struct adc_channel_cfg m_2nd_channel_cfg = {
    	.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
    };
    
    static int adc_sample1(void)
    {
    	int ret;
    
    	const struct adc_sequence sequence = {
    		.channels = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer = p_sample_buffer,
    		.buffer_size = sizeof(p_sample_buffer),
    		.resolution = ADC_RESOLUTION,
    	};
    
    	if (!adc_dev) {
    		return -1;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	if (ret) {
    //        printk("adc_read() failed with code %d\n", ret);
    	}
    
    	for (int i = 0; i < BUFFER_SIZE; i++) {
    //                printk("ADC raw value: %d\n", p_sample_buffer[i]);                
            }
    	return ret;
    }
    
    static int adc_sample2(void)
    {
    	int ret;
    
    	const struct adc_sequence sequence = {
    		.channels = BIT(ADC_2ND_CHANNEL_ID),
    		.buffer = p_sample_buffer,
    		.buffer_size = sizeof(p_sample_buffer),
    		.resolution = ADC_RESOLUTION,
    	};
    
    	if (!adc_dev) {
    		return -1;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	if (ret) {
    //        printk("adc_read() failed with code %d\n", ret);
    	}
    
    	for (int i = 0; i < BUFFER_SIZE; i++) {
    //                printk("ADC raw value: %d\n", p_sample_buffer[i]);                
            }
    	return ret;
    }
    //****************
    
    void my_work_handler(struct k_work *work)
    {int err;unsigned int k;
        /* do the processing that needs to be done periodically */
    //********** AIN0 Sample part **************
           err = adc_sample1();
            if (err) {
    //            printk("Error in adc sampling: %d\n", err);
            }
            var1 = p_sample_buffer[0];
    
           err = adc_sample2();
            if (err) {
    //            printk("Error in adc sampling: %d\n", err);
            }
            var2 = p_sample_buffer[0];// should it be index 0 or 1 ?????
    }
    
    
    K_WORK_DEFINE(my_work, my_work_handler);
    
    void my_timer_handler(struct k_timer *dummy)
    {
        k_work_submit(&my_work);
    }
    
    K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);
    //********************************************************
    void main(){
    
              //ADC setup
              adc_dev = device_get_binding(ADC_DEVICE_NAME);
                  if (!adc_dev) {
                  printk("device_get_binding ADC (=%s) failed\n", ADC_DEVICE_NAME);
              } 
        
              err = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
              if (err) {
                      printk("Error in adc AIN0 setup: %d\n", err);
                  }
    
              err = adc_channel_setup(adc_dev, &m_2nd_channel_cfg);
              if (err) {
                      printk("Error in adc AIN1 setup: %d\n", err);
                  }
    
              #if defined (CONFIG_BOARD_BMS_NRF5340_CPUAPP)
              NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
              #else
              #error "Choose supported board or add new board for the application"
              #endif
    	k_timer_start(&my_timer, K_SECONDS(4), K_SECONDS(30));
    while(1)
    	{
    	// do something	
    	}
    }

  • I mean the project folder which contain build file, configure file, cmakelist text file and source file. like the following screenshot:

  • Hi, I just need answer of three queries as shown in attached image.

  • Hello,

    1. In the adc.h, if #define  BUFFER_SIZE 2  right or wrong to sample 2 analog channels ? If in future, 3 chhannels are required, may I set #define  BUFFER_SIZE 3.

    The buffer size should be set to N*number of enabled channels, as SCAN mode will sample each channel subsequently and put the result in the RAM buffer as described here: https://infocenter.nordicsemi.com/topic/ps_nrf5340/saadc.html?cp=3_0_0_6_28_4_3#saadc_operationmodes_scan. If you set a buffer size that does not match the number of enabled channels, you will miss samples, or samples will be stored in the buffer in non-deterministic order.

    2. In the main file, I adc instantiated by binding and then, set up channels using err = adc_channel_setup() .. function. Is it proper way ?

    yes it is.

    3. '' #if defined (CONFIG_BOARD_BMS_NRF5340_CPUAPP)
    NRF_SAADC->TASKS_CALIBRATEOFFSET = 1''

    this task will start offset auto-calibration in SAADC peripheral. 

    4. I wrote two sample functions, as in adc.c. Is this proper way to add to sequence ? If, wrong any where, may you make changes and attached corrected code file ?

    It is ok. I have added a sample code where 2 channels are used. you can look at this as reference. 

    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     * Copyright (c) 2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    
    #include <drivers/adc.h>
    #include <zephyr.h>
    #include <ztest.h>
    
    #if defined(CONFIG_SHIELD_MIKROE_ADC_CLICK)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, microchip_mcp3204))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_EXTERNAL0
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_NRF51DK_NRF51422)
    
    #include <hal/nrf_adc.h>
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nordic_nrf_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1_3
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_1ST_CHANNEL_INPUT	NRF_ADC_CONFIG_INPUT_2
    #define ADC_2ND_CHANNEL_ID	2
    #define ADC_2ND_CHANNEL_INPUT	NRF_ADC_CONFIG_INPUT_3
    
    #elif defined(CONFIG_BOARD_NRF21540DK_NRF52840) || \
    	defined(CONFIG_BOARD_NRF52DK_NRF52832) || \
    	defined(CONFIG_BOARD_NRF52840DK_NRF52840) || \
    	defined(CONFIG_BOARD_RAK4631_NRF52840) || \
    	defined(CONFIG_BOARD_RAK5010_NRF52840) || \
    	defined(CONFIG_BOARD_NRF52840DONGLE_NRF52840) || \
    	defined(CONFIG_BOARD_NRF52840_BLIP) || \
    	defined(CONFIG_BOARD_NRF52840_PAPYR) || \
    	defined(CONFIG_BOARD_NRF52833DK_NRF52833) || \
    	defined(CONFIG_BOARD_BL652_DVK) || \
    	defined(CONFIG_BOARD_BL653_DVK) || \
    	defined(CONFIG_BOARD_BL654_DVK) || \
    	defined(CONFIG_BOARD_BL654_SENSOR_BOARD) || \
    	defined(CONFIG_BOARD_DEGU_EVK) || \
    	defined(CONFIG_BOARD_ADAFRUIT_FEATHER_NRF52840)	|| \
    	defined(CONFIG_BOARD_RUUVI_RUUVITAG) || \
    	defined(CONFIG_BOARD_BT510) || \
    	defined(CONFIG_BOARD_PINNACLE_100_DVK) || \
    	defined(CONFIG_BOARD_ARDUINO_NANO_33_BLE) || \
    	defined(CONFIG_BOARD_UBX_BMD300EVAL_NRF52832) || \
    	defined(CONFIG_BOARD_UBX_BMD330EVAL_NRF52810) || \
    	defined(CONFIG_BOARD_UBX_BMD340EVAL_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_BMD345EVAL_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_BMD360EVAL_NRF52811) || \
    	defined(CONFIG_BOARD_UBX_BMD380EVAL_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_EVKANNAB1_NRF52832) || \
    	defined(CONFIG_BOARD_UBX_EVKNINAB1_NRF52832) || \
    	defined(CONFIG_BOARD_UBX_EVKNINAB3_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_EVKNINAB4_NRF52833) || \
    	defined(CONFIG_BOARD_BT610)
    
    #include <hal/nrf_saadc.h>
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nordic_nrf_saadc))
    #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_AIN1
    #define ADC_2ND_CHANNEL_ID	2
    #define ADC_2ND_CHANNEL_INPUT	NRF_SAADC_INPUT_AIN2
    
    #elif defined(CONFIG_BOARD_FRDM_K22F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	14
    #define ADC_1ST_CHANNEL_INPUT	0
    
    #elif defined(CONFIG_BOARD_FRDM_K64F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	14
    
    #elif defined(CONFIG_BOARD_FRDM_K82F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	15
    
    #elif defined(CONFIG_BOARD_FRDM_KL25Z)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	12
    
    #elif defined(CONFIG_BOARD_FRDM_KW41Z)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	3
    
    #elif defined(CONFIG_BOARD_HEXIWEAR_K64)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	16
    
    #elif defined(CONFIG_BOARD_FRDM_K82F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	26
    
    #elif defined(CONFIG_BOARD_HEXIWEAR_KW40Z)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_SAM_E70_XPLAINED) || \
    	defined(CONFIG_BOARD_SAM_V71_XULT)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, atmel_sam_afec))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_EXTERNAL0
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    
    #elif defined(CONFIG_SOC_FAMILY_SAM0)
    #include <soc.h>
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, atmel_sam0_adc))
    #define ADC_RESOLUTION          12
    #define ADC_GAIN                ADC_GAIN_1
    #define ADC_REFERENCE           ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME    ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID      0
    #define ADC_1ST_CHANNEL_INPUT   ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC_Val
    
    #elif defined(CONFIG_BOARD_NUCLEO_F091RC) || \
    	defined(CONFIG_BOARD_NUCLEO_F103RB) || \
    	defined(CONFIG_BOARD_NUCLEO_F207ZG) || \
    	defined(CONFIG_BOARD_STM32F3_DISCO) || \
    	defined(CONFIG_BOARD_STM32L562E_DK) || \
    	defined(CONFIG_BOARD_NUCLEO_L552ZE_Q) || \
    	defined(CONFIG_BOARD_NUCLEO_F401RE) || \
    	defined(CONFIG_BOARD_NUCLEO_F429ZI) || \
    	defined(CONFIG_BOARD_NUCLEO_F746ZG) || \
    	defined(CONFIG_BOARD_NUCLEO_G071RB) || \
    	defined(CONFIG_BOARD_NUCLEO_L073RZ) || \
    	defined(CONFIG_BOARD_NUCLEO_WB55RG) || \
    	defined(CONFIG_BOARD_NUCLEO_L152RE) || \
    	defined(CONFIG_BOARD_OLIMEX_STM32_H103) || \
    	defined(CONFIG_BOARD_96B_AEROCORE2) || \
    	defined(CONFIG_BOARD_STM32F103_MINI) || \
    	defined(CONFIG_BOARD_STM32_MIN_DEV_BLUE) || \
    	defined(CONFIG_BOARD_STM32_MIN_DEV_BLACK) || \
    	defined(CONFIG_BOARD_WAVESHARE_OPEN103Z) || \
    	defined(CONFIG_BOARD_RONOTH_LODEV) || \
    	defined(CONFIG_BOARD_STM32L496G_DISCO)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    
    #elif defined(CONFIG_BOARD_NUCLEO_F302R8) || \
    	defined(CONFIG_BOARD_NUCLEO_G474RE) || \
    	defined(CONFIG_BOARD_NUCLEO_L412RB_P)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    /* Some F3 series SOCs do not have channel 0 connected to an external GPIO. */
    #define ADC_1ST_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_NUCLEO_L476RG) || \
    	defined(CONFIG_BOARD_BLACKPILL_F411CE) || \
    	defined(CONFIG_BOARD_BLACKPILL_F401CE) || \
    	defined(CONFIG_BOARD_NUCLEO_L4R5ZI) || \
    	defined(CONFIG_BOARD_MIKROE_CLICKER_2)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_DISCO_L475_IOT1)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	5
    
    #elif defined(CONFIG_BOARD_B_U585I_IOT02A)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	15
    
    #elif defined(CONFIG_BOARD_NUCLEO_H743ZI) || \
    	defined(CONFIG_BOARD_NUCLEO_H753ZI)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		16
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	15
    
    #elif defined(CONFIG_BOARD_TWR_KE18F)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc12))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_MEC15XXEVB_ASSY6853) || \
    	defined(CONFIG_BOARD_MEC1501MODULAR_ASSY6885)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, microchip_xec_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	4
    #define ADC_2ND_CHANNEL_ID	5
    
    #elif defined(CONFIG_BOARD_LPCXPRESSO55S69_CPU0) || \
    	defined(CONFIG_BOARD_LPCXPRESSO55S28) || \
    	defined(CONFIG_BOARD_MIMXRT1170_EVK_CM7) || \
    	defined(CONFIG_BOARD_MIMXRT685_EVK)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_lpc_lpadc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_EXTERNAL0
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_NPCX7M6FB_EVB) || \
    	defined(CONFIG_BOARD_NPCX9M6F_EVB)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nuvoton_npcx_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	2
    
    #elif defined(CONFIG_BOARD_CC3220SF_LAUNCHXL) || \
    	defined(CONFIG_BOARD_CC3235SF_LAUNCHXL)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, ti_cc32xx_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID      1
    
    #elif defined(CONFIG_BOARD_IT8XXX2_EVB)
    #define ADC_DEVICE_NAME	DT_LABEL(DT_INST(0, ite_it8xxx2_adc))
    #define ADC_RESOLUTION	3
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_MIMXRT1050_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1050_EVK_QSPI) || \
    	defined(CONFIG_BOARD_MIMXRT1064_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1060_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1024_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1010_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1015_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1020_EVK)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_mcux_12b1msps_sar))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID  1
    
    #elif defined(CONFIG_BOARD_NATIVE_POSIX)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, zephyr_adc_emul))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #else
    #error "Unsupported board."
    #endif
    
    /* Invalid value that is not supposed to be written by the driver. It is used
     * to mark the sample buffer entries as empty. If needed, it can be overriden
     * for a particular board by providing a specific definition above.
     */
    #if !defined(INVALID_ADC_VALUE)
    #define INVALID_ADC_VALUE SHRT_MIN
    #endif
    
    #define BUFFER_SIZE  6
    static ZTEST_BMEM int16_t m_sample_buffer[BUFFER_SIZE];
    
    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
    };
    #if defined(ADC_2ND_CHANNEL_ID)
    static const struct adc_channel_cfg m_2nd_channel_cfg = {
    	.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 /* defined(ADC_2ND_CHANNEL_ID) */
    
    const struct device *get_adc_device(void)
    {
    	return device_get_binding(ADC_DEVICE_NAME);
    }
    
    static const struct device *init_adc(void)
    {
    	int i, ret;
    	const struct device *adc_dev = device_get_binding(ADC_DEVICE_NAME);
    
    	zassert_not_null(adc_dev, "Cannot get ADC device");
    
    	ret = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
    	zassert_equal(ret, 0,
    		"Setting up of the first channel failed with code %d", ret);
    
    #if defined(ADC_2ND_CHANNEL_ID)
    	ret = adc_channel_setup(adc_dev, &m_2nd_channel_cfg);
    	zassert_equal(ret, 0,
    		"Setting up of the second channel failed with code %d", ret);
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    	for (i = 0; i < BUFFER_SIZE; ++i) {
    		m_sample_buffer[i] = INVALID_ADC_VALUE;
    	}
    
    	return adc_dev;
    }
    
    static void check_samples(int expected_count)
    {
    	int i;
    
    	TC_PRINT("Samples read: ");
    	for (i = 0; i < BUFFER_SIZE; i++) {
    		int16_t sample_value = m_sample_buffer[i];
    
    		TC_PRINT("0x%04x ", sample_value);
    		if (i < expected_count) {
    			zassert_not_equal(INVALID_ADC_VALUE, sample_value,
    				"[%u] should be filled", i);
    		} else {
    			zassert_equal(INVALID_ADC_VALUE, sample_value,
    				"[%u] should be empty", i);
    		}
    	}
    	TC_PRINT("\n");
    }
    
    /*
     * test_adc_sample_one_channel
     */
    static int test_task_one_channel(void)
    {
    	int ret;
    	const struct adc_sequence sequence = {
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	check_samples(1);
    
    	return TC_PASS;
    }
    
    void test_adc_sample_one_channel(void)
    {
    	zassert_true(test_task_one_channel() == TC_PASS, NULL);
    }
    
    /*
     * test_adc_sample_two_channels
     */
    #if defined(ADC_2ND_CHANNEL_ID)
    static int test_task_two_channels(void)
    {
    	int ret;
    	const struct adc_sequence sequence = {
    		.channels    = BIT(ADC_1ST_CHANNEL_ID) |
    			       BIT(ADC_2ND_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	check_samples(2);
    
    	return TC_PASS;
    }
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    void test_adc_sample_two_channels(void)
    {
    #if defined(ADC_2ND_CHANNEL_ID)
    	zassert_true(test_task_two_channels() == TC_PASS, NULL);
    #else
    	ztest_test_skip();
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    }
    
    /*
     * test_adc_asynchronous_call
     */
    #if defined(CONFIG_ADC_ASYNC)
    struct k_poll_signal async_sig;
    
    static int test_task_asynchronous_call(void)
    {
    	int ret;
    	const struct adc_sequence_options options = {
    		.extra_samplings = 4,
    		/* Start consecutive samplings as fast as possible. */
    		.interval_us     = 0,
    	};
    	const struct adc_sequence sequence = {
    		.options     = &options,
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    	struct k_poll_event  async_evt =
    		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
    					 K_POLL_MODE_NOTIFY_ONLY,
    					 &async_sig);
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read_async(adc_dev, &sequence, &async_sig);
    	zassert_equal(ret, 0, "adc_read_async() failed with code %d", ret);
    
    	ret = k_poll(&async_evt, 1, K_MSEC(1000));
    	zassert_equal(ret, 0, "k_poll failed with error %d", ret);
    
    	check_samples(1 + options.extra_samplings);
    
    	return TC_PASS;
    }
    #endif /* defined(CONFIG_ADC_ASYNC) */
    
    void test_adc_asynchronous_call(void)
    {
    #if defined(CONFIG_ADC_ASYNC)
    	zassert_true(test_task_asynchronous_call() == TC_PASS, NULL);
    #else
    	ztest_test_skip();
    #endif /* defined(CONFIG_ADC_ASYNC) */
    }
    
    /*
     * test_adc_sample_with_interval
     */
    static uint32_t my_sequence_identifier = 0x12345678;
    static void *user_data = &my_sequence_identifier;
    
    static enum adc_action sample_with_interval_callback(const struct device *dev,
    						     const struct adc_sequence *sequence,
    						     uint16_t sampling_index)
    {
    	if (sequence->options->user_data != &my_sequence_identifier) {
    		user_data = sequence->options->user_data;
    		return ADC_ACTION_FINISH;
    	}
    
    	TC_PRINT("%s: sampling %d\n", __func__, sampling_index);
    	return ADC_ACTION_CONTINUE;
    }
    
    static int test_task_with_interval(void)
    {
    	int ret;
    	const struct adc_sequence_options options = {
    		.interval_us     = 100 * 1000UL,
    		.callback        = sample_with_interval_callback,
    		.user_data       = user_data,
    		.extra_samplings = 4,
    	};
    	const struct adc_sequence sequence = {
    		.options     = &options,
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	zassert_equal(user_data, sequence.options->user_data,
    		"Invalid user data: %p, expected: %p",
    		user_data, sequence.options->user_data);
    
    	check_samples(1 + options.extra_samplings);
    
    	return TC_PASS;
    }
    
    void test_adc_sample_with_interval(void)
    {
    	zassert_true(test_task_with_interval() == TC_PASS, NULL);
    }
    
    /*
     * test_adc_repeated_samplings
     */
    static uint8_t m_samplings_done;
    static enum adc_action repeated_samplings_callback(const struct device *dev,
    						   const struct adc_sequence *sequence,
    						   uint16_t sampling_index)
    {
    	++m_samplings_done;
    	TC_PRINT("%s: done %d\n", __func__, m_samplings_done);
    	if (m_samplings_done == 1U) {
    		#if defined(ADC_2ND_CHANNEL_ID)
    			check_samples(2);
    		#else
    			check_samples(1);
    		#endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    		/* After first sampling continue normally. */
    		return ADC_ACTION_CONTINUE;
    	} else {
    		#if defined(ADC_2ND_CHANNEL_ID)
    			check_samples(4);
    		#else
    			check_samples(2);
    		#endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    		/*
    		 * The second sampling is repeated 9 times (the samples are
    		 * written in the same place), then the sequence is finished
    		 * prematurely.
    		 */
    		if (m_samplings_done < 10) {
    			return ADC_ACTION_REPEAT;
    		} else {
    			return ADC_ACTION_FINISH;
    		}
    	}
    }
    
    static int test_task_repeated_samplings(void)
    {
    	int ret;
    	const struct adc_sequence_options options = {
    		.callback        = repeated_samplings_callback,
    		/*
    		 * This specifies that 3 samplings are planned. However,
    		 * the callback function above is constructed in such way
    		 * that the first sampling is done normally, the second one
    		 * is repeated 9 times, and then the sequence is finished.
    		 * Hence, the third sampling will not take place.
    		 */
    		.extra_samplings = 2,
    		/* Start consecutive samplings as fast as possible. */
    		.interval_us     = 0,
    	};
    	const struct adc_sequence sequence = {
    		.options     = &options,
    #if defined(ADC_2ND_CHANNEL_ID)
    		.channels    = BIT(ADC_1ST_CHANNEL_ID) |
    			       BIT(ADC_2ND_CHANNEL_ID),
    #else
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	return TC_PASS;
    }
    
    void test_adc_repeated_samplings(void)
    {
    	zassert_true(test_task_repeated_samplings() == TC_PASS, NULL);
    }
    
    /*
     * test_adc_invalid_request
     */
    static int test_task_invalid_request(void)
    {
    	int ret;
    	struct adc_sequence sequence = {
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = 0, /* intentionally invalid value */
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_not_equal(ret, 0, "adc_read() unexpectedly succeeded");
    
    #if defined(CONFIG_ADC_ASYNC)
    	ret = adc_read_async(adc_dev, &sequence, &async_sig);
    	zassert_not_equal(ret, 0, "adc_read_async() unexpectedly succeeded");
    #endif
    
    	/*
    	 * Make the sequence parameters valid, now the request should succeed.
    	 */
    	sequence.resolution = ADC_RESOLUTION;
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	check_samples(1);
    
    	return TC_PASS;
    }
    
    void test_adc_invalid_request(void)
    {
    	zassert_true(test_task_invalid_request() == TC_PASS, NULL);
    }
    

    5. I called adc sampling functions in repeatitive timer. Is the result of adc from AIN0 and AIN1 be avaialble at same index or at different indices in p_sample_buffer[]

    Indexes will be different if both channels are enabled at once and scan mode are used. p_sample_buffer[] will have different values.  

    Regards,

    Kazi Afroza Sultana

Reply
  • Hello,

    1. In the adc.h, if #define  BUFFER_SIZE 2  right or wrong to sample 2 analog channels ? If in future, 3 chhannels are required, may I set #define  BUFFER_SIZE 3.

    The buffer size should be set to N*number of enabled channels, as SCAN mode will sample each channel subsequently and put the result in the RAM buffer as described here: https://infocenter.nordicsemi.com/topic/ps_nrf5340/saadc.html?cp=3_0_0_6_28_4_3#saadc_operationmodes_scan. If you set a buffer size that does not match the number of enabled channels, you will miss samples, or samples will be stored in the buffer in non-deterministic order.

    2. In the main file, I adc instantiated by binding and then, set up channels using err = adc_channel_setup() .. function. Is it proper way ?

    yes it is.

    3. '' #if defined (CONFIG_BOARD_BMS_NRF5340_CPUAPP)
    NRF_SAADC->TASKS_CALIBRATEOFFSET = 1''

    this task will start offset auto-calibration in SAADC peripheral. 

    4. I wrote two sample functions, as in adc.c. Is this proper way to add to sequence ? If, wrong any where, may you make changes and attached corrected code file ?

    It is ok. I have added a sample code where 2 channels are used. you can look at this as reference. 

    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     * Copyright (c) 2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    
    #include <drivers/adc.h>
    #include <zephyr.h>
    #include <ztest.h>
    
    #if defined(CONFIG_SHIELD_MIKROE_ADC_CLICK)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, microchip_mcp3204))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_EXTERNAL0
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_NRF51DK_NRF51422)
    
    #include <hal/nrf_adc.h>
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nordic_nrf_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1_3
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_1ST_CHANNEL_INPUT	NRF_ADC_CONFIG_INPUT_2
    #define ADC_2ND_CHANNEL_ID	2
    #define ADC_2ND_CHANNEL_INPUT	NRF_ADC_CONFIG_INPUT_3
    
    #elif defined(CONFIG_BOARD_NRF21540DK_NRF52840) || \
    	defined(CONFIG_BOARD_NRF52DK_NRF52832) || \
    	defined(CONFIG_BOARD_NRF52840DK_NRF52840) || \
    	defined(CONFIG_BOARD_RAK4631_NRF52840) || \
    	defined(CONFIG_BOARD_RAK5010_NRF52840) || \
    	defined(CONFIG_BOARD_NRF52840DONGLE_NRF52840) || \
    	defined(CONFIG_BOARD_NRF52840_BLIP) || \
    	defined(CONFIG_BOARD_NRF52840_PAPYR) || \
    	defined(CONFIG_BOARD_NRF52833DK_NRF52833) || \
    	defined(CONFIG_BOARD_BL652_DVK) || \
    	defined(CONFIG_BOARD_BL653_DVK) || \
    	defined(CONFIG_BOARD_BL654_DVK) || \
    	defined(CONFIG_BOARD_BL654_SENSOR_BOARD) || \
    	defined(CONFIG_BOARD_DEGU_EVK) || \
    	defined(CONFIG_BOARD_ADAFRUIT_FEATHER_NRF52840)	|| \
    	defined(CONFIG_BOARD_RUUVI_RUUVITAG) || \
    	defined(CONFIG_BOARD_BT510) || \
    	defined(CONFIG_BOARD_PINNACLE_100_DVK) || \
    	defined(CONFIG_BOARD_ARDUINO_NANO_33_BLE) || \
    	defined(CONFIG_BOARD_UBX_BMD300EVAL_NRF52832) || \
    	defined(CONFIG_BOARD_UBX_BMD330EVAL_NRF52810) || \
    	defined(CONFIG_BOARD_UBX_BMD340EVAL_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_BMD345EVAL_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_BMD360EVAL_NRF52811) || \
    	defined(CONFIG_BOARD_UBX_BMD380EVAL_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_EVKANNAB1_NRF52832) || \
    	defined(CONFIG_BOARD_UBX_EVKNINAB1_NRF52832) || \
    	defined(CONFIG_BOARD_UBX_EVKNINAB3_NRF52840) || \
    	defined(CONFIG_BOARD_UBX_EVKNINAB4_NRF52833) || \
    	defined(CONFIG_BOARD_BT610)
    
    #include <hal/nrf_saadc.h>
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nordic_nrf_saadc))
    #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_AIN1
    #define ADC_2ND_CHANNEL_ID	2
    #define ADC_2ND_CHANNEL_INPUT	NRF_SAADC_INPUT_AIN2
    
    #elif defined(CONFIG_BOARD_FRDM_K22F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	14
    #define ADC_1ST_CHANNEL_INPUT	0
    
    #elif defined(CONFIG_BOARD_FRDM_K64F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	14
    
    #elif defined(CONFIG_BOARD_FRDM_K82F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	15
    
    #elif defined(CONFIG_BOARD_FRDM_KL25Z)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	12
    
    #elif defined(CONFIG_BOARD_FRDM_KW41Z)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	3
    
    #elif defined(CONFIG_BOARD_HEXIWEAR_K64)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	16
    
    #elif defined(CONFIG_BOARD_FRDM_K82F)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	26
    
    #elif defined(CONFIG_BOARD_HEXIWEAR_KW40Z)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc16))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_SAM_E70_XPLAINED) || \
    	defined(CONFIG_BOARD_SAM_V71_XULT)
    
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, atmel_sam_afec))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_EXTERNAL0
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    
    #elif defined(CONFIG_SOC_FAMILY_SAM0)
    #include <soc.h>
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, atmel_sam0_adc))
    #define ADC_RESOLUTION          12
    #define ADC_GAIN                ADC_GAIN_1
    #define ADC_REFERENCE           ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME    ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID      0
    #define ADC_1ST_CHANNEL_INPUT   ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC_Val
    
    #elif defined(CONFIG_BOARD_NUCLEO_F091RC) || \
    	defined(CONFIG_BOARD_NUCLEO_F103RB) || \
    	defined(CONFIG_BOARD_NUCLEO_F207ZG) || \
    	defined(CONFIG_BOARD_STM32F3_DISCO) || \
    	defined(CONFIG_BOARD_STM32L562E_DK) || \
    	defined(CONFIG_BOARD_NUCLEO_L552ZE_Q) || \
    	defined(CONFIG_BOARD_NUCLEO_F401RE) || \
    	defined(CONFIG_BOARD_NUCLEO_F429ZI) || \
    	defined(CONFIG_BOARD_NUCLEO_F746ZG) || \
    	defined(CONFIG_BOARD_NUCLEO_G071RB) || \
    	defined(CONFIG_BOARD_NUCLEO_L073RZ) || \
    	defined(CONFIG_BOARD_NUCLEO_WB55RG) || \
    	defined(CONFIG_BOARD_NUCLEO_L152RE) || \
    	defined(CONFIG_BOARD_OLIMEX_STM32_H103) || \
    	defined(CONFIG_BOARD_96B_AEROCORE2) || \
    	defined(CONFIG_BOARD_STM32F103_MINI) || \
    	defined(CONFIG_BOARD_STM32_MIN_DEV_BLUE) || \
    	defined(CONFIG_BOARD_STM32_MIN_DEV_BLACK) || \
    	defined(CONFIG_BOARD_WAVESHARE_OPEN103Z) || \
    	defined(CONFIG_BOARD_RONOTH_LODEV) || \
    	defined(CONFIG_BOARD_STM32L496G_DISCO)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    
    #elif defined(CONFIG_BOARD_NUCLEO_F302R8) || \
    	defined(CONFIG_BOARD_NUCLEO_G474RE) || \
    	defined(CONFIG_BOARD_NUCLEO_L412RB_P)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    /* Some F3 series SOCs do not have channel 0 connected to an external GPIO. */
    #define ADC_1ST_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_NUCLEO_L476RG) || \
    	defined(CONFIG_BOARD_BLACKPILL_F411CE) || \
    	defined(CONFIG_BOARD_BLACKPILL_F401CE) || \
    	defined(CONFIG_BOARD_NUCLEO_L4R5ZI) || \
    	defined(CONFIG_BOARD_MIKROE_CLICKER_2)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_DISCO_L475_IOT1)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	5
    
    #elif defined(CONFIG_BOARD_B_U585I_IOT02A)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	15
    
    #elif defined(CONFIG_BOARD_NUCLEO_H743ZI) || \
    	defined(CONFIG_BOARD_NUCLEO_H753ZI)
    #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
    #define ADC_RESOLUTION		16
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	15
    
    #elif defined(CONFIG_BOARD_TWR_KE18F)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_kinetis_adc12))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_MEC15XXEVB_ASSY6853) || \
    	defined(CONFIG_BOARD_MEC1501MODULAR_ASSY6885)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, microchip_xec_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	4
    #define ADC_2ND_CHANNEL_ID	5
    
    #elif defined(CONFIG_BOARD_LPCXPRESSO55S69_CPU0) || \
    	defined(CONFIG_BOARD_LPCXPRESSO55S28) || \
    	defined(CONFIG_BOARD_MIMXRT1170_EVK_CM7) || \
    	defined(CONFIG_BOARD_MIMXRT685_EVK)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_lpc_lpadc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_EXTERNAL0
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_NPCX7M6FB_EVB) || \
    	defined(CONFIG_BOARD_NPCX9M6F_EVB)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nuvoton_npcx_adc))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	2
    
    #elif defined(CONFIG_BOARD_CC3220SF_LAUNCHXL) || \
    	defined(CONFIG_BOARD_CC3235SF_LAUNCHXL)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, ti_cc32xx_adc))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID      1
    
    #elif defined(CONFIG_BOARD_IT8XXX2_EVB)
    #define ADC_DEVICE_NAME	DT_LABEL(DT_INST(0, ite_it8xxx2_adc))
    #define ADC_RESOLUTION	3
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #elif defined(CONFIG_BOARD_MIMXRT1050_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1050_EVK_QSPI) || \
    	defined(CONFIG_BOARD_MIMXRT1064_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1060_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1024_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1010_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1015_EVK) || \
    	defined(CONFIG_BOARD_MIMXRT1020_EVK)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nxp_mcux_12b1msps_sar))
    #define ADC_RESOLUTION		12
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID  1
    
    #elif defined(CONFIG_BOARD_NATIVE_POSIX)
    #define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, zephyr_adc_emul))
    #define ADC_RESOLUTION		10
    #define ADC_GAIN		ADC_GAIN_1
    #define ADC_REFERENCE		ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
    #define ADC_1ST_CHANNEL_ID	0
    #define ADC_2ND_CHANNEL_ID	1
    
    #else
    #error "Unsupported board."
    #endif
    
    /* Invalid value that is not supposed to be written by the driver. It is used
     * to mark the sample buffer entries as empty. If needed, it can be overriden
     * for a particular board by providing a specific definition above.
     */
    #if !defined(INVALID_ADC_VALUE)
    #define INVALID_ADC_VALUE SHRT_MIN
    #endif
    
    #define BUFFER_SIZE  6
    static ZTEST_BMEM int16_t m_sample_buffer[BUFFER_SIZE];
    
    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
    };
    #if defined(ADC_2ND_CHANNEL_ID)
    static const struct adc_channel_cfg m_2nd_channel_cfg = {
    	.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 /* defined(ADC_2ND_CHANNEL_ID) */
    
    const struct device *get_adc_device(void)
    {
    	return device_get_binding(ADC_DEVICE_NAME);
    }
    
    static const struct device *init_adc(void)
    {
    	int i, ret;
    	const struct device *adc_dev = device_get_binding(ADC_DEVICE_NAME);
    
    	zassert_not_null(adc_dev, "Cannot get ADC device");
    
    	ret = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
    	zassert_equal(ret, 0,
    		"Setting up of the first channel failed with code %d", ret);
    
    #if defined(ADC_2ND_CHANNEL_ID)
    	ret = adc_channel_setup(adc_dev, &m_2nd_channel_cfg);
    	zassert_equal(ret, 0,
    		"Setting up of the second channel failed with code %d", ret);
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    	for (i = 0; i < BUFFER_SIZE; ++i) {
    		m_sample_buffer[i] = INVALID_ADC_VALUE;
    	}
    
    	return adc_dev;
    }
    
    static void check_samples(int expected_count)
    {
    	int i;
    
    	TC_PRINT("Samples read: ");
    	for (i = 0; i < BUFFER_SIZE; i++) {
    		int16_t sample_value = m_sample_buffer[i];
    
    		TC_PRINT("0x%04x ", sample_value);
    		if (i < expected_count) {
    			zassert_not_equal(INVALID_ADC_VALUE, sample_value,
    				"[%u] should be filled", i);
    		} else {
    			zassert_equal(INVALID_ADC_VALUE, sample_value,
    				"[%u] should be empty", i);
    		}
    	}
    	TC_PRINT("\n");
    }
    
    /*
     * test_adc_sample_one_channel
     */
    static int test_task_one_channel(void)
    {
    	int ret;
    	const struct adc_sequence sequence = {
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	check_samples(1);
    
    	return TC_PASS;
    }
    
    void test_adc_sample_one_channel(void)
    {
    	zassert_true(test_task_one_channel() == TC_PASS, NULL);
    }
    
    /*
     * test_adc_sample_two_channels
     */
    #if defined(ADC_2ND_CHANNEL_ID)
    static int test_task_two_channels(void)
    {
    	int ret;
    	const struct adc_sequence sequence = {
    		.channels    = BIT(ADC_1ST_CHANNEL_ID) |
    			       BIT(ADC_2ND_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	check_samples(2);
    
    	return TC_PASS;
    }
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    void test_adc_sample_two_channels(void)
    {
    #if defined(ADC_2ND_CHANNEL_ID)
    	zassert_true(test_task_two_channels() == TC_PASS, NULL);
    #else
    	ztest_test_skip();
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    }
    
    /*
     * test_adc_asynchronous_call
     */
    #if defined(CONFIG_ADC_ASYNC)
    struct k_poll_signal async_sig;
    
    static int test_task_asynchronous_call(void)
    {
    	int ret;
    	const struct adc_sequence_options options = {
    		.extra_samplings = 4,
    		/* Start consecutive samplings as fast as possible. */
    		.interval_us     = 0,
    	};
    	const struct adc_sequence sequence = {
    		.options     = &options,
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    	struct k_poll_event  async_evt =
    		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
    					 K_POLL_MODE_NOTIFY_ONLY,
    					 &async_sig);
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read_async(adc_dev, &sequence, &async_sig);
    	zassert_equal(ret, 0, "adc_read_async() failed with code %d", ret);
    
    	ret = k_poll(&async_evt, 1, K_MSEC(1000));
    	zassert_equal(ret, 0, "k_poll failed with error %d", ret);
    
    	check_samples(1 + options.extra_samplings);
    
    	return TC_PASS;
    }
    #endif /* defined(CONFIG_ADC_ASYNC) */
    
    void test_adc_asynchronous_call(void)
    {
    #if defined(CONFIG_ADC_ASYNC)
    	zassert_true(test_task_asynchronous_call() == TC_PASS, NULL);
    #else
    	ztest_test_skip();
    #endif /* defined(CONFIG_ADC_ASYNC) */
    }
    
    /*
     * test_adc_sample_with_interval
     */
    static uint32_t my_sequence_identifier = 0x12345678;
    static void *user_data = &my_sequence_identifier;
    
    static enum adc_action sample_with_interval_callback(const struct device *dev,
    						     const struct adc_sequence *sequence,
    						     uint16_t sampling_index)
    {
    	if (sequence->options->user_data != &my_sequence_identifier) {
    		user_data = sequence->options->user_data;
    		return ADC_ACTION_FINISH;
    	}
    
    	TC_PRINT("%s: sampling %d\n", __func__, sampling_index);
    	return ADC_ACTION_CONTINUE;
    }
    
    static int test_task_with_interval(void)
    {
    	int ret;
    	const struct adc_sequence_options options = {
    		.interval_us     = 100 * 1000UL,
    		.callback        = sample_with_interval_callback,
    		.user_data       = user_data,
    		.extra_samplings = 4,
    	};
    	const struct adc_sequence sequence = {
    		.options     = &options,
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	zassert_equal(user_data, sequence.options->user_data,
    		"Invalid user data: %p, expected: %p",
    		user_data, sequence.options->user_data);
    
    	check_samples(1 + options.extra_samplings);
    
    	return TC_PASS;
    }
    
    void test_adc_sample_with_interval(void)
    {
    	zassert_true(test_task_with_interval() == TC_PASS, NULL);
    }
    
    /*
     * test_adc_repeated_samplings
     */
    static uint8_t m_samplings_done;
    static enum adc_action repeated_samplings_callback(const struct device *dev,
    						   const struct adc_sequence *sequence,
    						   uint16_t sampling_index)
    {
    	++m_samplings_done;
    	TC_PRINT("%s: done %d\n", __func__, m_samplings_done);
    	if (m_samplings_done == 1U) {
    		#if defined(ADC_2ND_CHANNEL_ID)
    			check_samples(2);
    		#else
    			check_samples(1);
    		#endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    		/* After first sampling continue normally. */
    		return ADC_ACTION_CONTINUE;
    	} else {
    		#if defined(ADC_2ND_CHANNEL_ID)
    			check_samples(4);
    		#else
    			check_samples(2);
    		#endif /* defined(ADC_2ND_CHANNEL_ID) */
    
    		/*
    		 * The second sampling is repeated 9 times (the samples are
    		 * written in the same place), then the sequence is finished
    		 * prematurely.
    		 */
    		if (m_samplings_done < 10) {
    			return ADC_ACTION_REPEAT;
    		} else {
    			return ADC_ACTION_FINISH;
    		}
    	}
    }
    
    static int test_task_repeated_samplings(void)
    {
    	int ret;
    	const struct adc_sequence_options options = {
    		.callback        = repeated_samplings_callback,
    		/*
    		 * This specifies that 3 samplings are planned. However,
    		 * the callback function above is constructed in such way
    		 * that the first sampling is done normally, the second one
    		 * is repeated 9 times, and then the sequence is finished.
    		 * Hence, the third sampling will not take place.
    		 */
    		.extra_samplings = 2,
    		/* Start consecutive samplings as fast as possible. */
    		.interval_us     = 0,
    	};
    	const struct adc_sequence sequence = {
    		.options     = &options,
    #if defined(ADC_2ND_CHANNEL_ID)
    		.channels    = BIT(ADC_1ST_CHANNEL_ID) |
    			       BIT(ADC_2ND_CHANNEL_ID),
    #else
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    #endif /* defined(ADC_2ND_CHANNEL_ID) */
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = ADC_RESOLUTION,
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	return TC_PASS;
    }
    
    void test_adc_repeated_samplings(void)
    {
    	zassert_true(test_task_repeated_samplings() == TC_PASS, NULL);
    }
    
    /*
     * test_adc_invalid_request
     */
    static int test_task_invalid_request(void)
    {
    	int ret;
    	struct adc_sequence sequence = {
    		.channels    = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer      = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution  = 0, /* intentionally invalid value */
    	};
    
    	const struct device *adc_dev = init_adc();
    
    	if (!adc_dev) {
    		return TC_FAIL;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_not_equal(ret, 0, "adc_read() unexpectedly succeeded");
    
    #if defined(CONFIG_ADC_ASYNC)
    	ret = adc_read_async(adc_dev, &sequence, &async_sig);
    	zassert_not_equal(ret, 0, "adc_read_async() unexpectedly succeeded");
    #endif
    
    	/*
    	 * Make the sequence parameters valid, now the request should succeed.
    	 */
    	sequence.resolution = ADC_RESOLUTION;
    
    	ret = adc_read(adc_dev, &sequence);
    	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
    
    	check_samples(1);
    
    	return TC_PASS;
    }
    
    void test_adc_invalid_request(void)
    {
    	zassert_true(test_task_invalid_request() == TC_PASS, NULL);
    }
    

    5. I called adc sampling functions in repeatitive timer. Is the result of adc from AIN0 and AIN1 be avaialble at same index or at different indices in p_sample_buffer[]

    Indexes will be different if both channels are enabled at once and scan mode are used. p_sample_buffer[] will have different values.  

    Regards,

    Kazi Afroza Sultana

Children
No Data
Related