This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Abnormal ADC read with SoftDevice

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.

Parents
  • Hi

    I have heard it before that the ADC occasionally gives incorrect value if sampling on multiple pins with high sampling frequency. I have not yet figured out the root cause of this potential issue but I suspect that it is caused because sampling is started immediately after the configuration, which is what you are doing it seems.

    Try to add a delay between between configuring the ADC and starting the sampling, just to see if that fixes the issue. You could also configure the ADC first in a adc_config function and then take the multiple samples for the averaging. Let me know how that turns out.

Reply
  • Hi

    I have heard it before that the ADC occasionally gives incorrect value if sampling on multiple pins with high sampling frequency. I have not yet figured out the root cause of this potential issue but I suspect that it is caused because sampling is started immediately after the configuration, which is what you are doing it seems.

    Try to add a delay between between configuring the ADC and starting the sampling, just to see if that fixes the issue. You could also configure the ADC first in a adc_config function and then take the multiple samples for the averaging. Let me know how that turns out.

Children
  • I separate the ADC configuration and ADC reading as you suggested, and make ADC configured once and read several times. I make the ADC reading interval timer time out in 100 ms, so there is 100 ms delay between the ADC finishing configuration and the first ADC reading. I still observe the same behavior. I also make ADC only read once (number of averaging =1) in each measurement, and I still have the same issue. Note that I only use one ADC channel. One extra piece of information I want to provide is I enable PWM on another GPIO pin before ADC sampling each time. I don't know if the two are related.

  • Ok, thank you for the additional information and your experiments. I think it brings us closer to the actual problem. From your experiments, I suspect that my previously mentioned theory of needing to have delay between ADC configuration and sampling is incorrect. There must be another reason for your observation.

    Good that you mention the PWM. We have experienced that when toggling GPIO pins can create noise on adjacent GPIO pins. Try to disable the PWM or use a different GPIO pin for it, to see if the problem goes away. Or use another input pin for the ADC.

  • Hi Stefan, it turns out ADC read fine. In my application the voltage ADC read was correlated to the PWM signal. I find PWM waveform was regularly and randomly inverted, and that was why ADC read erroneous values. I have opened up a separate thread here devzone.nordicsemi.com/.../ , and will really appreciate if you can comment on that issue.

  • Thank you for your feedback diode. Good that we ruled out that the ADC was the source for the issue. I'll try to look into your PWM issue

Related