1 /*
2  * Copyright (c) 2015 - 2025, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <nrfx.h>
35 
36 #if NRFX_CHECK(NRFX_ADC_ENABLED)
37 
38 #include <nrfx_adc.h>
39 
40 #define NRFX_LOG_MODULE ADC
41 #include <nrfx_log.h>
42 
43 #define EVT_TO_STR(event)   (event == NRF_ADC_EVENT_END ? "NRF_ADC_EVENT_END" : "UNKNOWN EVENT")
44 
45 typedef struct
46 {
47     nrfx_adc_event_handler_t event_handler;
48     nrfx_adc_channel_t     * p_head;
49     nrfx_adc_channel_t     * p_current_conv;
50     nrf_adc_value_t        * p_buffer;
51     uint16_t                 size;
52     uint16_t                 idx;
53     nrfx_drv_state_t         state;
54 } adc_cb_t;
55 
56 static adc_cb_t m_cb;
57 
nrfx_adc_init(nrfx_adc_config_t const * p_config,nrfx_adc_event_handler_t event_handler)58 nrfx_err_t nrfx_adc_init(nrfx_adc_config_t const * p_config,
59                          nrfx_adc_event_handler_t  event_handler)
60 {
61     NRFX_ASSERT(p_config);
62     nrfx_err_t err_code;
63 
64     if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
65     {
66 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
67         err_code = NRFX_ERROR_ALREADY;
68 #else
69         err_code = NRFX_ERROR_INVALID_STATE;
70 #endif
71         NRFX_LOG_WARNING("Function: %s, error code: %s.",
72                          __func__,
73                          NRFX_LOG_ERROR_STRING_GET(err_code));
74         return err_code;
75     }
76 
77     nrf_adc_event_clear(NRF_ADC, NRF_ADC_EVENT_END);
78     if (event_handler)
79     {
80         NRFX_IRQ_PRIORITY_SET(ADC_IRQn, p_config->interrupt_priority);
81         NRFX_IRQ_ENABLE(ADC_IRQn);
82     }
83     m_cb.event_handler = event_handler;
84     m_cb.state = NRFX_DRV_STATE_INITIALIZED;
85 
86     err_code = NRFX_SUCCESS;
87     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
88     return err_code;
89 }
90 
nrfx_adc_uninit(void)91 void nrfx_adc_uninit(void)
92 {
93     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
94 
95     NRFX_IRQ_DISABLE(ADC_IRQn);
96     nrf_adc_int_disable(NRF_ADC, NRF_ADC_INT_END_MASK);
97     nrf_adc_task_trigger(NRF_ADC, NRF_ADC_TASK_STOP);
98 
99     // Disable all channels. This must be done after the interrupt is disabled
100     // because adc_sample_process() dereferences this pointer when it needs to
101     // switch back to the first channel in the list (when the number of samples
102     // to read is bigger than the number of enabled channels).
103     m_cb.p_head = NULL;
104 
105     m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
106     NRFX_LOG_INFO("Uninitialized.");
107 }
108 
nrfx_adc_init_check(void)109 bool nrfx_adc_init_check(void)
110 {
111     return (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
112 }
113 
nrfx_adc_channel_enable(nrfx_adc_channel_t * const p_channel)114 void nrfx_adc_channel_enable(nrfx_adc_channel_t * const p_channel)
115 {
116     NRFX_ASSERT(!nrfx_adc_is_busy());
117 
118     p_channel->p_next = NULL;
119     if (m_cb.p_head == NULL)
120     {
121         m_cb.p_head = p_channel;
122     }
123     else
124     {
125         nrfx_adc_channel_t * p_curr_channel = m_cb.p_head;
126         while (p_curr_channel->p_next != NULL)
127         {
128             NRFX_ASSERT(p_channel != p_curr_channel);
129             p_curr_channel = p_curr_channel->p_next;
130         }
131         p_curr_channel->p_next = p_channel;
132     }
133 
134     NRFX_LOG_INFO("Enabled.");
135 }
136 
nrfx_adc_channel_disable(nrfx_adc_channel_t * const p_channel)137 void nrfx_adc_channel_disable(nrfx_adc_channel_t * const p_channel)
138 {
139     NRFX_ASSERT(m_cb.p_head);
140     NRFX_ASSERT(!nrfx_adc_is_busy());
141 
142     nrfx_adc_channel_t * p_curr_channel = m_cb.p_head;
143     nrfx_adc_channel_t * p_prev_channel = NULL;
144     while (p_curr_channel != p_channel)
145     {
146         p_prev_channel = p_curr_channel;
147         p_curr_channel = p_curr_channel->p_next;
148         NRFX_ASSERT(p_curr_channel != NULL);
149     }
150     if (p_prev_channel)
151     {
152         p_prev_channel->p_next = p_curr_channel->p_next;
153     }
154     else
155     {
156         m_cb.p_head = p_curr_channel->p_next;
157     }
158 
159     NRFX_LOG_INFO("Disabled.");
160 }
161 
nrfx_adc_all_channels_disable(void)162 void nrfx_adc_all_channels_disable(void)
163 {
164     NRFX_ASSERT(!nrfx_adc_is_busy());
165 
166     m_cb.p_head = NULL;
167 }
168 
nrfx_adc_sample(void)169 void nrfx_adc_sample(void)
170 {
171     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
172     NRFX_ASSERT(!nrf_adc_busy_check(NRF_ADC));
173     nrf_adc_task_trigger(NRF_ADC, NRF_ADC_TASK_START);
174 }
175 
nrfx_adc_sample_convert(nrfx_adc_channel_t const * p_channel,nrf_adc_value_t * p_value)176 nrfx_err_t nrfx_adc_sample_convert(nrfx_adc_channel_t const * p_channel,
177                                    nrf_adc_value_t *          p_value)
178 {
179     nrfx_err_t err_code;
180 
181     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
182     if (m_cb.state == NRFX_DRV_STATE_POWERED_ON)
183     {
184         err_code = NRFX_ERROR_BUSY;
185         NRFX_LOG_WARNING("Function: %s, error code: %s.",
186                          __func__,
187                          NRFX_LOG_ERROR_STRING_GET(err_code));
188         return err_code;
189     }
190     else
191     {
192         m_cb.state = NRFX_DRV_STATE_POWERED_ON;
193 
194         nrf_adc_init(NRF_ADC, &p_channel->config);
195         nrf_adc_enable(NRF_ADC);
196         nrf_adc_int_disable(NRF_ADC, NRF_ADC_INT_END_MASK);
197         nrf_adc_task_trigger(NRF_ADC, NRF_ADC_TASK_START);
198         if (p_value)
199         {
200             while (!nrf_adc_event_check(NRF_ADC, NRF_ADC_EVENT_END)) {}
201             nrf_adc_event_clear(NRF_ADC, NRF_ADC_EVENT_END);
202             *p_value = (nrf_adc_value_t)nrf_adc_result_get(NRF_ADC);
203             nrf_adc_disable(NRF_ADC);
204 
205             m_cb.state = NRFX_DRV_STATE_INITIALIZED;
206         }
207         else
208         {
209             NRFX_ASSERT(m_cb.event_handler);
210             m_cb.p_buffer = NULL;
211             nrf_adc_int_enable(NRF_ADC, NRF_ADC_INT_END_MASK);
212         }
213         err_code = NRFX_SUCCESS;
214         NRFX_LOG_INFO("Function: %s, error code: %s.",
215                       __func__,
216                       NRFX_LOG_ERROR_STRING_GET(err_code));
217         return err_code;
218     }
219 }
220 
adc_sample_process(void)221 static bool adc_sample_process(void)
222 {
223     nrf_adc_event_clear(NRF_ADC, NRF_ADC_EVENT_END);
224     nrf_adc_disable(NRF_ADC);
225     m_cb.p_buffer[m_cb.idx] = (nrf_adc_value_t)nrf_adc_result_get(NRF_ADC);
226     m_cb.idx++;
227     if (m_cb.idx < m_cb.size)
228     {
229         bool task_trigger = false;
230         if (m_cb.p_current_conv->p_next == NULL)
231         {
232             // Make sure the list of channels has not been somehow removed
233             // (it is when all channels are disabled).
234             NRFX_ASSERT(m_cb.p_head);
235 
236             m_cb.p_current_conv = m_cb.p_head;
237         }
238         else
239         {
240             m_cb.p_current_conv = m_cb.p_current_conv->p_next;
241             task_trigger = true;
242         }
243         nrf_adc_init(NRF_ADC, &m_cb.p_current_conv->config);
244         nrf_adc_enable(NRF_ADC);
245         if (task_trigger)
246         {
247             nrf_adc_task_trigger(NRF_ADC, NRF_ADC_TASK_START);
248         }
249         return false;
250     }
251     else
252     {
253         return true;
254     }
255 }
256 
nrfx_adc_buffer_convert(nrf_adc_value_t * buffer,uint16_t size)257 nrfx_err_t nrfx_adc_buffer_convert(nrf_adc_value_t * buffer, uint16_t size)
258 {
259     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
260     NRFX_ASSERT(buffer);
261 
262     nrfx_err_t err_code;
263 
264     NRFX_LOG_INFO("Number of samples requested to convert: %d.", size);
265 
266     if (m_cb.state == NRFX_DRV_STATE_POWERED_ON)
267     {
268         err_code = NRFX_ERROR_BUSY;
269         NRFX_LOG_WARNING("Function: %s, error code: %s.",
270                          __func__,
271                          NRFX_LOG_ERROR_STRING_GET(err_code));
272         return err_code;
273     }
274     else
275     {
276         m_cb.state          = NRFX_DRV_STATE_POWERED_ON;
277         m_cb.p_current_conv = m_cb.p_head;
278         m_cb.size           = size;
279         m_cb.idx            = 0;
280         m_cb.p_buffer       = buffer;
281         nrf_adc_init(NRF_ADC, &m_cb.p_current_conv->config);
282         nrf_adc_event_clear(NRF_ADC, NRF_ADC_EVENT_END);
283         nrf_adc_enable(NRF_ADC);
284         if (m_cb.event_handler)
285         {
286             nrf_adc_int_enable(NRF_ADC, NRF_ADC_INT_END_MASK);
287         }
288         else
289         {
290             while (1)
291             {
292                 while (!nrf_adc_event_check(NRF_ADC, NRF_ADC_EVENT_END)){}
293 
294                 if (adc_sample_process())
295                 {
296                     m_cb.state = NRFX_DRV_STATE_INITIALIZED;
297                     break;
298                 }
299             }
300         }
301         err_code = NRFX_SUCCESS;
302         NRFX_LOG_INFO("Function: %s, error code: %s.",
303                       __func__,
304                       NRFX_LOG_ERROR_STRING_GET(err_code));
305         return err_code;
306     }
307 }
308 
nrfx_adc_is_busy(void)309 bool nrfx_adc_is_busy(void)
310 {
311     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
312     return (m_cb.state == NRFX_DRV_STATE_POWERED_ON) ? true : false;
313 }
314 
nrfx_adc_irq_handler(void)315 void nrfx_adc_irq_handler(void)
316 {
317     if (m_cb.p_buffer == NULL)
318     {
319         nrf_adc_event_clear(NRF_ADC, NRF_ADC_EVENT_END);
320         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_ADC_EVENT_END));
321         nrf_adc_int_disable(NRF_ADC, NRF_ADC_INT_END_MASK);
322         nrf_adc_disable(NRF_ADC);
323         nrfx_adc_evt_t evt;
324         evt.type = NRFX_ADC_EVT_SAMPLE;
325         evt.data.sample.sample = (nrf_adc_value_t)nrf_adc_result_get(NRF_ADC);
326         NRFX_LOG_DEBUG("ADC data:");
327         NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)(&evt.data.sample.sample), sizeof(nrf_adc_value_t));
328         m_cb.state = NRFX_DRV_STATE_INITIALIZED;
329         m_cb.event_handler(&evt);
330     }
331     else if (adc_sample_process())
332     {
333         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_ADC_EVENT_END));
334         nrf_adc_int_disable(NRF_ADC, NRF_ADC_INT_END_MASK);
335         nrfx_adc_evt_t evt;
336         evt.type = NRFX_ADC_EVT_DONE;
337         evt.data.done.p_buffer = m_cb.p_buffer;
338         evt.data.done.size     = m_cb.size;
339         m_cb.state = NRFX_DRV_STATE_INITIALIZED;
340         NRFX_LOG_DEBUG("ADC data:");
341         NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)m_cb.p_buffer, m_cb.size * sizeof(nrf_adc_value_t));
342         m_cb.event_handler(&evt);
343     }
344 }
345 
346 #endif // NRFX_CHECK(NRFX_ADC_ENABLED)
347