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

Understanding SAADC output buffer nondeterministic behavior.

Hi there, 

I am implementing the SAADC example into my application whereby I should be able to sample all 8 ADC channels "simultaneously" at a relatively high frequency.

I am using the same setup given in the example ->    \examples\peripheral\saadc. 

 1. Set up a ppi channel so that timer compare event is triggering sample task in SAADC. This roughly 160 uS. 

 2.  Initialize ADC channels with default configuration. 

	    nrf_saadc_channel_config_t channel_config0 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
		nrf_saadc_channel_config_t channel_config1 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);
		nrf_saadc_channel_config_t channel_config2 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
	    nrf_saadc_channel_config_t channel_config3 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
		nrf_saadc_channel_config_t channel_config4 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
		nrf_saadc_channel_config_t channel_config5 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);
		nrf_saadc_channel_config_t channel_config6 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
		nrf_saadc_channel_config_t channel_config7 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);


		 err_code = nrf_drv_saadc_channel_init(0, &channel_config0); 
		 APP_ERROR_CHECK(err_code);

		 err_code = nrf_drv_saadc_channel_init(1, &channel_config1);	// 	POGO 7, pos Buff out 1
		 APP_ERROR_CHECK(err_code);
		 
		 err_code = nrf_drv_saadc_channel_init(2, &channel_config2); 
		 APP_ERROR_CHECK(err_code);
		 
		 err_code = nrf_drv_saadc_channel_init(3, &channel_config3);
		 APP_ERROR_CHECK(err_code);
		 
		 err_code = nrf_drv_saadc_channel_init(4, &channel_config4); 
		 APP_ERROR_CHECK(err_code);
		 
		 err_code = nrf_drv_saadc_channel_init(5, &channel_config5); 
		 APP_ERROR_CHECK(err_code);
		 
		 err_code = nrf_drv_saadc_channel_init(6, &channel_config6); 
		 APP_ERROR_CHECK(err_code);
		 
		 err_code = nrf_drv_saadc_channel_init(7, &channel_config7); 
		 APP_ERROR_CHECK(err_code);

3. Every time my input signal completes a full period, I start a new ADC conversion, like this. 

	err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);	//Non blocking call
	APP_ERROR_CHECK(err_code);

That all works fine, since my input signal is square wave at 250 Hz, I have verified that with my logic analyzer. 

However the Issue is when a read the output buffer which is 200 long. 25 samples per input signal period 0.4 ms. 

Having initialized my ADC channels as mentioned above: 

I would expect the results to be stored, like this: (ADCx = AINx). 

[ ADC0 , ADC1 , ADC2 , ADC3 , ADC4 , ADC5 , ADC6 , ADC7] and repeat this behavior for n Samples. 

However, I actually get this order: triggering samples every 160 uS. 

[ ADC6 , ADC7 , ADC0 , ADC1 , ADC2 ,  ADC3 , ADC4 , ADC5]

If I change the sample rate to somehting diffferent like 1 mS. 

I get : 

[ ADC5 , ADC3 , ADC0 , ADC4 , ADC2 ,  ADC7 , ADC1 , ADC6]

So, Am I wrong at assuming that the value corresponding to each AIN should correspond to the order in which I initialized the channels ?  

Why does the order change depending on the sampling frequency ? 

What would be the best approach to still sample all channels and read the data for each channel accordingly ? 

Thanks ! 

Parents
  • Hi,

    Could you share a minimal project that can be run on the DK and that will reproduce the issue?

    regards

    Jared

  • Hi Jared, 

    I got the same weird order in the ADC buffer output in the example SDK, I am using SDK15.1. 

    Are there any considerations that should be taken into account when using the SAADC, in terms of setup or configuration for those 8 GPIO channels ? 

    Are they all fully available ?

    How likely is the softdevice to cause interference between the SAADC sampling process ?  

    Looking forward to hearing from you. 

    Thanks For looking into this ! 

    8686.saadc.zip

  • Hello again.

    Your case strongly resemblance the one described in this thread. In short, we have seen some issues where the layout of samples in memory are re-ordered when using the SAADC. This is usually a result of the START task being preempted/delayed after the SAMPLE task has been triggered by the PPI. A symptom of this issue is usually a reordering of samples in memory and loss of data from some channels ( it doesn't seem like you're observing the latter). The problem and purposed solutions are explained in the thread.

    However,  I would like you to try a couple of things before you try the solutions in that thread:

    1. I see that you only use one buffer, and call 
      nrf_drv_saadc_buffer_convert() in the callback handler. This might be problematic if the SAMPLE task is triggered during the updating of the pointer to the result buffer. Try removing the function call from the callback handler. It shouldn't be necessary to call the function if you only use one buffer.
    2. You can try to increase the SAMPLES_IN_BUFFER

    Note: that you need to remove the trigger of TASK_START in nrfx_saadc_irq_handler() if you implement solution 1 in the linked thread.

    best regards
    Jared 
Reply
  • Hello again.

    Your case strongly resemblance the one described in this thread. In short, we have seen some issues where the layout of samples in memory are re-ordered when using the SAADC. This is usually a result of the START task being preempted/delayed after the SAMPLE task has been triggered by the PPI. A symptom of this issue is usually a reordering of samples in memory and loss of data from some channels ( it doesn't seem like you're observing the latter). The problem and purposed solutions are explained in the thread.

    However,  I would like you to try a couple of things before you try the solutions in that thread:

    1. I see that you only use one buffer, and call 
      nrf_drv_saadc_buffer_convert() in the callback handler. This might be problematic if the SAMPLE task is triggered during the updating of the pointer to the result buffer. Try removing the function call from the callback handler. It shouldn't be necessary to call the function if you only use one buffer.
    2. You can try to increase the SAMPLES_IN_BUFFER

    Note: that you need to remove the trigger of TASK_START in nrfx_saadc_irq_handler() if you implement solution 1 in the linked thread.

    best regards
    Jared 
Children
No Data
Related