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.