adc_read gets stuck when reading multiple channels in a single call

Hi,

I've stumbled upon an adc_read issue on NRF52832, where following a certain sequence, adc_read gets stuck forever. I'm inserting a small code block that replicates the issue for me (on the second/third run). In the example, I read one channel first with calibration on, then go ahead and read two channels with a single call (providing the appropriate mask in adc sequence) & in this case it gets stuck on the first/second run of the code block. If I read all channels one by one, or, enable calibration for the two channel read, it does not get stuck. Have you noticed any similar behavior? Did I misconfigure something or maybe this is a known issue? Thanks!

int16_t ch0_sample;
int16_t ch6ch7_sample[2];

struct adc_sequence seq_ch0 =
{
	.buffer = &ch0_sample,
	.buffer_size = sizeof ch0_sample,
	.calibrate = true,
	.channels = BIT(0),
	.oversampling = 4,
	.resolution = 12
};

struct adc_sequence seq_ch6ch7 =
{
	.buffer = ch6ch7_sample,
	.buffer_size = sizeof ch6ch7_sample,
	.calibrate = false,
	.channels = BIT(6) | BIT(7),
	.oversampling = 0,
	.resolution = 8
};

struct adc_channel_cfg ch0_cfg = {
	.channel_id = 0,
	.gain = ADC_GAIN_1,
	.reference = ADC_REF_INTERNAL,
	.acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40),
	.input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0,
};

struct adc_channel_cfg ch6_cfg = {
	.channel_id = 6,
	.gain = ADC_GAIN_1_5,
	.reference = ADC_REF_INTERNAL,
	.acquisition_time = ADC_ACQ_TIME_DEFAULT,
	.input_positive = SAADC_CH_PSELP_PSELP_AnalogInput6,
};

struct adc_channel_cfg ch7_cfg = {
	.channel_id = 7,
	.gain = ADC_GAIN_1_5,
	.reference = ADC_REF_INTERNAL,
	.acquisition_time = ADC_ACQ_TIME_DEFAULT,
	.input_positive = SAADC_CH_PSELP_PSELP_AnalogInput7,
};

int err = adc_channel_setup(adc_device, &ch0_cfg);
if (err != 0)
{
	return err;
}

err = adc_channel_setup(adc_device, &ch6_cfg);
if (err != 0)
{
	return err;
}


err = adc_channel_setup(adc_device, &ch7_cfg);
if (err != 0)
{
	return err;
}

err = adc_read(adc_device, &seq_ch0);
if (err != 0)
{
	return err;
}

err = adc_read(adc_device, &seq_ch6ch7);
if (err != 0)
{
	return err;
}

Parents Reply Children
  • Thanks again for the helpful pointers. I think I got to the bottom of it now:

    From the reference above:

    "If more than one of the CH[n].PSELP registers is set, the device enters scan mode."

    I found that the PSELP register is only set in the adc_read (start_read in zephyr\drivers\adc\adc_nrfx_saadc.c) for channels selected in the provided sequence, thus it should enter scan mode only when calling the read, not channel configuration. Same goes for oversampling, if enabled it is set in this function for the given channel.

    However, all PSELP registers are explicitly unset if a channel is not selected in the sequence, but oversampling is only ever configured if it is enabled, i.e. it is not disabled explicitly in the start_read function for unused channels. Thus, in my case, BURST mode/oversampling is left enabled for the unused channel 0, which must cause problems then it goes into the second multiple channel adc_read (which uses scan mode for channels 6 & 7).

    If I do disable oversampling for all channels unreferenced in the sequence struct, in the start_read do-while loop, all goes well and adc does not get stuck at cases I've tested. So I'm not sure if this was the intended behavior or is an oversight. 

    Thanks for the help,

    Paulius

  • Thanks for the detailed analysis! Much appreciated.

    Kenneth

Related