Hello,
I am using the ADC on my custom board, based on nRF9160.
I am getting correct results when measuring a known voltage. However, I noticed that the execution is very slow.
I am using the following code. Using a scope, I can see that it takes ~3.8ms.
#define ADC_BIT_RANGE 14
#define ADC_NB_SAMPLES_TAKEN 8
static const struct device *adc_dev = DEVICE_DT_GET(DT_INST(0, nordic_nrf_saadc));
static int16_t m_sample_buffer[ADC_NB_SAMPLES_TAKEN];
int ADC_MeasureMillivots_Blocking(uint8_t ch)
{
uint8_t i ;
int val_mv = -1 ;
bool success = false ;
struct adc_sequence_options sequenceOption ={
.callback = NULL,
.extra_samplings = ADC_NB_SAMPLES_TAKEN-1 ,
.interval_us = 0 ,
.user_data = NULL
};
struct adc_sequence sequence = {
.options = &sequenceOption,
.channels = BIT(ch),
.buffer = &m_sample_buffer,
.buffer_size = sizeof(m_sample_buffer),
.resolution = ADC_BIT_RANGE,
.oversampling = 0,
.calibrate = false };
struct adc_channel_cfg channelConfig = {
.gain = ADC_GAIN_1_6,
.reference = ADC_REF_INTERNAL,
.acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5),
.channel_id = 1, // Will be updated just a few line below
.input_positive = 0 }; // Will be updated just a few line below
// There are only 8 channels: AN0 to AN7
if(ch <= 7)
{
// Exit low power mode
pm_device_action_run(adc_dev, PM_DEVICE_ACTION_RESUME);
// Update the configuration of the ADC channel to read, according to what is requested in argument
channelConfig.channel_id = ch ;
channelConfig.input_positive = (1 + ch) ; // Channel are offet by 1 : CH0 is input 1, CH1 is input 2, ...
// Update setup
if(!adc_channel_setup(adc_dev, &channelConfig) )
{
// Read result
if( !adc_read(adc_dev, &sequence) )
{
success = true ;
}
}
}
// Enter ADC low power
pm_device_action_run(adc_dev, PM_DEVICE_ACTION_SUSPEND);
// Convert the result
if(success)
{
// Make an average of the samples
val_mv = 0 ;
for(i=0;i<ADC_NB_SAMPLES_TAKEN;i++){
val_mv += m_sample_buffer[i] ;
}
val_mv /= ADC_NB_SAMPLES_TAKEN ;
// Convert to millivolts
adc_raw_to_millivolts(adc_ref_internal(adc_dev), channelConfig.gain, sequence.resolution, &val_mv) ;
}
else
{
// Error !
val_mv = -1 ;
}
return val_mv ;
}
Device tree is as simple as :
&adc {
status = "okay";
};
Removing the adc_read() reduces the function execution to ~10µs. It's obviously useless, as I don't get any results. But it shows that the other lines of code in this function have a very small impact on execution time.
I tried several things, but none of these made a significant difference:
- Remove the PM_DEVICE_ACTION_SUSPEND/RESUME
- Reduce the number of samples
- Reduce the resolution
- Change the acquisition time to 5, 10 or 20µs
On this topic, I notices that using the macro seems to provide strange results. File zephyr/drivers/adc.h states that range is 0-16383, but I see the following values :
> ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5) returns 16389
> ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10) returns 16394
> ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20) returns 16404
I am currently using NCS v2.5.2
Any hint on what can be wrong / how to improve speed ?
Thanks.