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 nrf_saadc_value_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 |= 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 = NRF_CTZ(channel_mask);
162
163 channel_mask &= ~(1 << channel);
164 m_cb.channels_configured &= ~(1 << 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 = NRF_CTZ(channel_mask);
176 channel_mask &= ~(1 << 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 = 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, ch_pos, burst_to_set);
245 nrfy_saadc_channel_configure(NRF_SAADC, 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 err_code = NRFX_ERROR_INVALID_STATE;
255 NRFX_LOG_WARNING("Function: %s, error code: %s.",
256 __func__,
257 NRFX_LOG_ERROR_STRING_GET(err_code));
258 return err_code;
259 }
260 m_cb.saadc_state = NRF_SAADC_STATE_IDLE;
261
262 saadc_channels_deconfig(SAADC_ALL_CHANNELS_MASK);
263 uint32_t mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STARTED) |
264 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STOPPED) |
265 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_END) |
266 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_CALIBRATEDONE);
267
268 nrfy_saadc_int_init(NRF_SAADC, mask, interrupt_priority, false);
269 m_cb.event_handler = NULL;
270
271 err_code = NRFX_SUCCESS;
272 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
273
274 return err_code;
275 }
276
nrfx_saadc_uninit(void)277 void nrfx_saadc_uninit(void)
278 {
279 nrfx_saadc_abort();
280
281 nrfy_saadc_int_uninit(NRF_SAADC);
282 nrfy_saadc_disable(NRF_SAADC);
283 saadc_channels_disable(m_cb.channels_configured | m_cb.channels_activated);
284 m_cb.saadc_state = NRF_SAADC_STATE_UNINITIALIZED;
285 }
286
nrfx_saadc_channels_config(nrfx_saadc_channel_t const * p_channels,uint32_t channel_count)287 nrfx_err_t nrfx_saadc_channels_config(nrfx_saadc_channel_t const * p_channels,
288 uint32_t channel_count)
289 {
290 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
291 NRFX_ASSERT(p_channels);
292 NRFX_ASSERT(channel_count <= SAADC_CH_NUM);
293
294 if (saadc_busy_check())
295 {
296 return NRFX_ERROR_BUSY;
297 }
298
299 saadc_channels_deconfig(SAADC_ALL_CHANNELS_MASK);
300 for (uint8_t i = 0; i < channel_count; i++)
301 {
302 if (m_cb.channels_configured & (1 << p_channels[i].channel_index))
303 {
304 // This channel is already configured!
305 return NRFX_ERROR_INVALID_PARAM;
306 }
307
308 saadc_channel_config(&p_channels[i]);
309 }
310
311 return NRFX_SUCCESS;
312 }
313
nrfx_saadc_channel_config(nrfx_saadc_channel_t const * p_channel)314 nrfx_err_t nrfx_saadc_channel_config(nrfx_saadc_channel_t const * p_channel)
315 {
316 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
317 NRFX_ASSERT(p_channel);
318
319 if (saadc_busy_check())
320 {
321 return NRFX_ERROR_BUSY;
322 }
323
324 saadc_channel_config(p_channel);
325
326 return NRFX_SUCCESS;
327 }
328
nrfx_saadc_channels_configured_get(void)329 uint32_t nrfx_saadc_channels_configured_get(void)
330 {
331 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
332
333 return m_cb.channels_configured;
334 }
335
nrfx_saadc_channels_deconfig(uint32_t channel_mask)336 nrfx_err_t nrfx_saadc_channels_deconfig(uint32_t channel_mask)
337 {
338 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
339
340 if (saadc_busy_check())
341 {
342 return NRFX_ERROR_BUSY;
343 }
344
345 saadc_channels_deconfig(channel_mask);
346
347 return NRFX_SUCCESS;
348 }
349
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)350 nrfx_err_t nrfx_saadc_simple_mode_set(uint32_t channel_mask,
351 nrf_saadc_resolution_t resolution,
352 nrf_saadc_oversample_t oversampling,
353 nrfx_saadc_event_handler_t event_handler)
354 {
355 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
356
357 if (saadc_busy_check())
358 {
359 return NRFX_ERROR_BUSY;
360 }
361
362 uint8_t active_ch_count;
363 nrfx_err_t err = saadc_channel_count_get(channel_mask, &active_ch_count);
364 if (err != NRFX_SUCCESS)
365 {
366 return err;
367 }
368
369 nrf_saadc_burst_t burst;
370 if (oversampling == NRF_SAADC_OVERSAMPLE_DISABLED)
371 {
372 burst = NRF_SAADC_BURST_DISABLED;
373 }
374 else
375 {
376 // Burst is implicitly enabled if oversampling is enabled.
377 burst = NRF_SAADC_BURST_ENABLED;
378 }
379
380 saadc_generic_mode_set(channel_mask,
381 resolution,
382 oversampling,
383 burst,
384 event_handler);
385
386 m_cb.channels_activated_count = active_ch_count;
387 m_cb.saadc_state = NRF_SAADC_STATE_SIMPLE_MODE;
388
389 return NRFX_SUCCESS;
390 }
391
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)392 nrfx_err_t nrfx_saadc_advanced_mode_set(uint32_t channel_mask,
393 nrf_saadc_resolution_t resolution,
394 nrfx_saadc_adv_config_t const * p_config,
395 nrfx_saadc_event_handler_t event_handler)
396 {
397 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
398 NRFX_ASSERT(p_config);
399
400 if (saadc_busy_check())
401 {
402 return NRFX_ERROR_BUSY;
403 }
404
405 uint8_t active_ch_count;
406 nrfx_err_t err = saadc_channel_count_get(channel_mask, &active_ch_count);
407 if (err != NRFX_SUCCESS)
408 {
409 return err;
410 }
411
412 if ((p_config->internal_timer_cc) && ((active_ch_count > 1) || (!event_handler)))
413 {
414 return NRFX_ERROR_NOT_SUPPORTED;
415 }
416
417 bool oversampling_without_burst = false;
418 if ((p_config->oversampling != NRF_SAADC_OVERSAMPLE_DISABLED) &&
419 (p_config->burst == NRF_SAADC_BURST_DISABLED))
420 {
421 if (active_ch_count > 1)
422 {
423 // Oversampling without burst is possible only on single channel.
424 return NRFX_ERROR_NOT_SUPPORTED;
425 }
426 else
427 {
428 oversampling_without_burst = true;
429 }
430 }
431
432 saadc_generic_mode_set(channel_mask,
433 resolution,
434 p_config->oversampling,
435 p_config->burst,
436 event_handler);
437
438 if (p_config->internal_timer_cc)
439 {
440 nrfy_saadc_continuous_mode_enable(NRF_SAADC, p_config->internal_timer_cc);
441 }
442 else
443 {
444 nrfy_saadc_continuous_mode_disable(NRF_SAADC);
445 }
446
447 m_cb.channels_activated_count = active_ch_count;
448 m_cb.start_on_end = p_config->start_on_end;
449 m_cb.oversampling_without_burst = oversampling_without_burst;
450
451 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE;
452
453 return NRFX_SUCCESS;
454 }
455
nrfx_saadc_buffer_set(nrf_saadc_value_t * p_buffer,uint16_t size)456 nrfx_err_t nrfx_saadc_buffer_set(nrf_saadc_value_t * p_buffer, uint16_t size)
457 {
458 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
459
460 if (m_cb.buffer_secondary.p_buffer)
461 {
462 return NRFX_ERROR_ALREADY_INITIALIZED;
463 }
464
465 if (!nrfx_is_in_ram(p_buffer))
466 {
467 return NRFX_ERROR_INVALID_ADDR;
468 }
469
470 if ((size % m_cb.channels_activated_count != 0) ||
471 (size >= (1 << SAADC_EASYDMA_MAXCNT_SIZE)) ||
472 (!size))
473 {
474 return NRFX_ERROR_INVALID_LENGTH;
475 }
476
477 nrfy_saadc_buffer_t buffer = {.p_buffer = p_buffer, .length = size};
478 switch (m_cb.saadc_state)
479 {
480 case NRF_SAADC_STATE_SIMPLE_MODE:
481 if (m_cb.channels_activated_count != size)
482 {
483 return NRFX_ERROR_INVALID_LENGTH;
484 }
485 m_cb.buffer_primary = buffer;
486 break;
487
488 case NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED:
489 nrfy_saadc_buffer_set(NRF_SAADC, &buffer, false, false);
490 /* FALLTHROUGH */
491
492 case NRF_SAADC_STATE_ADV_MODE:
493 /* FALLTHROUGH */
494
495 case NRF_SAADC_STATE_ADV_MODE_SAMPLE:
496 if (m_cb.buffer_primary.p_buffer)
497 {
498 m_cb.buffer_secondary = buffer;
499 }
500 else
501 {
502 m_cb.buffer_primary = buffer;
503 }
504 break;
505
506 default:
507 return NRFX_ERROR_INVALID_STATE;
508 }
509
510 return NRFX_SUCCESS;
511 }
512
nrfx_saadc_mode_trigger(void)513 nrfx_err_t nrfx_saadc_mode_trigger(void)
514 {
515 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
516 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_IDLE);
517
518 if (!m_cb.buffer_primary.p_buffer)
519 {
520 return NRFX_ERROR_NO_MEM;
521 }
522
523 nrfx_err_t result = NRFX_SUCCESS;
524 switch (m_cb.saadc_state)
525 {
526 case NRF_SAADC_STATE_SIMPLE_MODE:
527 {
528 nrfy_saadc_enable(NRF_SAADC);
529 // When in simple blocking or non-blocking mode, buffer size is equal to activated channel count.
530 // Single SAMPLE task is enough to obtain one sample on each activated channel.
531 // This will result in buffer being filled with samples and therefore END event will appear.
532
533 if (m_cb.event_handler)
534 {
535 m_cb.saadc_state = NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE;
536 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_primary, true, false);
537 }
538 else
539 {
540 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_primary, true, true);
541 nrfy_saadc_sample_start(NRF_SAADC, &m_cb.buffer_primary);
542 nrfy_saadc_disable(NRF_SAADC);
543 }
544 break;
545 }
546
547 case NRF_SAADC_STATE_ADV_MODE:
548 {
549 nrfy_saadc_enable(NRF_SAADC);
550 if (m_cb.event_handler)
551 {
552 // When in advanced non-blocking mode, latch whole buffer in EasyDMA.
553 // END event will arrive when whole buffer is filled with samples.
554
555 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE_SAMPLE;
556 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_primary, true, false);
557 break;
558 }
559 // When in advanced blocking mode, latch single chunk of buffer in EasyDMA.
560 // Each chunk consists of single sample from each activated channels.
561 // END event will arrive when single chunk is filled with samples.
562 nrfy_saadc_buffer_t chunk =
563 {.p_buffer = &m_cb.buffer_primary.p_buffer[m_cb.samples_converted],
564 .length = m_cb.channels_activated_count};
565 nrfy_saadc_buffer_set(NRF_SAADC, &chunk, true, true);
566 if (m_cb.oversampling_without_burst)
567 {
568 // Oversampling without burst is possible only on single channel.
569 // In this configuration more than one SAMPLE task is needed to obtain single sample.
570 uint32_t samples_to_take =
571 nrfy_saadc_oversample_sample_count_get(nrfy_saadc_oversample_get(NRF_SAADC));
572
573 for (uint32_t sample_idx = 0; sample_idx < samples_to_take - 1; sample_idx++)
574 {
575 nrfy_saadc_sample_start(NRF_SAADC, NULL);
576 uint32_t evt_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_DONE);
577 while (!nrfy_saadc_events_process(NRF_SAADC, evt_mask, NULL))
578 {}
579 }
580 }
581 // Single SAMPLE task is enough to obtain one sample on each activated channel.
582 // This will result in chunk being filled with samples and therefore END event will appear.
583 nrfy_saadc_sample_start(NRF_SAADC, &chunk);
584
585 m_cb.samples_converted += m_cb.channels_activated_count;
586 if (m_cb.samples_converted < m_cb.buffer_primary.length)
587 {
588 result = NRFX_ERROR_BUSY;
589 }
590 else
591 {
592 m_cb.samples_converted = 0;
593 m_cb.buffer_primary = m_cb.buffer_secondary;
594 m_cb.buffer_secondary.p_buffer = NULL;
595 }
596 nrfy_saadc_disable(NRF_SAADC);
597 break;
598 }
599
600 default:
601 result = NRFX_ERROR_INVALID_STATE;
602 break;
603 }
604
605 return result;
606 }
607
nrfx_saadc_abort(void)608 void nrfx_saadc_abort(void)
609 {
610 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
611
612 if (m_cb.saadc_state == NRF_SAADC_STATE_CALIBRATION ? m_cb.calib_event_handler :
613 m_cb.event_handler)
614 {
615 nrfy_saadc_abort(NRF_SAADC, NULL);
616 }
617 else
618 {
619 m_cb.buffer_primary.p_buffer = NULL;
620 m_cb.buffer_secondary.p_buffer = NULL;
621 m_cb.samples_converted = 0;
622 }
623 }
624
nrfx_saadc_limits_set(uint8_t channel,int16_t limit_low,int16_t limit_high)625 nrfx_err_t nrfx_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high)
626 {
627 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
628 NRFX_ASSERT(limit_high >= limit_low);
629
630 if (!m_cb.event_handler)
631 {
632 return NRFX_ERROR_FORBIDDEN;
633 }
634
635 if ((m_cb.saadc_state == NRF_SAADC_STATE_IDLE) ||
636 (m_cb.saadc_state == NRF_SAADC_STATE_CALIBRATION))
637 {
638 return NRFX_ERROR_INVALID_STATE;
639 }
640
641 if (!(m_cb.channels_activated & (1 << channel)))
642 {
643 return NRFX_ERROR_INVALID_PARAM;
644 }
645
646 nrfy_saadc_channel_limits_set(NRF_SAADC, channel, limit_low, limit_high);
647
648 uint32_t int_mask = nrfy_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_LOW);
649 if (limit_low == INT16_MIN)
650 {
651 m_cb.limits_low_activated &= ~(1 << channel);
652 nrfy_saadc_int_disable(NRF_SAADC, int_mask);
653 }
654 else
655 {
656 m_cb.limits_low_activated |= (1 << channel);
657 nrfy_saadc_int_enable(NRF_SAADC, int_mask);
658 }
659
660 int_mask = nrfy_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_HIGH);
661 if (limit_high == INT16_MAX)
662 {
663 m_cb.limits_high_activated &= ~(1 << channel);
664 nrfy_saadc_int_disable(NRF_SAADC, int_mask);
665 }
666 else
667 {
668 m_cb.limits_high_activated |= (1 << channel);
669 nrfy_saadc_int_enable(NRF_SAADC, int_mask);
670 }
671
672 return NRFX_SUCCESS;
673 }
674
nrfx_saadc_offset_calibrate(nrfx_saadc_event_handler_t calib_event_handler)675 nrfx_err_t nrfx_saadc_offset_calibrate(nrfx_saadc_event_handler_t calib_event_handler)
676 {
677 NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
678
679 if (saadc_busy_check())
680 {
681 return NRFX_ERROR_BUSY;
682 }
683
684 m_cb.saadc_state_prev = m_cb.saadc_state;
685 m_cb.saadc_state = NRF_SAADC_STATE_CALIBRATION;
686 m_cb.calib_event_handler = calib_event_handler;
687
688 nrfy_saadc_enable(NRF_SAADC);
689
690 uint32_t int_mask = nrfy_saadc_int_enable_check(NRF_SAADC, ~0UL);
691 nrfy_saadc_int_set(NRF_SAADC, 0);
692 if (calib_event_handler)
693 {
694 nrfy_saadc_calibrate(NRF_SAADC, false);
695 // Make sure that LIMIT feature is disabled before offset calibration.
696 int_mask &= ~(NRF_SAADC_INT_CH0LIMITL | NRF_SAADC_INT_CH0LIMITH);
697 nrfy_saadc_int_set(NRF_SAADC, int_mask | NRF_SAADC_INT_STARTED | NRF_SAADC_INT_STOPPED |
698 NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE);
699 }
700 else
701 {
702 nrfy_saadc_calibrate(NRF_SAADC, true);
703
704 nrfy_saadc_buffer_t calib_buffer = {.p_buffer = m_cb.calib_samples,
705 .length = NRFX_ARRAY_SIZE(m_cb.calib_samples)};
706 nrfy_saadc_buffer_set(NRF_SAADC, &calib_buffer, true, true);
707
708 nrfy_saadc_stop(NRF_SAADC, true);
709 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END);
710 nrfy_saadc_disable(NRF_SAADC);
711 m_cb.saadc_state = m_cb.saadc_state_prev;
712
713 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CH0_LIMITL);
714 nrfy_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CH0_LIMITH);
715 nrfy_saadc_int_set(NRF_SAADC, int_mask);
716 }
717
718 return NRFX_SUCCESS;
719 }
720
saadc_pre_calibration_state_restore(void)721 static void saadc_pre_calibration_state_restore(void)
722 {
723 nrf_saadc_disable(NRF_SAADC);
724 uint32_t int_mask = nrfy_saadc_int_enable_check(NRF_SAADC, ~0UL) &
725 ~(NRF_SAADC_INT_STARTED | NRF_SAADC_INT_STOPPED |
726 NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE);
727 m_cb.saadc_state = m_cb.saadc_state_prev;
728 if (m_cb.event_handler)
729 {
730 // Restore interrupts that are used in sampling if user provided event handler
731 // during mode configuration.
732 int_mask |= NRF_SAADC_INT_STARTED | NRF_SAADC_INT_STOPPED | NRF_SAADC_INT_END;
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 if (m_cb.limits_low_activated & 0x1UL)
737 {
738 int_mask |= NRF_SAADC_INT_CH0LIMITL;
739 }
740 if (m_cb.limits_high_activated & 0x1UL)
741 {
742 int_mask |= NRF_SAADC_INT_CH0LIMITH;
743 }
744 nrfy_saadc_int_set(NRF_SAADC, int_mask);
745 }
746
saadc_event_started_handle(void)747 static void saadc_event_started_handle(void)
748 {
749 nrfx_saadc_evt_t evt_data;
750
751 switch (m_cb.saadc_state)
752 {
753 case NRF_SAADC_STATE_ADV_MODE_SAMPLE:
754 evt_data.type = NRFX_SAADC_EVT_READY;
755 m_cb.event_handler(&evt_data);
756
757 if (nrfy_saadc_continuous_mode_enable_check(NRF_SAADC))
758 {
759 // Trigger internal timer
760 nrfy_saadc_sample_start(NRF_SAADC, NULL);
761 }
762
763 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED;
764 if (m_cb.buffer_secondary.p_buffer)
765 {
766 nrfy_saadc_buffer_set(NRF_SAADC, &m_cb.buffer_secondary, false, false);
767 }
768 /* FALLTHROUGH */
769
770 case NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED:
771 if (!m_cb.buffer_secondary.p_buffer)
772 {
773 // Send next buffer request only if it was not provided earlier,
774 // before conversion start or outside of user's callback context.
775 evt_data.type = NRFX_SAADC_EVT_BUF_REQ;
776 m_cb.event_handler(&evt_data);
777 }
778 break;
779
780 case NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE:
781 nrfy_saadc_sample_start(NRF_SAADC, NULL);
782 break;
783
784 case NRF_SAADC_STATE_CALIBRATION:
785 // Stop the SAADC immediately after the temporary buffer is latched to drop spurious samples.
786 // This will cause STOPPED and END events to arrive.
787 nrfy_saadc_stop(NRF_SAADC, false);
788 break;
789
790 default:
791 break;
792 }
793 }
794
saadc_event_end_handle(void)795 static void saadc_event_end_handle(void)
796 {
797 nrfx_saadc_evt_t evt_data;
798 evt_data.type = NRFX_SAADC_EVT_DONE;
799 evt_data.data.done.p_buffer = m_cb.buffer_primary.p_buffer;
800 evt_data.data.done.size = m_cb.buffer_primary.length;
801
802 switch (m_cb.saadc_state)
803 {
804 case NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE:
805 nrfy_saadc_disable(NRF_SAADC);
806 m_cb.saadc_state = NRF_SAADC_STATE_SIMPLE_MODE;
807 /* In the simple, non-blocking mode the event handler must be
808 * called after the internal driver state is updated. This will
809 * allow starting a new conversion from the event handler context.
810 */
811 m_cb.event_handler(&evt_data);
812 break;
813
814 case NRF_SAADC_STATE_ADV_MODE_SAMPLE_STARTED:
815 if (m_cb.start_on_end && m_cb.buffer_secondary.p_buffer)
816 {
817 nrfy_saadc_buffer_latch(NRF_SAADC, false);
818 }
819 m_cb.event_handler(&evt_data);
820 m_cb.buffer_primary = m_cb.buffer_secondary;
821 m_cb.buffer_secondary.p_buffer = NULL;
822 if (!m_cb.buffer_primary.p_buffer)
823 {
824 nrfy_saadc_disable(NRF_SAADC);
825 m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE;
826 evt_data.type = NRFX_SAADC_EVT_FINISHED;
827 m_cb.event_handler(&evt_data);
828 }
829 break;
830
831 case NRF_SAADC_STATE_CALIBRATION:
832 // Spurious samples were successfully dropped and they won't affect next conversion.
833 saadc_pre_calibration_state_restore();
834 evt_data.type = NRFX_SAADC_EVT_CALIBRATEDONE;
835 m_cb.calib_event_handler(&evt_data);
836 break;
837
838 default:
839 break;
840 }
841 }
842
saadc_event_limits_handle(void)843 static void saadc_event_limits_handle(void)
844 {
845 uint32_t limits_activated = nrfy_saadc_int_enable_check(NRF_SAADC,
846 NRF_SAADC_ALL_CHANNELS_LIMITS_INT_MASK);
847 uint32_t limits_triggered = nrfy_saadc_events_process(NRF_SAADC, limits_activated, NULL) >>
848 NRF_SAADC_LIMITS_INT_OFFSET;
849
850 while (limits_triggered)
851 {
852 uint8_t limit = NRF_CTZ((uint32_t)limits_triggered);
853 limits_triggered &= ~(1 << limit);
854
855 // There are two limits per channel.
856 uint8_t channel = limit / 2;
857
858 // Limits are organised into single pair (high limit and low limit) per channel.
859 // Do not assume whether high limit or low limit is first in the bitmask.
860 nrf_saadc_limit_t limit_type =
861 ((limit & 0x1) == (NRFY_EVENT_TO_INT_BITPOS(NRF_SAADC_EVENT_CH0_LIMITH) & 0x1)) ?
862 NRF_SAADC_LIMIT_HIGH : NRF_SAADC_LIMIT_LOW;
863
864 nrfx_saadc_evt_t evt_data;
865 evt_data.type = NRFX_SAADC_EVT_LIMIT;
866 evt_data.data.limit.channel = channel;
867 evt_data.data.limit.limit_type = limit_type;
868 m_cb.event_handler(&evt_data);
869 }
870 }
871
nrfx_saadc_irq_handler(void)872 void nrfx_saadc_irq_handler(void)
873 {
874 uint32_t evt_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STARTED) |
875 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STOPPED) |
876 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_END) |
877 NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_CALIBRATEDONE);
878 evt_mask = nrfy_saadc_events_process(NRF_SAADC, evt_mask, &m_cb.buffer_primary);
879
880 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_CALIBRATEDONE))
881 {
882 nrfy_saadc_int_disable(NRF_SAADC, NRF_SAADC_INT_CALIBRATEDONE);
883 // Latch the temporary buffer to intercept any spurious samples that may appear after calibration.
884 nrfy_saadc_buffer_t calib_buffer = {.p_buffer = m_cb.calib_samples,
885 .length = NRFX_ARRAY_SIZE(m_cb.calib_samples)};
886 nrfy_saadc_buffer_set(NRF_SAADC, &calib_buffer, true, false);
887 }
888
889 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STOPPED))
890 {
891 if (m_cb.saadc_state != NRF_SAADC_STATE_CALIBRATION)
892 {
893 // If there was ongoing conversion the STOP task also triggers the END event
894 m_cb.buffer_primary.length = nrfy_saadc_amount_get(NRF_SAADC);
895 m_cb.buffer_secondary.p_buffer = NULL;
896 }
897
898 if (nrfy_saadc_int_enable_check(NRF_SAADC, NRF_SAADC_INT_CALIBRATEDONE))
899 {
900 // If STOP event arrived before CALIBRATEDONE then the calibration was aborted
901 // and END event will not appear.
902 // Calibration procedure was not completed and user handler will not be called.
903 saadc_pre_calibration_state_restore();
904 }
905 /* fall-through to the END event handler */
906 }
907
908 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_END))
909 {
910 saadc_event_end_handle();
911 }
912
913 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_SAADC_EVENT_STARTED))
914 {
915 saadc_event_started_handle();
916 }
917
918 if (m_cb.saadc_state != NRF_SAADC_STATE_CALIBRATION)
919 {
920 saadc_event_limits_handle();
921 }
922 }
923
924 #endif // NRFX_CHECK(NRFX_SAADC_ENABLED)
925