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";
};
};