<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ADC - how to consume fast samples while avoiding race conditions?</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/79050/adc---how-to-consume-fast-samples-while-avoiding-race-conditions</link><description>Hi everyone, 
 I have a fairly simple use for ADC: sample 4 channels (scan mode) every 10ms and store in RAM. 
 Every now and then (asynchronously) there will be a function or a task (not in ISR context) that will want to read the latest values of the</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Tue, 31 Aug 2021 16:09:07 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/79050/adc---how-to-consume-fast-samples-while-avoiding-race-conditions" /><item><title>RE: ADC - how to consume fast samples while avoiding race conditions?</title><link>https://devzone.nordicsemi.com/thread/327476?ContentTypeID=1</link><pubDate>Tue, 31 Aug 2021 16:09:07 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:29dc3394-6c28-470a-a7e9-6b0872317ba5</guid><dc:creator>mikemike651</dc:creator><description>&lt;p&gt;Thank you Einar! The atomic functions might just be what I need.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: ADC - how to consume fast samples while avoiding race conditions?</title><link>https://devzone.nordicsemi.com/thread/327353?ContentTypeID=1</link><pubDate>Tue, 31 Aug 2021 08:47:07 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:558740ea-1387-45f9-bf26-3b5e81170094</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;OK, now I see. This is not directly related to the SAADC driver, then. If you are only interested inthe very last sample and you want to do this simply and safely, perhaps you could stay with the buffer size you had (one sample for each channel in each buffer), and simply copy out to a variable which is not one of the two buffers in the event handler. This is a quite fast operation, so it should be OK to do this in the SAADC interrupt.&lt;/p&gt;
&lt;p&gt;The above can be done atomically using the&amp;nbsp;LDREX/STREX instructions, and the SDK has a helper library for that: &lt;a href="https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.0.2/group__nrf__atomic.html"&gt;nrf_atomic&lt;/a&gt;. IThat could be used direclty, but it&amp;nbsp;is used to implement other modules as well, such as &lt;a href="https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.0.2/group__nrf__ringbuf.html"&gt;nrf_ringbuf&lt;/a&gt;. I am sure there are other methods as well, some may be better for your use case, but this gives an idea of the toolbox you have at hand.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: ADC - how to consume fast samples while avoiding race conditions?</title><link>https://devzone.nordicsemi.com/thread/327280?ContentTypeID=1</link><pubDate>Mon, 30 Aug 2021 15:56:04 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a7fb10ad-305a-4142-a12e-24f2e0a2d0a1</guid><dc:creator>mikemike651</dc:creator><description>&lt;p&gt;Thanks for your patience Einar, sure I&amp;#39;ll try to explain.&lt;/p&gt;
&lt;p&gt;With your suggestion I will have a dual buffer scheme that is updated every 100ms:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family:courier new, courier;"&gt;static nrf_saadc_value_t m_buffer_pool[2][ADC_NUM_SAMPLES_IN_BUFFER];&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;While the hardware updates index 0, the user can consume index 1, and vice-versa (the active buffer is marked by &lt;span style="font-family:courier new, courier;"&gt;m_buffer_index&lt;/span&gt; in my code). My concern is that because the consumption is done asynchronously (it is unaware of when the last batch of fresh samples has arrived), it can happen at the end of the 100ms window just before the ISR fires with new samples.&lt;/p&gt;
&lt;p&gt;In the code I posted, the ISR updates &lt;span style="font-family:courier new, courier;"&gt;m_buffer_index&lt;/span&gt;, and I&amp;#39;m worried it will happen while the user is trying to access it (and the buffer), in the function &lt;span style="font-family:courier new, courier;"&gt;adc_get_latest_values()&lt;/span&gt; which I posted originally.&lt;/p&gt;
&lt;p&gt;What I&amp;#39;m trying to ask is, is there a software solution, say a FIFO, a ring buffer, or some synchronization trick, that can help with this potential issue?&lt;/p&gt;
&lt;p&gt;Thanks again for your help.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: ADC - how to consume fast samples while avoiding race conditions?</title><link>https://devzone.nordicsemi.com/thread/327277?ContentTypeID=1</link><pubDate>Mon, 30 Aug 2021 15:42:03 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5d010f17-ee79-44f4-9b56-56a17dbec481</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I am not sure I understand the context here. If you sample every 10 ms and use the buffer size I suggested, that means buffers swap every 100 ms (you can use lager buffers as well). And so, from you get the event/interrupt with the buffer filled you know it will take at least 100 ms (in this example) before any data can change. That should give you a lot of time to use this data, copy it somewhere or whatever you need to do before there is any risk of it being&amp;nbsp;corrupted.&lt;/p&gt;
&lt;p&gt;I do not see why disabling interrupts would be relevant in this situation, as we are not talking about short times here. So you are right it would not work, but also It does not seem relevant. Or perhaps I don&amp;#39;t understand where you mean there is a race condition? If so, perhaps you can explain in more detail in that case?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: ADC - how to consume fast samples while avoiding race conditions?</title><link>https://devzone.nordicsemi.com/thread/327276?ContentTypeID=1</link><pubDate>Mon, 30 Aug 2021 15:32:12 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5f2cb3ad-3884-422d-b3da-65f3cb470e9e</guid><dc:creator>mikemike651</dc:creator><description>&lt;p&gt;Thanks for your answer Einar.&lt;/p&gt;
&lt;p&gt;Even if we use larger buffers, there is still the chance that while (asynchronously) reading the buffer that&amp;#39;s not being currently used by hardware, a new ISR will kick in and change the buffer pointer. Are you aware of any software tricks that might help with that, or maybe have a code example that would show a guaranteed way to avoid a race condition?&lt;/p&gt;
&lt;p&gt;Usually in such scenarios, disabling interrupts is a decent solution, but I read that in the nRF SDK it may mess up the SoftDevice stack (which in our case needs to be running while using the ADC).&lt;/p&gt;
&lt;p&gt;Appreciate your help!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: ADC - how to consume fast samples while avoiding race conditions?</title><link>https://devzone.nordicsemi.com/thread/327273?ContentTypeID=1</link><pubDate>Mon, 30 Aug 2021 15:22:58 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:6893381c-503a-4bab-b7d4-fecf852142e0</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;In principle 10 ms should be enough time for most tasks. Do you have a rush to use the values from the SAADC? If you do not need the latest samples every 10 ms, then you could use larger buffers, so that you would not have to swap buffers every 10 ms. Lets say you use set ADC_NUM_SAMPLES_IN_BUFFER to (NUM_SAADC_CHANNELS * 10) that would give you more time to process the data before they are updated. (I just suggested 10 here, a different number might make more sense in your application).&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>