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

nRF52 SAADC Double Buffering

Hi,

I am trying to use the SAADC to periodically sample an input from AIN0 and send the resultant data over a BLE link to a phone. Going through the forums I saw that the ble_app_proximity is a good example of this so I went ahead to try and understand how it is designed.

In a nutshell, to my understanding, it is using a timer to call the nrf_drv_saadc_sample()function and when complete as signalled by NRF_DRV_SAADC_EVT_DONEthe resultant data is converted and transmitted.

Within the adc_configure() function there is the following:

err_code = nrf_drv_saadc_buffer_convert(&adc_buf[0],1);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_saadc_buffer_convert(&adc_buf[1],1);
APP_ERROR_CHECK(err_code);

According to SAADC documentation in infocenter, this is explained as:

The driver supports double buffering, which means that nrf_drv_saadc_buffer_convert can be called twice and the buffer that is provided in the second call will be used immediately after the first one is filled.

So this is clear to me that the second buffer will be used if the first one is filled - which is called double buffering here. But later in the saadc_event_handler there is another call err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,1)

I am unable to understand what this call does (even though the documentation says that this is the setup for continuous conversion. Can someone please explain this in a little more detail?

My questions are basically as follows:

  1. When sampling an input voltage, my first result goes to adc_buf[0] and only if it is full (because I haven't read it?) it will go to adc_buf[1] .. is that how it is supposed to be?

  2. What does the call nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,1) do within the saadc_event_handler?

  3. If I don't set up double buffering i.e. only have a single call as below, what will happen? And will I still need a call to this function in the event handler?

    err_code = nrf_drv_saadc_buffer_convert(&adc_buf[0],1);

  • Hi,

    1. Yes, you will get a NRF_DRV_SAADC_EVT_DONE when adc_buf[0] result is ready and another when adc_buf[1] is ready.

    2. It sets up the completed buffer for the next conversion in non-blocking mode. So initially you have adc_buf[0] and adc_buf[1] set up as the 2 buffers. Then when you get the first NRF_DRV_SAADC_EVT_DONE event the completed buffer is adc_buf[0]. The nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,1) call sets up adc_buf[0] for conversion again, so the next 2 buffers will be adc_buf[1] and adc_buf[0]. If you don't call nrf_drv_saadc_buffer_convert at this point then your next buffer is just adc_buf[1] and is no longer double buffered.

    3. You will still get the NRF_DRV_SAADC_EVT_DONE event when adc_buf[0] is complete. If you want to continue sampling you will have to call nrf_drv_saadc_buffer_convert to set up adc_buf[0] again for conversion, otherwise you won't have any buffers ready for conversion.

  • Many thanks for the explanation James. So from (3) of your answer, I understand that regardless of sing;e/double buffering scheme nrf_drv_saadc_buffer_convert needs to be called to set up a buffer for conversion before sampling.

    However, I have a couple of follow up questions about (2):

    Initially, as you said, I have adc_buf[0] and adc_buf[1], and the call to nrf_drv_saadc_buffer_convert() sets up adc_buf[0] for conversion. The next two buffers will then be adc_buf[1] and adc_buf[0] ... do you mean in that order i.e. array element 1 and 0? If so, why?

    Secondly, in a double buffered scheme with adc_buf[0] and adc_buf[1], what is the purpose of the second buffer? If adc_buf is an array with 16-bit elements, each sample will be 10-bits so what purpose does it serve to have an extra buffer element?

  • Yes it will be in that order. Think of it as a FIFO queue: your first two nrf_drv_saadc_buffer_convert calls sets up the queue as adc_buf[0], adc_buf[1]. When the first saadc_event_handler occurs adc_buf[0] is removed from the queue, and when nrf_drv_saadc_buffer_convert is called again in the event handler adc_buf[0] is added back to the queue making it adc_buf[1], adc_buf[0].

    The saadc example is better for understanding how a double buffered scheme could be useful. Instead of adc_buf[2], lets say you have adc_buf[2][1000], so now instead of having 2 buffers with 1 value each you have 2 buffers with 1000 values each. If you need to perform some operations on these 1000 samples it may be hard to maintain a high sampling rate at the same time. But with a double buffered scheme you can perform operations on 1 buffer while at the same time doing conversation on the other.

  • I've noticed in most of the examples that nrf_drv_saadc_buffer_convert() is called in the event handler, prior to the resulting buffer being processed.

    Does this mean that buffers we pass to nrf_drv_saadc_buffer_convert() are guaranteed not to be filled until the event handler has finished processing? Or, should the results of the buffer in the event handler be processed, prior to calling nrf_drv_saadc_buffer_convert() and re-enabling it for data streaming.

Related