I have a simple nRF51822 BLE application where a voltage is read by ADC periodically, and several values are sampled and averaged. However, from time to time, I get another erroneous ADC value. I have two relevant timers: data update timer (repeated mode, times out every few minutes) and ADC read interval timer (single-shot mode, times out in 100 ms). A global variable n is used to track the number of ADC read. The logic goes as follows:
Init: global n=0; constant N=8
Data timer times out -->
Data timer handler which starts ADC read interval timer -->
ADC read interval timer times out -->
ADC read interval timer handler: Get ADC value; n increments by 1. Is n less than N? If yes, restart ADC read interval timer; if no, set n=0, and calculate the averaged ADC value.
The ADC read function is inside ADC read interval timer handler, and is pasted here, or as follows:
static uint16_t adc10_data_get(void)
{
uint16_t adc_read;
NRF_ADC->INTENSET= 0; // disable interrupt
NRF_ADC->EVENTS_END = 0;
NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled; // Enable ADC
NRF_ADC->CONFIG = (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos) /* Bits 17..16 : ADC external reference pin selection. */
| (ADC_CONFIG_PSEL_AnalogInput5 << ADC_CONFIG_PSEL_Pos) /*!< Use analog input X as analog input. */
| (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) /*!< Use internal 1.2V bandgap voltage as reference for conversion. */
| (ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) /*!< Analog input specified by PSEL with prescaling used as input for the conversion. */
| (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos); /*!< 10bit ADC resolution. */
NRF_ADC->TASKS_START = 1; //Start ADC sampling
while (!NRF_ADC->EVENTS_END) {} // wait till ADC sampling finishes
NRF_ADC->EVENTS_END = 0;
adc_read = NRF_ADC->RESULT; // read ADC result
NRF_ADC->TASKS_STOP = 1; //Use the STOP task to save current. Workaround for PAN_028 rev1.5 anomaly 1.
return adc_read;
}
You can see I am not using ADC interrupt. The background BLE advertising interval is 1s.
For a given voltage, for majority of time, the ADC reads 0x224 which is the correct value. But from time to time, it also reads 0x287 which is 99 higher, and is obviously an incorrect value. Moreover, the erroneous value seems to be fairly independent on the number of ADC averaging. For example, it is 0x287 for both N=1 and N=5. The appearance of such anomaly seems to be less frequent if the averaging number N is lower, but I haven't done enough tests to strictly confirm this observation.
I just wonder which part of the code may cause such a behavior, and how to fix that.