This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf 51822 IO values not as expected

Good morning all,

We have a circuit based on 51822 chip.

We are currently trying to monitor some value from 0v to 24v from the analog inputs. It's working, however, we have found 2 issues.

  1. The values we get are between 74 (0V) and 496 (24V) The precise formula is Y = 17,554X + 74,443 with Rquare = 1 where X is the voltage input value and the analog value we get from the chip.

  2. Sometimes we need to call the function 2 times in order to get the right analog value for a given voltage. (could it be a buffer problem?)

See image below. I have traced this curve from several measurements. image description

Where this could come from?

To get the 24v down to a reasonable voltage we are using this voltage divider image description (370k, 2.2M)

To get the value from an input, we are using this formula:

 U16 AINS_GetValue(U8 innum)
 
 {
  //Clear Event flags
 nrf_adc_conversion_event_clean();

 //Read Sample
 AIns.ADC_Channel[innum].ADC_Buf[AIns.ADC_Channel[innum].State.Bits.Index++] = nrf_adc_result_get();

 //Find average
 AIns.ADC_Channel[innum].ADC_Avg = 0;
 for(U8 i = 0; i < 4; i++) AIns.ADC_Channel[innum].ADC_Avg += AIns.ADC_Channel[innum].ADC_Buf[i];
 AIns.ADC_Channel[innum].ADC_Avg >>= 2;

 //Return value
 return AIns.ADC_Channel[innum].ADC_Avg;

 }

where both functions (nrf_adc_conversion_event_clean(); nrf_adc_result_get(); ) are from the Nordic Semi Ble UART application code.

Could it be my the //Read Sample part of the code the problem?

ADC initialization seems to be OK with the right scaling/resolution/reference but maybe I'm wrong... Inputs # are good since these values are the same for the 4 inputs.

 void AINS_Init(void)
 {
 U32                      pCompareEvent;
 U32                      pADCTask;
 nrf_ppi_channel_t        PPIChannel;
 ret_code_t               error;
 U32                      TimerTicks;
 nrf_adc_config_t         ADCConfig = NRF_ADC_CONFIG_DEFAULT;

 //Initialize AINS structure  
 AIns.Current.Number = 0;
 AIns.ADC_Channel[AIN1].hwChannel = AIN1_HWCHN;
 AIns.ADC_Channel[AIN2].hwChannel = AIN2_HWCHN;
 AIns.ADC_Channel[AIN3].hwChannel = AIN3_HWCHN;
 AIns.ADC_Channel[AIN4].hwChannel = AIN4_HWCHN;
 
 for(U8 i = 0; i < 4; i++)
 {
 AIns.ADC_Channel[i].ADC_Avg = 0;
 AIns.ADC_Channel[i].State.Raw = 0;
 for(U8 j = 0; j < 4; j++) AIns.ADC_Channel[i].ADC_Buf[j] = 0;
 }

 //Initialize PPI
 error = nrf_drv_ppi_init();
 APP_ERROR_CHECK(error);

 //Initialize Timer
 error = nrf_drv_timer_init(&Timer, NULL, Timer_EventHandler);
 APP_ERROR_CHECK(error);

 //Initialize ADC
 ADCConfig.scaling    = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
 ADCConfig.resolution = NRF_ADC_CONFIG_RES_10BIT;
 ADCConfig.reference  = NRF_ADC_CONFIG_REF_VBG;
 nrf_adc_configure(&ADCConfig);
 nrf_adc_input_select((nrf_adc_config_input_t)AIns.ADC_Channel[AIns.Current.Number].hwChannel);
 nrf_adc_int_enable(ADC_INTENSET_END_Enabled << ADC_INTENSET_END_Pos);
 sd_nvic_SetPriority(ADC_IRQn, NRF_APP_PRIORITY_LOW);  
 sd_nvic_EnableIRQ(ADC_IRQn);

//Configure Timer to generate an event every XX us
TimerTicks = nrf_drv_timer_us_to_ticks(&Timer, AIN_ADC_SAMPLE_PERIOD_US);
nrf_drv_timer_extended_compare(&Timer, NRF_TIMER_CC_CHANNEL0, TimerTicks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);

 //Allocate PPI Channel
error = nrf_drv_ppi_channel_alloc(&PPIChannel);
APP_ERROR_CHECK(error);

//Get Event and Task Pionters
pCompareEvent = nrf_drv_timer_event_address_get(&Timer, NRF_TIMER_EVENT_COMPARE0);
pADCTask = (U32)nrf_adc_task_address_get(NRF_ADC_TASK_START);

//Assign and Enable PPI channel
error = nrf_drv_ppi_channel_assign(PPIChannel, pCompareEvent, pADCTask);
APP_ERROR_CHECK(error);
error = nrf_drv_ppi_channel_enable(PPIChannel);
APP_ERROR_CHECK(error);

//Enable timer
nrf_drv_timer_enable(&Timer);
}

Maybe someone see right away what we are doing wrong?

Thanks everyone!

EDIT: Excel file for capacitor calculation CapacitorCalculationforVoltageDivider20160913v1.xls

EDIT BIS: OP AMP to isolate ADC image description

Regards,

Francois

  • Could it be a good option to use an OP-AMP in order to isolate the signal from the ADC? How do we add pictures in comment? Please see added picture in original post. Sorry for so many questions.

  • Hi Fransois

    By inserting a few extra numbers into your excel sheet, you should be seeing value ~819 on the ADC output (10-bit, 1/3 prescaler) when inserting 20V into a 2200k/370k voltage divider and with adequately large capacitor connected in the circuit and slow sampling frequency (<0.5Hz). According to the calculation, the capacitor should be ~1uF.

    To be honest, I was not completely satified with the calculation result in the pdf document. I was fairly confident with the theory and the equations, but the result was 70nF, but in practice we found that 22nF was adequate. So there is perhaps something that I have not taken into account, but I think this still gives a good idea about the size.

    You can verify the capacitor size with trial and error method. First do the calculation and install that capacitor that you have calculated and test the ADC output with small sampling frequency, e.g. 0.5 Hz. Step 2 is to install a capacitor double that size. If you get the same ADC output as before , then the former capacitor size was not to small. Try then to put half the capacitor size as the first one, if you get lower or higher value than before, the capacitor is too small. If you get the same ADC output, you can try to decrease the capacitor further until you see an error on the ADC output. My point is: increase the size of the capacitor until you stop seeing ADC output error, then the capacitor is big enough. Check for error near the boundary of the ADC range, e.g. at 1.1V if the range is 0V-1.2V

    Operational amplifier is good yes and is the way to go if you need higher sampling frequency than perhaps ~1Hz - 5Hz. Capacitor is simpler solution and cheaper.

  • Amazing answer! Thank you.

    I guess there is something missing as the value I get today with no capacitor and the voltage divider does not correspond to what is in your file. Are you sure about ADC resistance value?

    I will try with a very big one (425nf) as I don't need high level of reactivity. Will try other value on test board.

    Thanks again, will keep you informed.

    Cheers,

    Francois

  • Very good.

    The values for the ADC internal resistors are documented in table 313 in the nRF51 Series Reference Manual v3.0.

Related