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

ADC issue (strange things happen when measuring)

Hi,

i am using the adc module to read 3 channels in an app_timer handler. I configure the adc each time i get into the handler to read the desired input and read it twice (first a dummy read out). I am using the pca10005 board. My issue is that no matter which analog input pin is use (currently AIN2,3 and 4) i get 0x03FF read at everyone of them. Like for example:

  • i use pin AIN2 and connect it to 3V3
  • all others are connected to e.g. GND or floating (result is the same no matter where the others are connected to)
  • my handler measures at all pins ( AIN2,3 and 4) the 3V3 (0x03FF) connected just to AIN2

My system voltage is 3.3V and my max ADC input voltage is 3.3V. The configuration in my app_timer handle function is like following:


static void meas_timeout_handler(void * p_context)
{
    //uint32_t        err_code;
		static uint8_t channel = 0;
		uint32_t adcChannelRawValue = 0;
		uint32_t adcChannelMeasuredVoltage = 0;

		UNUSED_PARAMETER(p_context);
	
    NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) | 	
											(ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |	
                      (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) |
                      (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
	
		if(channel > 2)
		{
				channel = 0;
		}

		switch(channel)
		{
			case BATTERY_VOLTAGE_SENSOR: NRF_ADC->CONFIG |= (ADC_CONFIG_PSEL_AnalogInput2 << ADC_CONFIG_PSEL_Pos);
				break;
			case BATTERY_CURRENT_SENSOR: NRF_ADC->CONFIG |= (ADC_CONFIG_PSEL_AnalogInput3 << ADC_CONFIG_PSEL_Pos);
				break;
			case LED_TEMPERATURE_SENSOR: NRF_ADC->CONFIG |= (ADC_CONFIG_PSEL_AnalogInput4 << ADC_CONFIG_PSEL_Pos);
				break;
			default:
				break;
		}

		
						// Start the ADC and dummy read
						NRF_ADC->EVENTS_END  = 0;
						NRF_ADC->TASKS_START = 1;
						while(!NRF_ADC->EVENTS_END);
						adcChannelRawValue = NRF_ADC->RESULT;
						adcChannelRawValue = 0;
						NRF_ADC->EVENTS_END = 0;
						NRF_ADC->TASKS_STOP = 1;

		
		// Start the ADC
		NRF_ADC->EVENTS_END  = 0;
		NRF_ADC->TASKS_START = 1;

		while(!NRF_ADC->EVENTS_END);
		adcChannelRawValue = NRF_ADC->RESULT;
		
		adcChannelMeasuredVoltage = adcChannelRawValue;
		//adcChannelMeasuredVoltage = (adcChannelRawValue * 3 * VBG_VOLTAGE_IN_MV) / ADC_RANGE_10BIT;
		
		NRF_ADC->EVENTS_END = 0;
		NRF_ADC->TASKS_STOP = 1;
			
		switch(channel)
		{
			case BATTERY_VOLTAGE_SENSOR:
						deviceSensorValue[BATTERY_VOLTAGE_SENSOR] = adcChannelMeasuredVoltage;
						battery_level_update();
				break;			
			case BATTERY_CURRENT_SENSOR:
						m_lis_info.value_current_battery = (uint16_t)adcChannelMeasuredVoltage;
						status_informations_update();
				break;
			case LED_TEMPERATURE_SENSOR:
						m_lis_info.value_temp_led = (uint16_t)adcChannelMeasuredVoltage;
						status_informations_update();
				break;
			case CHIP_TEMPERATURE_SENSOR:
						m_lis_info.value_temp_chip = (uint16_t)deviceSensorValue[CHIP_TEMPERATURE_SENSOR];				
					status_informations_update();
				break;			
			default:
				break;
		}	
				
		channel++;

                //zero all vars passed to status_informations_update() to see described issue more clearly
		m_lis_info.value_current_battery = 0; 
		m_lis_info.value_temp_led =	0;
		m_lis_info.value_temp_chip = 0;
}

Can anyone help me? I think my adc is configurated the right way. Is there a issue reading the adc?

Kind regards

Parents
  • You seem to lack actually enabling the ADC, by setting the ENABLE register. Try setting this before starting the conversion, and then disabling it afterwards.

    Also, the ADC will be more precise if you start the external 16 MHz clock before the reading. If you use the softdevice, this can be done by calling sd_clock_hfclk_request(), and then _release() afterwards. If you don't use the softdevice, the same can be done with the TASKS_HFCLKSTART and HFCLKSTOP in the CLOCK peripheral.

    Edit: I just added your code to the ble_app_template from the SDK, and it seems to work as expected, as long as I don't have anything else connected to the pins in question. Remember that AIN2-AIN4 are P0.01 to P0.03, so if you have the default setup, those will be bound high externally, on the nRFgo motherboard.

    I've attached the code I used.

    devzone-marius-adc.zip

Reply
  • You seem to lack actually enabling the ADC, by setting the ENABLE register. Try setting this before starting the conversion, and then disabling it afterwards.

    Also, the ADC will be more precise if you start the external 16 MHz clock before the reading. If you use the softdevice, this can be done by calling sd_clock_hfclk_request(), and then _release() afterwards. If you don't use the softdevice, the same can be done with the TASKS_HFCLKSTART and HFCLKSTOP in the CLOCK peripheral.

    Edit: I just added your code to the ble_app_template from the SDK, and it seems to work as expected, as long as I don't have anything else connected to the pins in question. Remember that AIN2-AIN4 are P0.01 to P0.03, so if you have the default setup, those will be bound high externally, on the nRFgo motherboard.

    I've attached the code I used.

    devzone-marius-adc.zip

Children
Related