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

ADC Sequential Read Issue

I'm having an issue when trying to perform sequential reads with the ADC on 4 different pins. I've setup a timer to trigger every 1 second. In the Timer0 IRQ I setup the ADC for the first pin, and start a read using NRF_ADC->TASKS_START = 1;

Then in the ADC IRQ I increment the ADC pin configuration and trigger the next read until my counter reaches 4 at which point I just setup the ADC for my first pin but don't trigger again as the timer IRQ will do this on it's next iteration.

The issue I'm having is that if I pull one of the 4 ADC pins to GND, all 4 ADCs will start to read 1. I noticed that on my first iteration they read correctly until reading the shorted one, so I tried re-initializing the ADCs between each iteration and that fixed it. I've now narrowed it down to having to reconfigure the prescaling and the resolution in which case it works.

In short, the below code works as intended but why do I need to do the first two commands in "ADC_pin_configure()"??

/** @file
* @brief Example template project.
* @defgroup nrf_templates_example Example Template
*
*/

#include <stdbool.h>
#include <stdint.h>

#include "boards.h"
//#include "bsp.h"
//#include "nordic_common.h"

#include "nrf.h"
#include "nrf_delay.h"
#include "nrf_drv_adc.h"
#include "nrf_drv_timer.h"
#include "nrf_gpio.h"

#include "app_error.h"
#include "app_timer.h"
//#include "app_util_platform.h"
#include "app_uart.h"

#include "uart.h"


const nrf_drv_timer_t            pADC_Timer = NRF_DRV_TIMER_INSTANCE(0);
static uint8_t                   m_adc_pin_configuration;

void timer_init(uint32_t time_us);
void ADC_pin_configure(uint8_t pin_number);
void ADC_init(uint8_t pin_number);


/**
 * @brief Handler for timer events.
 */
void timer_handler(nrf_timer_event_t event_type, void* p_context)
{

  switch (event_type)
  {
	case NRF_TIMER_EVENT_COMPARE0:
	  printf("\r\n");
	  bsp_board_led_invert(0);
  
	  //start sampling 
	  NRF_ADC->TASKS_START = 1;
  
	  break;

	default:
	  break;
  }
}

/* Interrupt handler for ADC data ready event */
void ADC_IRQHandler(void)
{
	uint32_t adc_result_calibrated = NRF_ADC->RESULT;

	/* Clear dataready event */
  NRF_ADC->EVENTS_END = 0;	
	
	switch(m_adc_pin_configuration)
	{
	//Record ADC reading, configure ADC for the next pin and trigger sample
		case ADC_CONFIG_PSEL_AnalogInput6: 
			printf("ADC 6:  %d\r\n", adc_result_calibrated);	
			ADC_pin_configure(ADC_CONFIG_PSEL_AnalogInput5);
			NRF_ADC->TASKS_START = 1;
			break;

		case ADC_CONFIG_PSEL_AnalogInput5: 
			printf("ADC 5:  %d\r\n", adc_result_calibrated);	
			ADC_pin_configure(ADC_CONFIG_PSEL_AnalogInput4);
			NRF_ADC->TASKS_START = 1;
			break;  

		case ADC_CONFIG_PSEL_AnalogInput4: 
			printf("ADC 4:  %d\r\n", adc_result_calibrated);	
			ADC_pin_configure(ADC_CONFIG_PSEL_AnalogInput3);
			NRF_ADC->TASKS_START = 1;
			break;       

		case ADC_CONFIG_PSEL_AnalogInput3: 
			printf("ADC 3:  %d\r\n", adc_result_calibrated);	
			ADC_pin_configure(ADC_CONFIG_PSEL_AnalogInput6);
			break;
	}
}

void ADC_pin_configure(uint8_t pin_number)
{
  /* 10-bit Resolution */
  NRF_ADC->CONFIG = ((ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) & ADC_CONFIG_RES_Msk);

  /* 2/3 prescaling */
  NRF_ADC->CONFIG |= ((ADC_CONFIG_INPSEL_AnalogInputTwoThirdsPrescaling << ADC_CONFIG_INPSEL_Pos) & ADC_CONFIG_INPSEL_Msk);
  
	NRF_ADC->CONFIG	|= (pin_number << ADC_CONFIG_PSEL_Pos);
	m_adc_pin_configuration = pin_number;
}


/**
 * @brief Function for application main entry.
 */
int main(void)
{
  uint32_t time_us = 1000000; //Time(in microseconds) between consecutive compare events.
  
  /* Configure board. */
  uart_init();
  bsp_board_leds_init();
  printf("\r\nUART Start!\r\n");
  
  timer_init(time_us);
 
  ADC_init(ADC_CONFIG_PSEL_AnalogInput6);
  
  while (true)
  {
	// enter into sleep mode
	//__SEV();
	//__WFE();
	__WFI();
  }
}

void timer_init(uint32_t time_us)
{
  uint32_t err_code = NRF_SUCCESS;  
  uint32_t time_ticks;
  
  //Configure pADC_Timer for generating simple light effect - leds on board will invert his state one after the other.
  nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
  err_code = nrf_drv_timer_init(&pADC_Timer, &timer_cfg, timer_handler);
  APP_ERROR_CHECK(err_code);

  time_ticks = nrf_drv_timer_us_to_ticks(&pADC_Timer, time_us);
  nrf_drv_timer_extended_compare(&pADC_Timer, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
  nrf_drv_timer_enable(&pADC_Timer); 
}

/** Configures and enables the ADC
 */
void ADC_init(uint8_t pin_number)
{	
	/* Enable interrupt on ADC sample ready event*/		
	NRF_ADC->INTENSET = ADC_INTENSET_END_Msk;
  
	NVIC_EnableIRQ(ADC_IRQn);	

  /* Init the ADC */
  NRF_ADC->POWER = 1;
  NRF_ADC->TASKS_STOP = 1;
  NRF_ADC->ENABLE = 1;

  /* 10-bit Resolution */
  NRF_ADC->CONFIG = ((ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) & ADC_CONFIG_RES_Msk);

  /* 2/3 prescaling */
  NRF_ADC->CONFIG |= ((ADC_CONFIG_INPSEL_AnalogInputTwoThirdsPrescaling << ADC_CONFIG_INPSEL_Pos) & ADC_CONFIG_INPSEL_Msk);

  /* set input analog pin - Analog Pin 5 is BMD200_PIN_15 */
  NRF_ADC->CONFIG |= ((ADC_CONFIG_PSEL_AnalogInput6 << ADC_CONFIG_PSEL_Pos) & ADC_CONFIG_PSEL_Msk);

  /* set reference to internal 1.2V */
  NRF_ADC->CONFIG |= ((ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) & ADC_CONFIG_REFSEL_Msk);

  /* disable ext reference */
  NRF_ADC->CONFIG |= ((ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos) & ADC_CONFIG_EXTREFSEL_Msk);  
  
  ADC_pin_configure(pin_number);
	
	/* Enable ADC*/
	NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;	
}
Related