1 /*
2 * Copyright (c) 2015 - 2023, 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 #include <nrfx.h>
34
35 #if NRFX_CHECK(NRFX_SAADC_ENABLED)
36 #include <nrfx_saadc.h>
37
38 #define NRFX_LOG_MODULE SAADC
39 #include <nrfx_log.h>
40
41 #if defined(NRF52_SERIES) && !defined(USE_WORKAROUND_FOR_ANOMALY_212)
42 // ANOMALY 212 - SAADC events are missing when switching from single channel
43 // to multi channel configuration with burst enabled.
44 #define USE_WORKAROUND_FOR_ANOMALY_212 1
45 #endif
46
47 #if defined(NRF53_SERIES) || defined(NRF91_SERIES)
48 // Make sure that SAADC is stopped before channel configuration.
49 #define STOP_SAADC_ON_CHANNEL_CONFIG 1
50 #endif
51
52 /** @brief Bitmask of all available SAADC channels. */
53 #define SAADC_ALL_CHANNELS_MASK ((1UL << SAADC_CH_NUM) - 1UL)
54
55 /** @brief SAADC driver states.*/
56 typedef enum
57 {
58 NRF_SAADC_STATE_UNINITIALIZED = 0,
59 NRF_SAADC_STATE_IDLE,
60 NRF_SAADC_STATE_SIMPLE_MODE,
61 NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE,
62 NRF_SAADC_STATE_ADV_MODE,
63 NRF_SAADC_STATE_ADV_MODE_SAMPLE,
64 NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED,
65 NRF_SAADC_STATE_CALIBRATION
66 } nrf_saadc_state_t;
67
68 /** @brief SAADC control block.*/
69 typedef struct
70 {
71 nrfx_saadc_event_handler_t event_handler; ///< Event handler function pointer.
72 nrfx_saadc_event_handler_t calib_event_handler; ///< Event handler function pointer for calibration event.
73 nrfy_saadc_buffer_t buffer_primary; ///< Primary buffer description structure.
74 nrfy_saadc_buffer_t buffer_secondary; ///< Secondary buffer description structure.
75 uint16_t calib_samples[2]; ///< Scratch buffer for post-calibration samples.
76 uint16_t samples_converted; ///< Number of samples present in result buffer when in the blocking mode.
77 nrfy_saadc_channel_input_t channels_input[SAADC_CH_NUM]; ///< Array holding input of each of the channels.
78 nrf_saadc_state_t saadc_state; ///< State of the SAADC driver.
79 nrf_saadc_state_t saadc_state_prev; ///< Previous state of the SAADC driver.
80 uint8_t channels_configured; ///< Bitmask of the configured channels.
81 uint8_t channels_activated; ///< Bitmask of the activated channels.
82 uint8_t channels_activated_count; ///< Number of the activated channels.
83 uint8_t limits_low_activated; ///< Bitmask of the activated low limits.
84 uint8_t limits_high_activated; ///< Bitmask of the activated high limits.
85 bool start_on_end; ///< Flag indicating if the START task is to be triggered on the END event.
86 bool oversampling_without_burst; ///< Flag indicating whether oversampling without burst is configured.
87 } nrfx_saadc_cb_t;
88
89 static nrfx_saadc_cb_t m_cb;
90
91 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_212)
saadc_anomaly_212_workaround_apply(void)92 static void saadc_anomaly_212_workaround_apply(void)
93 {
94 uint32_t c[SAADC_CH_NUM];
95 uint32_t l[SAADC_CH_NUM];
96
97 for (uint32_t i = 0; i < SAADC_CH_NUM; i++)
98 {
99 c[i] = NRF_SAADC->CH[i].CONFIG;
100 l[i] = NRF_SAADC->CH[i].LIMIT;
101 }
102 nrf_saadc_resolution_t resolution = nrfy_saadc_resolution_get(NRF_SAADC);
103 uint32_t u640 = *(volatile uint32_t *)0x40007640;
104 uint32_t u644 = *(volatile uint32_t *)0x40007644;
105 uint32_t u648 = *(volatile uint32_t *)0x40007648;
106
107 *(volatile uint32_t *)0x40007FFC = 0;
108 *(volatile uint32_t *)0x40007FFC = 1;
109
110 for (uint32_t i = 0; i < SAADC_CH_NUM; i++)
111 {
112 NRF_SAADC->CH[i].CONFIG = c[i];
113 NRF_SAADC->CH[i].LIMIT = l[i];
114 }
115 *(volatile uint32_t *)0x40007640 = u640;
116 *(volatile uint32_t *)0x40007644 = u644;
117 *(volatile uint32_t *)0x40007648 = u648;
118 nrfy_saadc_resolution_set(NRF_SAADC, resolution);
119 }
120 #endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_212)
121
saadc_channel_count_get(uint32_t ch_to_activate_mask,uint8_t * p_active_ch_count)122 static nrfx_err_t saadc_channel_count_get(uint32_t ch_to_activate_mask,
123 uint8_t * p_active_ch_count)
124 {
125 NRFX_ASSERT(ch_to_activate_mask);
126 NRFX_ASSERT(ch_to_activate_mask < (1 << SAADC_CH_NUM));
127
128 uint8_t active_ch_count = 0;
129 for (uint32_t ch_mask = 1; ch_mask < (1 << SAADC_CH_NUM); ch_mask <<= 1)
130 {
131 if (ch_to_activate_mask & ch_mask)
132 {
133 // Check if requested channels are configured.
134 if (!(m_cb.channels_configured & ch_mask))
135 {
136 return NRFX_ERROR_INVALID_PARAM;
137 }
138 active_ch_count++;
139 }
140 }
141
142 *p_active_ch_count = active_ch_count;
143 return NRFX_SUCCESS;
144 }
145
saadc_channel_config(nrfx_saadc_channel_t const * p_channel)146 static void saadc_channel_config(nrfx_saadc_channel_t const * p_channel)
147 {
148 NRFX_ASSERT(p_channel->pin_p != NRF_SAADC_INPUT_DISABLED);
149
150 uint8_t channel_index = p_channel->channel_index;
151 nrfy_saadc_channel_configure(NRF_SAADC, channel_index, &p_channel->channel_config, NULL);
152 m_cb.channels_input[channel_index].input_p = p_channel->pin_p;
153 m_cb.channels_input[channel_index].input_n = p_channel->pin_n;
154 m_cb.channels_configured |= (uint8_t)(1U << channel_index);
155 }
156
saadc_channels_deconfig(uint32_t channel_mask)157 static void saadc_channels_deconfig(uint32_t channel_mask)
158 {
159 while (channel_mask)
160 {
161 uint8_t channel = (uint8_t)NRF_CTZ(channel_mask);
162
163 channel_mask &= ~(1UL << channel);
164 m_cb.channels_configured &= (uint8_t)~(1UL << channel);
165
166 m_cb.channels_input[channel].input_p = NRF_SAADC_INPUT_DISABLED;
167 m_cb.channels_input[channel].input_n = NRF_SAADC_INPUT_DISABLED;
168 }
169 }
170
saadc_channels_disable(uint32_t channel_mask)171 static void saadc_channels_disable(uint32_t channel_mask)
172 {
173 while (channel_mask)
174 {
175 uint8_t channel = (uint8_t)NRF_CTZ(channel_mask);
176 channel_mask &= ~(1UL << channel);
177 nrfy_saadc_channel_input_set(NRF_SAADC, channel,
178 NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
179 }
180 }
181
saadc_busy_check(void)182 static bool saadc_busy_check(void)
183 {
184 if ((m_cb.saadc_state == NRF_SAADC_STATE_IDLE) ||
185 (m_cb.saadc_state == NRF_SAADC_STATE_ADV_MODE) ||
186 (m_cb.saadc_state == NRF_SAADC_STATE_SIMPLE_MODE))
187 {
188 return false;
189 }
190 else
191 {
192 return true;
193 }
194 }
195
saadc_generic_mode_set(uint32_t ch_to_activate_mask,nrf_saadc_resolution_t resolution,nrf_saadc_oversample_t oversampling,nrf_saadc_burst_t burst,nrfx_saadc_event_handler_t event_handler)196 static void saadc_generic_mode_set(uint32_t ch_to_activate_mask,
197 nrf_saadc_resolution_t resolution,
198 nrf_saadc_oversample_t oversampling,
199 nrf_saadc_burst_t burst,
200 nrfx_saadc_event_handler_t event_handler)
201 {
202 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_212)
203 saadc_anomaly_212_workaround_apply();
204 #endif
205
206 #if NRFX_CHECK(STOP_SAADC_ON_CHANNEL_CONFIG)
207 nrfy_saadc_int_disable(NRF_SAADC, NRF_SAADC_INT_STOPPED);
208 nrfy_saadc_stop(NRF_SAADC, true);
209 #endif
210
211 m_cb.limits_low_activated = 0;
212 m_cb.limits_high_activated = 0;
213
214 m_cb.buffer_primary.p_buffer = NULL;
215 m_cb.buffer_secondary.p_buffer = NULL;
216 m_cb.event_handler = event_handler;
217 m_cb.channels_activated = (uint8_t)ch_to_activate_mask;
218 m_cb.samples_converted = 0;
219
220 nrfy_saadc_config_t config = {.resolution = resolution, .oversampling = oversampling};
221 nrfy_saadc_periph_configure(NRF_SAADC, &config);
222 if (event_handler)
223 {
224 nrfy_saadc_int_set(NRF_SAADC,
225 NRF_SAADC_INT_STARTED |
226 NRF_SAADC_INT_STOPPED |
227 NRF_SAADC_INT_END);
228 }
229 else
230 {
231 nrfy_saadc_int_set(NRF_SAADC, 0);
232 }
233
234 for (uint32_t ch_pos = 0; ch_pos < SAADC_CH_NUM; ch_pos++)
235 {
236 nrf_saadc_burst_t burst_to_set = NRF_SAADC_BURST_DISABLED;
237 nrfy_saadc_channel_input_t input = {.input_p = NRF_SAADC_INPUT_DISABLED,
238 .input_n = NRF_SAADC_INPUT_DISABLED};
239 if (ch_to_activate_mask & (1 << ch_pos))
240 {
241 input = m_cb.channels_input[ch_pos];
242 burst_to_set = burst;
243 }
244 nrfy_saadc_burst_set(NRF_SAADC, (uint8_t)ch_pos, burst_to_set);
245 nrfy_saadc_channel_configure(NRF_SAADC, (uint8_t)ch_pos, NULL, &input);
246 }
247 }
248
nrfx_saadc_init(uint8_t interrupt_priority)249 nrfx_err_t nrfx_saadc_init(uint8_t interrupt_priority)
250 {
251 nrfx_err_t err_code;
252 if (m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED)
253 {
254 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
255 err_code = NRFX_ERROR_ALREADY;
256 #else
257 err_code = NRFX_ERROR_INVALID_STATE;
258 #endif
259 NRFX_LOG_WARNING("Function: %s, error code: %s.",
260 __func__,
261 NRFX_LOG_ERROR_STRING_GET(err_code));
262 return err_code;
263 }
264 m_cb.saadc_state = NRF_SAADC_STATE_IDLE;
265
266 saadc_channels_deconfig(SAADC_ALL_CHANNELS_MASK);
267 uint32_t mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STARTED) |
268 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STOPPED) |
269 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_END) |
270 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_CALIBRATEDONE);
271
272 nrfy_saadc_int_init(NRF_SAADC, mask, interrupt_priority, false);
273 m_cb.event_handler = NULL;
274
275 err_code = NRFX_SUCCESS;
276 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
277
278 return err_code;
279 }
280
nrfx_saadc_uninit(void)281 void nrfx_saadc_uninit(void)
282 {
283 nrfx_saadc_abort();
284
285 nrfy_saadc_int_uninit(NRF_SAADC);
286 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_DONE);
287 nrfy_saadc_disable(NRF_SAADC);
288 saadc_channels_disable(m_cb.channels_configured | m_cb.channels_activated);
289 m_cb.saadc_state = NRF_SAADC_STATE_UNINITIALIZED;
290 }
291
nrfx_saadc_init_check(void)292 bool nrfx_saadc_init_check(void)
293 {
294 return (m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
295 }
296
nrfx_saadc_channels_config(nrfx_saadc_channel_t const * p_channels,uint32_t channel_count)297 nrfx_err_t nrfx_saadc_channels_config(nrfx_saadc_channel_t const * p_channels,
298 uint32_t channel_count)
299 {
300 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
301 NRFX_ASSERT(p_channels);
302 NRFX_ASSERT(channel_count <= SAADC_CH_NUM);
303
304 if (saadc_busy_check())
305 {
306 return NRFX_ERROR_BUSY;
307 }
308
309 saadc_channels_deconfig(SAADC_ALL_CHANNELS_MASK);
310 for (uint8_t i = 0; i < channel_count; i++)
311 {
312 if (m_cb.channels_configured & (1 << p_channels[i].channel_index))
313 {
314 // This channel is already configured!
315 return NRFX_ERROR_INVALID_PARAM;
316 }
317
318 saadc_channel_config(&p_channels[i]);
319 }
320
321 return NRFX_SUCCESS;
322 }
323
nrfx_saadc_channel_config(nrfx_saadc_channel_t const * p_channel)324 nrfx_err_t nrfx_saadc_channel_config(nrfx_saadc_channel_t const * p_channel)
325 {
326 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
327 NRFX_ASSERT(p_channel);
328
329 if (saadc_busy_check())
330 {
331 return NRFX_ERROR_BUSY;
332 }
333
334 saadc_channel_config(p_channel);
335
336 return NRFX_SUCCESS;
337 }
338
nrfx_saadc_channels_configured_get(void)339 uint32_t nrfx_saadc_channels_configured_get(void)
340 {
341 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
342
343 return m_cb.channels_configured;
344 }
345
nrfx_saadc_channels_deconfig(uint32_t channel_mask)346 nrfx_err_t nrfx_saadc_channels_deconfig(uint32_t channel_mask)
347 {
348 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
349
350 if (saadc_busy_check())
351 {
352 return NRFX_ERROR_BUSY;
353 }
354
355 saadc_channels_deconfig(channel_mask);
356
357 return NRFX_SUCCESS;
358 }
359
nrfx_saadc_simple_mode_set(uint32_t channel_mask,nrf_saadc_resolution_t resolution,nrf_saadc_oversample_t oversampling,nrfx_saadc_event_handler_t event_handler)360 nrfx_err_t nrfx_saadc_simple_mode_set(uint32_t channel_mask,
361 nrf_saadc_resolution_t resolution,
362 nrf_saadc_oversample_t oversampling,
363 nrfx_saadc_event_handler_t event_handler)
364 {
365 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
366
367 if (saadc_busy_check())
368 {
369 return NRFX_ERROR_BUSY;
370 }
371
372 uint8_t active_ch_count;
373 nrfx_err_t err = saadc_channel_count_get(channel_mask, &active_ch_count);
374 if (err != NRFX_SUCCESS)
375 {
376 return err;
377 }
378
379 nrf_saadc_burst_t burst;
380 if (oversampling == NRF_SAADC_OVERSAMPLE_DISABLED)
381 {
382 burst = NRF_SAADC_BURST_DISABLED;
383 }
384 else
385 {
386 // Burst is implicitly enabled if oversampling is enabled.
387 burst = NRF_SAADC_BURST_ENABLED;
388 }
389
390 saadc_generic_mode_set(channel_mask,
391 resolution,
392 oversampling,
393 burst,
394 event_handler);
395
396 m_cb.channels_activated_count = active_ch_count;
397 m_cb.saadc_state = NRF_SAADC_STATE_SIMPLE_MODE;
398
399 return NRFX_SUCCESS;
400 }
401
nrfx_saadc_advanced_mode_set(uint32_t channel_mask,nrf_saadc_resolution_t resolution,nrfx_saadc_adv_config_t const * p_config,nrfx_saadc_event_handler_t event_handler)402 nrfx_err_t nrfx_saadc_advanced_mode_set(uint32_t channel_mask,
403 nrf_saadc_resolution_t resolution,
404 nrfx_saadc_adv_config_t const * p_config,
405 nrfx_saadc_event_handler_t event_handler)
406 {
407 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
408 NRFX_ASSERT(p_config);
409
410 if (saadc_busy_check())
411 {
412 return NRFX_ERROR_BUSY;
413 }
414
415 uint8_t active_ch_count;
416 nrfx_err_t err = saadc_channel_count_get(channel_mask, &active_ch_count);
417 if (err != NRFX_SUCCESS)
418 {
419 return err;
420 }
421
422 if ((p_config->internal_timer_cc) && ((active_ch_count > 1) || (!event_handler)))
423 {
424 return NRFX_ERROR_NOT_SUPPORTED;
425 }
426
427 bool oversampling_without_burst = false;
428 if ((p_config->oversampling != NRF_SAADC_OVERSAMPLE_DISABLED) &&
429 (p_config->burst == NRF_SAADC_BURST_DISABLED))
430 {
431 if (active_ch_count > 1)
432 {
433 // Oversampling without burst is possible only on single channel.
434 return NRFX_ERROR_NOT_SUPPORTED;
435 }
436 else
437 {
438 oversampling_without_burst = true;
439 }
440 }
441
442 saadc_generic_mode_set(channel_mask,
443 resolution,
444 p_config->oversampling,
445 p_config->burst,
446 event_handler);
447
448 if (p_config->internal_timer_cc)
449 {
450 nrfy_saadc_continuous_mode_enable(NRF_SAADC, p_config->internal_timer_cc);
451 }
452 else
453 {
454 nrfy_saadc_continuous_mode_disable(NRF_SAADC);
455 }
456
457 m_cb.channels_activated_count = active_ch_count;
458 m_cb.start_on_end = p_config->start_on_end;
459 m_cb.oversampling_without_burst = oversampling_without_burst;
460
461 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE;
462
463 return NRFX_SUCCESS;
464 }
465
nrfx_saadc_buffer_set(nrf_saadc_value_t * p_buffer,uint16_t size)466 nrfx_err_t nrfx_saadc_buffer_set(nrf_saadc_value_t * p_buffer, uint16_t size)
467 {
468 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
469
470 if (m_cb.buffer_secondary.p_buffer)
471 {
472 return NRFX_ERROR_ALREADY;
473 }
474
475 if (!nrfx_is_in_ram(p_buffer))
476 {
477 return NRFX_ERROR_INVALID_ADDR;
478 }
479
480 if ((size % m_cb.channels_activated_count != 0) ||
481 (size > SAADC_RESULT_MAXCNT_MAXCNT_Msk) ||
482 (!size))
483 {
484 return NRFX_ERROR_INVALID_LENGTH;
485 }
486
487 nrfy_saadc_buffer_t buffer = {.p_buffer = p_buffer, .length = size};
488 switch (m_cb.saadc_state)
489 {
490 case NRF_SAADC_STATE_SIMPLE_MODE:
491 if (m_cb.channels_activated_count != size)
492 {
493 return NRFX_ERROR_INVALID_LENGTH;
494 }
495 m_cb.buffer_primary = buffer;
496 break;
497
498 case NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED:
499 nrfy_saadc_buffer_set(NRF_SAADC, &buffer, false, false);
500 /* FALLTHROUGH */
501
502 case NRF_SAADC_STATE_ADV_MODE:
503 /* FALLTHROUGH */
504
505 case NRF_SAADC_STATE_ADV_MODE_SAMPLE:
506 if (m_cb.buffer_primary.p_buffer)
507 {
508 m_cb.buffer_secondary = buffer;
509 }
510 else
511 {
512 m_cb.buffer_primary = buffer;
513 }
514 break;
515
516 default:
517 return NRFX_ERROR_INVALID_STATE;
518 }
519
520 return NRFX_SUCCESS;
521 }
522
nrfx_saadc_mode_trigger(void)523 nrfx_err_t nrfx_saadc_mode_trigger(void)
524 {
525 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
526 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_IDLE);
527
528 if (!m_cb.buffer_primary.p_buffer)
529 {
530 return NRFX_ERROR_NO_MEM;
531 }
532
533 nrfx_err_t result = NRFX_SUCCESS;
534 switch (m_cb.saadc_state)
535 {
536 case NRF_SAADC_STATE_SIMPLE_MODE:
537 {
538 nrfy_saadc_enable(NRF_SAADC);
539 // When in simple blocking or non-blocking mode, buffer size is equal to activated channel count.
540 // Single SAMPLE task is enough to obtain one sample on each activated channel.
541 // This will result in buffer being filled with samples and therefore END event will appear.
542
543 if (m_cb.event_handler)
544 {
545 m_cb.saadc_state = NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE;
546 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_primary, true, false);
547 }
548 else
549 {
550 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_primary, true, true);
551 nrfy_saadc_sample_start(NRF_SAADC, &m_cb.buffer_primary);
552 nrfy_saadc_disable(NRF_SAADC);
553 }
554 break;
555 }
556
557 case NRF_SAADC_STATE_ADV_MODE:
558 {
559 nrfy_saadc_enable(NRF_SAADC);
560 if (m_cb.event_handler)
561 {
562 // When in advanced non-blocking mode, latch whole buffer in EasyDMA.
563 // END event will arrive when whole buffer is filled with samples.
564
565 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE_SAMPLE;
566 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_primary, true, false);
567 break;
568 }
569 // When in advanced blocking mode, latch single chunk of buffer in EasyDMA.
570 // Each chunk consists of single sample from each activated channels.
571 // END event will arrive when single chunk is filled with samples.
572 nrfy_saadc_buffer_t chunk = { .length = m_cb.channels_activated_count};
573
574 #if (NRF_SAADC_8BIT_SAMPLE_WIDTH == 8)
575 if (nrfy_saadc_resolution_get(NRF_SAADC) == NRF_SAADC_RESOLUTION_8BIT)
576 {
577 chunk.p_buffer = (nrf_saadc_value_t *)
578 &((uint8_t *)m_cb.buffer_primary.p_buffer)[m_cb.samples_converted];
579 }
580 else
581 #endif
582 {
583 chunk.p_buffer = (nrf_saadc_value_t *)
584 &((uint16_t *)m_cb.buffer_primary.p_buffer)[m_cb.samples_converted];
585 }
586 nrfy_saadc_buffer_set(NRF_SAADC, &chunk, true, true);
587 if (m_cb.oversampling_without_burst)
588 {
589 // Oversampling without burst is possible only on single channel.
590 // In this configuration more than one SAMPLE task is needed to obtain single sample.
591 uint32_t samples_to_take =
592 nrfy_saadc_oversample_sample_count_get(nrfy_saadc_oversample_get(NRF_SAADC));
593
594 for (uint32_t sample_idx = 0; sample_idx < samples_to_take - 1; sample_idx++)
595 {
596 nrfy_saadc_sample_start(NRF_SAADC, NULL);
597 uint32_t evt_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_DONE);
598 while (!nrfy_saadc_events_process(NRF_SAADC, evt_mask, NULL))
599 {}
600 }
601 }
602 // Single SAMPLE task is enough to obtain one sample on each activated channel.
603 // This will result in chunk being filled with samples and therefore END event will appear.
604 nrfy_saadc_sample_start(NRF_SAADC, &chunk);
605
606 m_cb.samples_converted += m_cb.channels_activated_count;
607 if (m_cb.samples_converted < m_cb.buffer_primary.length)
608 {
609 result = NRFX_ERROR_BUSY;
610 }
611 else
612 {
613 m_cb.samples_converted = 0;
614 m_cb.buffer_primary = m_cb.buffer_secondary;
615 m_cb.buffer_secondary.p_buffer = NULL;
616 }
617 nrfy_saadc_disable(NRF_SAADC);
618 break;
619 }
620
621 default:
622 result = NRFX_ERROR_INVALID_STATE;
623 break;
624 }
625
626 return result;
627 }
628
nrfx_saadc_abort(void)629 void nrfx_saadc_abort(void)
630 {
631 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
632
633 if (m_cb.saadc_state == NRF_SAADC_STATE_CALIBRATION ? m_cb.calib_event_handler :
634 m_cb.event_handler)
635 {
636 nrfy_saadc_abort(NRF_SAADC, NULL);
637 }
638 else
639 {
640 m_cb.buffer_primary.p_buffer = NULL;
641 m_cb.buffer_secondary.p_buffer = NULL;
642 m_cb.samples_converted = 0;
643 }
644 }
645
nrfx_saadc_limits_set(uint8_t channel,int16_t limit_low,int16_t limit_high)646 nrfx_err_t nrfx_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high)
647 {
648 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
649 NRFX_ASSERT(limit_high >= limit_low);
650
651 if (!m_cb.event_handler)
652 {
653 return NRFX_ERROR_FORBIDDEN;
654 }
655
656 if ((m_cb.saadc_state == NRF_SAADC_STATE_IDLE) ||
657 (m_cb.saadc_state == NRF_SAADC_STATE_CALIBRATION))
658 {
659 return NRFX_ERROR_INVALID_STATE;
660 }
661
662 if (!(m_cb.channels_activated & (1 << channel)))
663 {
664 return NRFX_ERROR_INVALID_PARAM;
665 }
666
667 nrfy_saadc_channel_limits_set(NRF_SAADC, channel, limit_low, limit_high);
668
669 uint32_t int_mask = nrfy_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_LOW);
670 if (limit_low == INT16_MIN)
671 {
672 m_cb.limits_low_activated &= (uint8_t)~(1UL << channel);
673 nrfy_saadc_int_disable(NRF_SAADC, int_mask);
674 }
675 else
676 {
677 m_cb.limits_low_activated |= (uint8_t)(1UL << channel);
678 nrfy_saadc_int_enable(NRF_SAADC, int_mask);
679 }
680
681 int_mask = nrfy_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_HIGH);
682 if (limit_high == INT16_MAX)
683 {
684 m_cb.limits_high_activated &= (uint8_t)~(1UL << channel);
685 nrfy_saadc_int_disable(NRF_SAADC, int_mask);
686 }
687 else
688 {
689 m_cb.limits_high_activated |= (uint8_t)(1UL << channel);
690 nrfy_saadc_int_enable(NRF_SAADC, int_mask);
691 }
692
693 return NRFX_SUCCESS;
694 }
695
nrfx_saadc_offset_calibrate(nrfx_saadc_event_handler_t calib_event_handler)696 nrfx_err_t nrfx_saadc_offset_calibrate(nrfx_saadc_event_handler_t calib_event_handler)
697 {
698 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
699
700 if (saadc_busy_check())
701 {
702 return NRFX_ERROR_BUSY;
703 }
704
705 m_cb.saadc_state_prev = m_cb.saadc_state;
706 m_cb.saadc_state = NRF_SAADC_STATE_CALIBRATION;
707 m_cb.calib_event_handler = calib_event_handler;
708
709 nrfy_saadc_enable(NRF_SAADC);
710
711 uint32_t int_mask = nrfy_saadc_int_enable_check(NRF_SAADC, ~0UL);
712 nrfy_saadc_int_set(NRF_SAADC, 0);
713 if (calib_event_handler)
714 {
715 nrfy_saadc_calibrate(NRF_SAADC, false);
716 // Make sure that LIMIT feature is disabled before offset calibration.
717 int_mask &= ~(uint32_t)(NRF_SAADC_INT_CH0LIMITL | NRF_SAADC_INT_CH0LIMITH);
718 nrfy_saadc_int_set(NRF_SAADC, int_mask | NRF_SAADC_INT_STARTED | NRF_SAADC_INT_STOPPED |
719 NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE);
720 }
721 else
722 {
723 nrfy_saadc_calibrate(NRF_SAADC, true);
724
725 nrfy_saadc_buffer_t calib_buffer = {.p_buffer = m_cb.calib_samples,
726 .length = NRFX_ARRAY_SIZE(m_cb.calib_samples)};
727 nrfy_saadc_buffer_set(NRF_SAADC, &calib_buffer, true, true);
728
729 nrfy_saadc_stop(NRF_SAADC, true);
730 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END);
731 nrfy_saadc_disable(NRF_SAADC);
732 m_cb.saadc_state = m_cb.saadc_state_prev;
733
734 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CH0_LIMITL);
735 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CH0_LIMITH);
736 nrfy_saadc_int_set(NRF_SAADC, int_mask);
737 }
738
739 return NRFX_SUCCESS;
740 }
741
saadc_pre_calibration_state_restore(void)742 static void saadc_pre_calibration_state_restore(void)
743 {
744 nrfy_saadc_disable(NRF_SAADC);
745 uint32_t int_mask = nrfy_saadc_int_enable_check(NRF_SAADC, ~0UL) &
746 (uint32_t)(~(NRF_SAADC_INT_STARTED | NRF_SAADC_INT_STOPPED |
747 NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE));
748 m_cb.saadc_state = m_cb.saadc_state_prev;
749 if (m_cb.event_handler)
750 {
751 // Restore interrupts that are used in sampling if user provided event handler
752 // during mode configuration.
753 int_mask |= NRF_SAADC_INT_STARTED | NRF_SAADC_INT_STOPPED | NRF_SAADC_INT_END;
754 }
755 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CH0_LIMITL);
756 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CH0_LIMITH);
757 if (m_cb.limits_low_activated & 0x1UL)
758 {
759 int_mask |= NRF_SAADC_INT_CH0LIMITL;
760 }
761 if (m_cb.limits_high_activated & 0x1UL)
762 {
763 int_mask |= NRF_SAADC_INT_CH0LIMITH;
764 }
765 nrfy_saadc_int_set(NRF_SAADC, int_mask);
766 }
767
saadc_event_started_handle(void)768 static void saadc_event_started_handle(void)
769 {
770 nrfx_saadc_evt_t evt_data;
771
772 switch (m_cb.saadc_state)
773 {
774 case NRF_SAADC_STATE_ADV_MODE_SAMPLE:
775 evt_data.type = NRFX_SAADC_EVT_READY;
776 m_cb.event_handler(&evt_data);
777
778 if (nrfy_saadc_continuous_mode_enable_check(NRF_SAADC))
779 {
780 // Trigger internal timer
781 nrfy_saadc_sample_start(NRF_SAADC, NULL);
782 }
783
784 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED;
785 if (m_cb.buffer_secondary.p_buffer)
786 {
787 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_secondary, false, false);
788 }
789 /* FALLTHROUGH */
790
791 case NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED:
792 if (!m_cb.buffer_secondary.p_buffer)
793 {
794 // Send next buffer request only if it was not provided earlier,
795 // before conversion start or outside of user's callback context.
796 evt_data.type = NRFX_SAADC_EVT_BUF_REQ;
797 m_cb.event_handler(&evt_data);
798 }
799 break;
800
801 case NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE:
802 nrfy_saadc_sample_start(NRF_SAADC, NULL);
803 break;
804
805 case NRF_SAADC_STATE_CALIBRATION:
806 // Stop the SAADC immediately after the temporary buffer is latched to drop spurious samples.
807 // This will cause STOPPED and END events to arrive.
808 nrfy_saadc_stop(NRF_SAADC, false);
809 break;
810
811 default:
812 break;
813 }
814 }
815
saadc_event_end_handle(void)816 static void saadc_event_end_handle(void)
817 {
818 nrfx_saadc_evt_t evt_data;
819 evt_data.type = NRFX_SAADC_EVT_DONE;
820 evt_data.data.done.p_buffer = m_cb.buffer_primary.p_buffer;
821 evt_data.data.done.size = (uint16_t)m_cb.buffer_primary.length;
822
823 switch (m_cb.saadc_state)
824 {
825 case NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE:
826 nrfy_saadc_disable(NRF_SAADC);
827 m_cb.saadc_state = NRF_SAADC_STATE_SIMPLE_MODE;
828 /* In the simple, non-blocking mode the event handler must be
829 * called after the internal driver state is updated. This will
830 * allow starting a new conversion from the event handler context.
831 */
832 m_cb.event_handler(&evt_data);
833 break;
834
835 case NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED:
836 if (m_cb.start_on_end && m_cb.buffer_secondary.p_buffer)
837 {
838 nrfy_saadc_buffer_latch(NRF_SAADC, false);
839 }
840 m_cb.event_handler(&evt_data);
841 m_cb.buffer_primary = m_cb.buffer_secondary;
842 m_cb.buffer_secondary.p_buffer = NULL;
843 if (!m_cb.buffer_primary.p_buffer)
844 {
845 nrfy_saadc_disable(NRF_SAADC);
846 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE;
847 evt_data.type = NRFX_SAADC_EVT_FINISHED;
848 m_cb.event_handler(&evt_data);
849 }
850 break;
851
852 case NRF_SAADC_STATE_CALIBRATION:
853 // Spurious samples were successfully dropped and they won't affect next conversion.
854 saadc_pre_calibration_state_restore();
855 evt_data.type = NRFX_SAADC_EVT_CALIBRATEDONE;
856 m_cb.calib_event_handler(&evt_data);
857 break;
858
859 default:
860 break;
861 }
862 }
863
saadc_event_limits_handle(void)864 static void saadc_event_limits_handle(void)
865 {
866 uint32_t limits_activated = nrfy_saadc_int_enable_check(NRF_SAADC,
867 NRF_SAADC_ALL_CHANNELS_LIMITS_INT_MASK);
868 uint32_t limits_triggered = nrfy_saadc_events_process(NRF_SAADC, limits_activated, NULL) >>
869 NRF_SAADC_LIMITS_INT_OFFSET;
870
871 while (limits_triggered)
872 {
873 uint8_t limit = (uint8_t)NRF_CTZ((uint32_t)limits_triggered);
874 limits_triggered &= ~(1UL << limit);
875
876 // There are two limits per channel.
877 uint8_t channel = limit / 2;
878
879 // Limits are organised into single pair (high limit and low limit) per channel.
880 // Do not assume whether high limit or low limit is first in the bitmask.
881 nrf_saadc_limit_t limit_type =
882 ((limit & 0x1) == (NRFY_EVENT_TO_INT_BITPOS(NRF_SAADC_EVENT_CH0_LIMITH) & 0x1)) ?
883 NRF_SAADC_LIMIT_HIGH : NRF_SAADC_LIMIT_LOW;
884
885 nrfx_saadc_evt_t evt_data;
886 evt_data.type = NRFX_SAADC_EVT_LIMIT;
887 evt_data.data.limit.channel = channel;
888 evt_data.data.limit.limit_type = limit_type;
889 m_cb.event_handler(&evt_data);
890 }
891 }
892
nrfx_saadc_irq_handler(void)893 void nrfx_saadc_irq_handler(void)
894 {
895 uint32_t evt_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STARTED) |
896 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STOPPED) |
897 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_END) |
898 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_CALIBRATEDONE);
899 evt_mask = nrfy_saadc_events_process(NRF_SAADC, evt_mask, &m_cb.buffer_primary);
900
901 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_CALIBRATEDONE))
902 {
903 nrfy_saadc_int_disable(NRF_SAADC, NRF_SAADC_INT_CALIBRATEDONE);
904 // Latch the temporary buffer to intercept any spurious samples that may appear after calibration.
905 nrfy_saadc_buffer_t calib_buffer = {.p_buffer = m_cb.calib_samples,
906 .length = NRFX_ARRAY_SIZE(m_cb.calib_samples)};
907 nrfy_saadc_buffer_set(NRF_SAADC, &calib_buffer, true, false);
908 }
909
910 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STOPPED))
911 {
912 if (m_cb.saadc_state != NRF_SAADC_STATE_CALIBRATION)
913 {
914 // If there was ongoing conversion the STOP task also triggers the END event
915 m_cb.buffer_primary.length = nrfy_saadc_amount_get(NRF_SAADC);
916 m_cb.buffer_secondary.p_buffer = NULL;
917 }
918
919 if (nrfy_saadc_int_enable_check(NRF_SAADC, NRF_SAADC_INT_CALIBRATEDONE))
920 {
921 // If STOP event arrived before CALIBRATEDONE then the calibration was aborted
922 // and END event will not appear.
923 // Calibration procedure was not completed and user handler will not be called.
924 saadc_pre_calibration_state_restore();
925 }
926 /* fall-through to the END event handler */
927 }
928
929 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_END))
930 {
931 saadc_event_end_handle();
932 }
933
934 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STARTED))
935 {
936 saadc_event_started_handle();
937 }
938
939 if (m_cb.saadc_state != NRF_SAADC_STATE_CALIBRATION)
940 {
941 saadc_event_limits_handle();
942 }
943 }
944
945 #endif // NRFX_CHECK(NRFX_SAADC_ENABLED)
946