Hi,
I am working on setting up multiple ADC channels in the device tree. My starting point is here, which seemed to be an unofficial ADC example that many ADC-related posts referred to.
I can make it work for a single-ended mode as well as a differential mode involving two channels in the source code, but it is difficult to find a suitable guide for setting up the ADC channels in the device tree. After reading off many posts, I came up with the following lines of code in the overlay file:
&adc { // compatible = "nordic_nrf_saadc"; status = "okay"; io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>; io-channel-names = "VCM2", "READ2_MCU", "READ3_MCU", "VCM3", "VCM1", "READ1_MCU", "VCM4", "READ4_MCU"; };
#define ADC_DEVICE_NAME "ADC_0" #define ADC_RESOLUTION 10 #define ADC_GAIN ADC_GAIN_1_4 #define ADC_REFERENCE ADC_REF_VDD_1_4 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10) #define AIN0_VCM_CHANNEL_ID 0 #define AIN0_VCM_CHANNEL_INPUT NRF_SAADC_INPUT_AIN0 #define AIN1_READ2_MCU_CHANNEL_ID 1 #define AIN1_READ2_MCU_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1 static const struct adc_channel_cfg m_read2_channel_cfg = { .gain = ADC_GAIN, .reference = ADC_REFERENCE, .acquisition_time = ADC_ACQUISITION_TIME, .channel_id = AIN1_READ2_MCU_CHANNEL_ID, .differential = 1, #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS) .input_positive = AIN1_READ2_MCU_CHANNEL_INPUT, .input_negative = AIN0_VCM_CHANNEL_INPUT, #endif }; #define BUFFER_SIZE 8 static int16_t m_sample_buffer[BUFFER_SIZE]; const struct adc_sequence_options sequence_opts = { .interval_us = 0, .callback = NULL, .user_data = NULL, .extra_samplings = 7, }; static int adc_sample(void) { int ret; const struct adc_sequence sequence = { .options = &sequence_opts, .channels = BIT(AIN1_READ2_MCU_CHANNEL_ID), .buffer = m_sample_buffer, .buffer_size = sizeof(m_sample_buffer), .resolution = ADC_RESOLUTION, }; if (!adc_dev) { return -1; } ret = adc_read(adc_dev, &sequence); printk("\nADC read err: %d\n", ret); /* Print the AIN0 values */ printk("ADC raw value: "); for (int i = 0; i < BUFFER_SIZE; i++) { printk("%d ", m_sample_buffer[i]); } printf("\n Measured voltage: "); for (int i = 0; i < BUFFER_SIZE; i++) { float adc_voltage = 0; adc_voltage = (float)(((float)m_sample_buffer[i] / 1023.0f) * 3600.0f); printk("%f ",adc_voltage); } printk("\n"); return ret; } int read_adc(void) { int err; printk("nRF53 SAADC sampling AIN1 (READ2_MCU)\n"); adc_dev = device_get_binding(ADC_DEVICE_NAME); if (!adc_dev) { printk("device_get_binding ADC_0 failed\n"); } err = adc_channel_setup(adc_dev, &m_read2_channel_cfg); if (err) { printk("Error in adc setup: %d\n", err); } /* Trigger offset calibration * As this generates a _DONE and _RESULT event * the first result will be incorrect. */ NRF_SAADC_S->TASKS_CALIBRATEOFFSET = 1; while (1) { err = adc_sample(); if (err) { printk("Error in adc sampling: %d\n", err); } k_sleep(K_MSEC(500)); } }
/ { n: node { compatible = " "; io-channels = <&adc 4>; label = "AIN_0"; }; };