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

Simulataneous ADC sampling

Hello, I am trying to make adc sampling on two adc inputs at the same time. The adc example (simulataneous-adc-sampling-from-two-inputs) is not using IRQ handler and applying some delay, but I really want to sample them at the same time. Here is my code and I am checking with nRF-UART app, it seems like the code doesn't work properly. I am very bad at programming. Please help me figure out the problem.

static void adc_init(void)
{	
	/* Enable interrupt on ADC sample ready event*/		
	NRF_ADC->INTENSET = ADC_INTENSET_END_Msk;   
	sd_nvic_SetPriority(ADC_IRQn, NRF_APP_PRIORITY_LOW);  
	sd_nvic_EnableIRQ(ADC_IRQn);
	
	NRF_ADC->CONFIG	= (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos) /* Bits 17..16 : ADC external reference pin selection. */
									| (ADC_CONFIG_PSEL_AnalogInput2 << ADC_CONFIG_PSEL_Pos)					/*!< Use analog input 2 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 no prescaling used as input for the conversion. */
									| (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos);									/*!< 8bit ADC resolution. */ 
	
	/* Enable ADC*/
	NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
	adc_result1 = NRF_ADC->RESULT;
	
}

static void adc_init2(void)
{	
	/* Enable interrupt on ADC sample ready event*/		
	NRF_ADC->INTENSET = ADC_INTENSET_END_Msk;   
	sd_nvic_SetPriority(ADC_IRQn, NRF_APP_PRIORITY_LOW);  
	sd_nvic_EnableIRQ(ADC_IRQn);
	
	NRF_ADC->CONFIG	= (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos) /* Bits 17..16 : ADC external reference pin selection. */
									| (ADC_CONFIG_PSEL_AnalogInput6 << ADC_CONFIG_PSEL_Pos)					/*!< Use analog input 2 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 no prescaling used as input for the conversion. */
									| (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos);									/*!< 8bit ADC resolution. */ 
	
	/* Enable ADC*/
	NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
	adc_result2 = NRF_ADC->RESULT;
}

/* Interrupt handler for ADC data ready event */
void ADC_IRQHandler(void)
{
	uint8_t adc_result1;
	uint8_t adc_result2;
	
	/* Clear dataready event */
  NRF_ADC->EVENTS_END = 0;	

  /* Write ADC result both to the UART and over BLE */
//	adc_result = NRF_ADC->RESULT;
	app_uart_put(adc_result1);
	app_uart_put(adc_result2);
	ble_nus_send_string(&m_nus, &adc_result1, 1);
	ble_nus_send_string(&m_nus, &adc_result2, 1);
	nrf_gpio_pin_toggle(LED_3);        //indicate on LED that the ADC interrupt handler is executing
	
	//Use the STOP task to save current. Workaround for PAN_028 rev1.5 anomaly 1.
  NRF_ADC->TASKS_STOP = 1;
	
	//Release the external crystal
	sd_clock_hfclk_release();
}	
Parents Reply Children
  • Thank you for the work Stefan. But it looks like it is sampling two inputs sequentially. I have also looked at similar questions posted on the developer zone, but they don't seem to work in simultaneous fashion. I am curious whether real simultaneous sampling is even possible

  • Actual simultaneous ADC sampling is not possible. You will always have to sample one pin and then the other pin. In order to make it simultaneous, you would need two ADC peripherals, but the nRF51 only has one.

    The time difference between the two samples is approximately the duration of the sampling plus ~10us. It takes ~10us to enter the ADC interrupt handler, reconfigure the ADC and start the sampling on the second pin. For 8-bit sampling, the time difference would be 20+10=30us. For 10-bit sampling the time difference would be 68+10=78us

  • Thank you for the reply. I have one more question. Is there any example that enable two ADC using IRQ? All the examples and questions that can be found here is only using PPI, so it will be really helpful to have an example with IRQ.

  • In the example above, when both of the pins have been sampled, the ADC interrupt handler is entered.

    If you want to start the ADC sampling from a RTC interrupt hanlder instead of directly connecting the RTC with the ADC->START task via PPI, then you could enable the RTC0 interrupt in the following way:

    static void rtc_config(void)
    {
    	NRF_RTC0->PRESCALER = COUNTER_PRESCALER;                   // Set prescaler to a TICK of RTC_FREQUENCY
    	NRF_RTC0->EVTENSET = RTC_EVTENSET_TICK_Msk;                // Enable TICK event			
    	NRF_RTC0->INTENSET = RTC_INTENSET_TICK_Msk;		    //Enable RTC interrupt on TICK event
    	NVIC_EnableIRQ(RTC0_IRQn);						    //Enable RTC interrupt
    	
    	NRF_RTC0->TASKS_START = 1;                                               // Start RTC0
    }
    

    And then you would define the RTC0 interrupt handler like this:

    void RTC0_IRQHandler(void)
    {
        NRF_RTC0->EVENTS_TICK = 0;
        NRF_ADC->TASKS_START = 1;
    }
    
Related