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