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_I2S_ENABLED)
37
38 #include <nrfx_i2s.h>
39 #include <haly/nrfy_gpio.h>
40
41 #define NRFX_LOG_MODULE I2S
42 #include <nrfx_log.h>
43
44 #define EVT_TO_STR(event) \
45 (event == NRF_I2S_EVENT_RXPTRUPD ? "NRF_I2S_EVENT_RXPTRUPD" : \
46 (event == NRF_I2S_EVENT_TXPTRUPD ? "NRF_I2S_EVENT_TXPTRUPD" : \
47 (event == NRF_I2S_EVENT_STOPPED ? "NRF_I2S_EVENT_STOPPED" : \
48 "UNKNOWN EVENT")))
49
50 #if !defined(USE_WORKAROUND_FOR_I2S_STOP_ANOMALY) && \
51 (defined(NRF52_SERIES) || defined(NRF91_SERIES))
52 // Enable workaround for nRF52 Series anomaly 194 / nRF9160 anomaly 1
53 // (STOP task does not switch off all resources).
54 #define USE_WORKAROUND_FOR_I2S_STOP_ANOMALY 1
55 #endif
56
57 #if !defined(USE_WORKAROUND_FOR_ANOMALY_170) && defined(NRF52_SERIES)
58 // Enable workaround for nRF52 Series anomaly 170
59 // (when reading the value of PSEL registers, the CONNECT field might not
60 // return the same value that has been written to it).
61 #define USE_WORKAROUND_FOR_ANOMALY_170 1
62 #endif
63
64 #if !defined(USE_WORKAROUND_FOR_ANOMALY_196) && defined(NRF52_SERIES)
65 // Enable workaround for nRF52 Series anomaly 196
66 // (PSEL acquires GPIO regardless of ENABLE).
67 #define USE_WORKAROUND_FOR_ANOMALY_196 1
68 #endif
69
70 // Control block - driver instance local data.
71 typedef struct
72 {
73 nrfx_i2s_data_handler_t handler;
74 nrfx_drv_state_t state;
75
76 bool use_rx : 1;
77 bool use_tx : 1;
78 bool rx_ready : 1;
79 bool tx_ready : 1;
80 bool buffers_needed : 1;
81 bool buffers_reused : 1;
82 bool skip_gpio_cfg : 1;
83 bool skip_psel_cfg : 1;
84
85 #if !NRFX_API_VER_AT_LEAST(3, 3, 0)
86 uint16_t buffer_size;
87 #endif
88 nrfx_i2s_buffers_t next_buffers;
89 nrfx_i2s_buffers_t current_buffers;
90 } nrfx_i2s_cb_t;
91
92 static nrfx_i2s_cb_t m_cb[NRFX_I2S_ENABLED_COUNT];
93
configure_pins(nrfx_i2s_config_t const * p_config)94 static void configure_pins(nrfx_i2s_config_t const * p_config)
95 {
96 if (!p_config->skip_gpio_cfg)
97 {
98 // Configure pins used by the peripheral:
99
100 // - SCK and LRCK (required) - depending on the mode of operation these
101 // pins are configured as outputs (in Master mode) or inputs (in Slave
102 // mode).
103 if (p_config->mode == NRF_I2S_MODE_MASTER)
104 {
105 nrfy_gpio_cfg_output(p_config->sck_pin);
106 nrfy_gpio_cfg_output(p_config->lrck_pin);
107 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_I2S_CLOCKPIN_SCK_NEEDED)
108 nrfy_gpio_pin_clock_set(p_config->sck_pin, true);
109 #endif
110 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_I2S_CLOCKPIN_LRCK_NEEDED)
111 nrfy_gpio_pin_clock_set(p_config->lrck_pin, true);
112 #endif
113 }
114 else
115 {
116 nrfy_gpio_cfg_input(p_config->sck_pin, NRF_GPIO_PIN_NOPULL);
117 nrfy_gpio_cfg_input(p_config->lrck_pin, NRF_GPIO_PIN_NOPULL);
118 }
119 // - MCK (optional) - always output,
120 if (p_config->mck_pin != NRF_I2S_PIN_NOT_CONNECTED)
121 {
122 nrfy_gpio_cfg_output(p_config->mck_pin);
123 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_I2S_CLOCKPIN_MCK_NEEDED)
124 nrfy_gpio_pin_clock_set(p_config->mck_pin, true);
125 #endif
126 }
127 // - SDOUT (optional) - always output,
128 if (p_config->sdout_pin != NRF_I2S_PIN_NOT_CONNECTED)
129 {
130 nrfy_gpio_cfg_output(p_config->sdout_pin);
131 }
132 // - SDIN (optional) - always input.
133 if (p_config->sdin_pin != NRF_I2S_PIN_NOT_CONNECTED)
134 {
135 nrfy_gpio_cfg_input(p_config->sdin_pin, NRF_GPIO_PIN_NOPULL);
136 }
137 }
138 }
139
deconfigure_pins(nrfx_i2s_t const * p_instance)140 static void deconfigure_pins(nrfx_i2s_t const * p_instance)
141 {
142 nrf_i2s_pins_t pins;
143
144 nrfy_i2s_pins_get(p_instance->p_reg, &pins);
145
146 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_170)
147 // Create bitmask for extracting pin number from PSEL register.
148 uint32_t pin_mask = NRF_I2S_PSEL_SCK_PIN_MASK;
149 #if NRF_I2S_HAS_GPIO_PORT_SELECTION
150 // If device supports more than one GPIO port, take port number into account as well.
151 pin_mask |= NRF_I2S_PSEL_SCK_PORT_MASK;
152 #endif
153 #else
154 uint32_t pin_mask = 0xFFFFFFFF;
155 #endif // USE_WORKAROUND_FOR_ANOMALY_170
156
157 nrfy_gpio_cfg_default(pins.sck_pin & pin_mask);
158 nrfy_gpio_cfg_default(pins.lrck_pin & pin_mask);
159
160 if (pins.mck_pin != NRF_I2S_PIN_NOT_CONNECTED)
161 {
162 nrfy_gpio_cfg_default(pins.mck_pin & pin_mask);
163 }
164
165 if (pins.sdout_pin != NRF_I2S_PIN_NOT_CONNECTED)
166 {
167 nrfy_gpio_cfg_default(pins.sdout_pin & pin_mask);
168 }
169
170 if (pins.sdin_pin != NRF_I2S_PIN_NOT_CONNECTED)
171 {
172 nrfy_gpio_cfg_default(pins.sdin_pin & pin_mask);
173 }
174 }
175
validate_config(nrf_i2s_mode_t mode,nrf_i2s_ratio_t ratio,nrf_i2s_swidth_t swidth)176 static inline bool validate_config(nrf_i2s_mode_t mode,
177 nrf_i2s_ratio_t ratio,
178 nrf_i2s_swidth_t swidth)
179 {
180 // The MCK/LRCK ratio has to be a multiple of 2 * sample width.
181 if (mode == NRF_I2S_MODE_MASTER)
182 {
183 if (swidth == NRF_I2S_SWIDTH_16BIT)
184 {
185 if (ratio == NRF_I2S_RATIO_48X)
186 {
187 return false;
188 }
189 }
190
191 if (swidth == NRF_I2S_SWIDTH_24BIT)
192 {
193 if ((ratio == NRF_I2S_RATIO_32X) ||
194 (ratio == NRF_I2S_RATIO_64X) ||
195 (ratio == NRF_I2S_RATIO_128X) ||
196 (ratio == NRF_I2S_RATIO_256X) ||
197 (ratio == NRF_I2S_RATIO_512X))
198 {
199 return false;
200 }
201 }
202
203 #if NRF_I2S_HAS_SWIDTH_32BIT
204 if (swidth == NRF_I2S_SWIDTH_32BIT)
205 {
206 if ((ratio == NRF_I2S_RATIO_32X) ||
207 (ratio == NRF_I2S_RATIO_48X) ||
208 (ratio == NRF_I2S_RATIO_96X))
209 {
210 return false;
211 }
212 }
213 #endif
214
215 }
216
217 return true;
218 }
219
nrfx_i2s_init(nrfx_i2s_t const * p_instance,nrfx_i2s_config_t const * p_config,nrfx_i2s_data_handler_t handler)220 nrfx_err_t nrfx_i2s_init(nrfx_i2s_t const * p_instance,
221 nrfx_i2s_config_t const * p_config,
222 nrfx_i2s_data_handler_t handler)
223 {
224 NRFX_ASSERT(p_config);
225 NRFX_ASSERT(handler);
226
227 nrfx_err_t err_code;
228 nrfx_i2s_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
229
230 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
231 {
232 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
233 err_code = NRFX_ERROR_ALREADY;
234 #else
235 err_code = NRFX_ERROR_INVALID_STATE;
236 #endif
237 NRFX_LOG_WARNING("Function: %s, error code: %s.",
238 __func__,
239 NRFX_LOG_ERROR_STRING_GET(err_code));
240 return err_code;
241 }
242
243
244 if (!validate_config(p_config->mode,
245 p_config->ratio,
246 p_config->sample_width))
247 {
248 err_code = NRFX_ERROR_INVALID_PARAM;
249 NRFX_LOG_WARNING("Function: %s, error code: %s.",
250 __func__,
251 NRFX_LOG_ERROR_STRING_GET(err_code));
252 return err_code;
253 }
254
255 configure_pins(p_config);
256
257 nrfy_i2s_config_t nrfy_config =
258 {
259 .config = {
260 .mode = p_config->mode,
261 .format = p_config->format,
262 .alignment = p_config->alignment,
263 .sample_width = p_config->sample_width,
264 .channels = p_config->channels,
265 .mck_setup = p_config->mck_setup,
266 .ratio = p_config->ratio,
267 },
268 .pins = {
269 .sck_pin = p_config->sck_pin,
270 .lrck_pin = p_config->lrck_pin,
271 .mck_pin = p_config->mck_pin,
272 .sdout_pin = p_config->sdout_pin,
273 .sdin_pin = p_config->sdin_pin,
274 },
275 #if NRF_I2S_HAS_CLKCONFIG
276 .clksrc = p_config->clksrc,
277 .enable_bypass = p_config->enable_bypass,
278 #endif
279 .skip_psel_cfg = p_config->skip_psel_cfg
280 };
281
282 nrfy_i2s_periph_configure(p_instance->p_reg, &nrfy_config);
283
284 p_cb->handler = handler;
285 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
286 p_cb->skip_psel_cfg = p_config->skip_psel_cfg;
287
288 nrfy_i2s_int_init(p_instance->p_reg,
289 NRF_I2S_INT_RXPTRUPD_MASK |
290 NRF_I2S_INT_TXPTRUPD_MASK |
291 NRF_I2S_INT_STOPPED_MASK,
292 p_config->irq_priority,
293 false);
294
295 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
296
297 NRFX_LOG_INFO("Initialized.");
298 return NRFX_SUCCESS;
299 }
300
nrfx_i2s_uninit(nrfx_i2s_t const * p_instance)301 void nrfx_i2s_uninit(nrfx_i2s_t const * p_instance)
302 {
303 nrfx_i2s_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
304
305 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
306
307 nrfx_i2s_stop(p_instance);
308
309 nrfy_i2s_int_uninit(p_instance->p_reg);
310 nrfy_i2s_disable(p_instance->p_reg);
311
312 if (!p_cb->skip_gpio_cfg)
313 {
314 deconfigure_pins(p_instance);
315 }
316
317 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_196)
318 if (!p_cb->skip_psel_cfg)
319 {
320 // Disabling I2S is insufficient to release pins acquired by the peripheral.
321 // Explicit disconnect is needed.
322 nrf_i2s_pins_t pins = {
323 .sck_pin = NRF_I2S_PIN_NOT_CONNECTED,
324 .lrck_pin = NRF_I2S_PIN_NOT_CONNECTED,
325 .mck_pin = NRF_I2S_PIN_NOT_CONNECTED,
326 .sdout_pin = NRF_I2S_PIN_NOT_CONNECTED,
327 .sdin_pin = NRF_I2S_PIN_NOT_CONNECTED,
328 };
329 nrfy_i2s_pins_set(p_instance->p_reg, &pins);
330 }
331 #endif
332
333 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
334 NRFX_LOG_INFO("Uninitialized.");
335 }
336
nrfx_i2s_init_check(nrfx_i2s_t const * p_instance)337 bool nrfx_i2s_init_check(nrfx_i2s_t const * p_instance)
338 {
339 nrfx_i2s_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
340
341 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
342 }
343
nrfx_i2s_start(nrfx_i2s_t const * p_instance,nrfx_i2s_buffers_t const * p_initial_buffers,uint16_t buffer_size,uint8_t flags)344 nrfx_err_t nrfx_i2s_start(nrfx_i2s_t const * p_instance,
345 nrfx_i2s_buffers_t const * p_initial_buffers,
346 #if !NRFX_API_VER_AT_LEAST(3, 3, 0)
347 uint16_t buffer_size,
348 #endif
349 uint8_t flags)
350 {
351 NRFX_ASSERT(p_initial_buffers != NULL);
352 NRFX_ASSERT(p_initial_buffers->p_rx_buffer != NULL ||
353 p_initial_buffers->p_tx_buffer != NULL);
354 NRFX_ASSERT((p_initial_buffers->p_rx_buffer == NULL) ||
355 (nrfx_is_in_ram(p_initial_buffers->p_rx_buffer) &&
356 nrfx_is_word_aligned(p_initial_buffers->p_rx_buffer)));
357 NRFX_ASSERT((p_initial_buffers->p_tx_buffer == NULL) ||
358 (nrfx_is_in_ram(p_initial_buffers->p_tx_buffer) &&
359 nrfx_is_word_aligned(p_initial_buffers->p_tx_buffer)));
360 #if NRFX_API_VER_AT_LEAST(3, 3, 0)
361 NRFX_ASSERT(p_initial_buffers->buffer_size != 0);
362 #else
363 NRFX_ASSERT(buffer_size != 0);
364 #endif
365 (void)(flags);
366
367 nrfx_err_t err_code;
368 nrfx_i2s_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
369
370 if (p_cb->state != NRFX_DRV_STATE_INITIALIZED)
371 {
372 err_code = NRFX_ERROR_INVALID_STATE;
373 NRFX_LOG_WARNING("Function: %s, error code: %s.",
374 __func__,
375 NRFX_LOG_ERROR_STRING_GET(err_code));
376 return err_code;
377 }
378
379 if (((p_initial_buffers->p_rx_buffer != NULL)
380 && !nrfx_is_in_ram(p_initial_buffers->p_rx_buffer))
381 ||
382 ((p_initial_buffers->p_tx_buffer != NULL)
383 && !nrfx_is_in_ram(p_initial_buffers->p_tx_buffer)))
384 {
385 err_code = NRFX_ERROR_INVALID_ADDR;
386 NRFX_LOG_WARNING("Function: %s, error code: %s.",
387 __func__,
388 NRFX_LOG_ERROR_STRING_GET(err_code));
389 return err_code;
390 }
391
392 p_cb->use_rx = (p_initial_buffers->p_rx_buffer != NULL);
393 p_cb->use_tx = (p_initial_buffers->p_tx_buffer != NULL);
394 p_cb->rx_ready = false;
395 p_cb->tx_ready = false;
396 p_cb->buffers_needed = false;
397 #if !NRFX_API_VER_AT_LEAST(3, 3, 0)
398 p_cb->buffer_size = buffer_size;
399 #endif
400
401 // Set the provided initial buffers as next, they will become the current
402 // ones after the IRQ handler is called for the first time, what will occur
403 // right after the START task is triggered.
404 p_cb->next_buffers = *p_initial_buffers;
405 p_cb->current_buffers.p_rx_buffer = NULL;
406 p_cb->current_buffers.p_tx_buffer = NULL;
407
408
409 nrfy_i2s_enable(p_instance->p_reg);
410
411 p_cb->state = NRFX_DRV_STATE_POWERED_ON;
412
413 /* Clear spurious RXPTRUPD and TXPTRUPD events (see nRF52 anomaly 55). */
414 nrfy_i2s_event_clear(p_instance->p_reg, NRF_I2S_EVENT_RXPTRUPD);
415 nrfy_i2s_event_clear(p_instance->p_reg, NRF_I2S_EVENT_TXPTRUPD);
416
417 nrfy_i2s_int_enable(p_instance->p_reg,
418 (p_cb->use_rx ? NRF_I2S_INT_RXPTRUPD_MASK : 0UL) |
419 (p_cb->use_tx ? NRF_I2S_INT_TXPTRUPD_MASK : 0UL) |
420 NRF_I2S_INT_STOPPED_MASK);
421
422 #if NRFX_API_VER_AT_LEAST(3, 3, 0)
423 nrfy_i2s_buffers_set(p_instance->p_reg, &p_cb->next_buffers);
424 #else
425 const nrfy_i2s_xfer_desc_t xfer = {
426 .p_rx_buffer = p_cb->next_buffers.p_rx_buffer,
427 .p_tx_buffer = p_cb->next_buffers.p_tx_buffer,
428 .buffer_size = p_cb->buffer_size,
429 };
430
431 nrfy_i2s_buffers_set(p_instance->p_reg, &xfer);
432 #endif
433 nrfy_i2s_xfer_start(p_instance->p_reg, NULL);
434
435 NRFX_LOG_INFO("Started.");
436 return NRFX_SUCCESS;
437 }
438
nrfx_i2s_next_buffers_set(nrfx_i2s_t const * p_instance,nrfx_i2s_buffers_t const * p_buffers)439 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_t const * p_instance,
440 nrfx_i2s_buffers_t const * p_buffers)
441 {
442 nrfx_err_t err_code;
443 nrfx_i2s_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
444
445 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
446 NRFX_ASSERT(p_buffers);
447 NRFX_ASSERT((p_buffers->p_rx_buffer == NULL) ||
448 (nrfx_is_in_ram(p_buffers->p_rx_buffer) &&
449 nrfx_is_word_aligned(p_buffers->p_rx_buffer)));
450 NRFX_ASSERT((p_buffers->p_tx_buffer == NULL) ||
451 (nrfx_is_in_ram(p_buffers->p_tx_buffer) &&
452 nrfx_is_word_aligned(p_buffers->p_tx_buffer)));
453 #if NRFX_API_VER_AT_LEAST(3, 3, 0)
454 NRFX_ASSERT(p_buffers->buffer_size != 0);
455 #endif
456
457 if (!p_cb->buffers_needed)
458 {
459 err_code = NRFX_ERROR_INVALID_STATE;
460 NRFX_LOG_WARNING("Function: %s, error code: %s.",
461 __func__,
462 NRFX_LOG_ERROR_STRING_GET(err_code));
463 return err_code;
464 }
465
466 if (((p_buffers->p_rx_buffer != NULL)
467 && !nrfx_is_in_ram(p_buffers->p_rx_buffer))
468 ||
469 ((p_buffers->p_tx_buffer != NULL)
470 && !nrfx_is_in_ram(p_buffers->p_tx_buffer)))
471 {
472 err_code = NRFX_ERROR_INVALID_ADDR;
473 NRFX_LOG_WARNING("Function: %s, error code: %s.",
474 __func__,
475 NRFX_LOG_ERROR_STRING_GET(err_code));
476 return err_code;
477 }
478
479 if (p_cb->use_tx)
480 {
481 NRFX_ASSERT(p_buffers->p_tx_buffer != NULL);
482 }
483 if (p_cb->use_rx)
484 {
485 NRFX_ASSERT(p_buffers->p_rx_buffer != NULL);
486 }
487
488 #if NRFX_API_VER_AT_LEAST(3, 3, 0)
489 nrfy_i2s_buffers_set(p_instance->p_reg, p_buffers);
490 #else
491 nrfy_i2s_xfer_desc_t xfer = {
492 .p_rx_buffer = p_buffers->p_rx_buffer,
493 .p_tx_buffer = p_buffers->p_tx_buffer,
494 .buffer_size = p_cb->buffer_size,
495 };
496
497 nrfy_i2s_buffers_set(p_instance->p_reg, &xfer);
498 #endif
499
500 p_cb->next_buffers = *p_buffers;
501 p_cb->buffers_needed = false;
502
503 return NRFX_SUCCESS;
504 }
505
nrfx_i2s_stop(nrfx_i2s_t const * p_instance)506 void nrfx_i2s_stop(nrfx_i2s_t const * p_instance)
507 {
508 nrfx_i2s_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
509
510 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
511
512 p_cb->buffers_needed = false;
513
514 // First disable interrupts, then trigger the STOP task, so no spurious
515 // RXPTRUPD and TXPTRUPD events (see nRF52 anomaly 55) are processed.
516 nrfy_i2s_int_disable(p_instance->p_reg, NRF_I2S_INT_RXPTRUPD_MASK |
517 NRF_I2S_INT_TXPTRUPD_MASK);
518
519 nrfy_i2s_abort(p_instance->p_reg, NULL);
520
521 #if NRFX_CHECK(USE_WORKAROUND_FOR_I2S_STOP_ANOMALY)
522 *((volatile uint32_t *)(((uint32_t)p_instance->p_reg) + 0x38)) = 1;
523 *((volatile uint32_t *)(((uint32_t)p_instance->p_reg) + 0x3C)) = 1;
524 #endif
525 }
526
irq_handler(NRF_I2S_Type * p_reg,nrfx_i2s_cb_t * p_cb)527 static void irq_handler(NRF_I2S_Type * p_reg, nrfx_i2s_cb_t * p_cb)
528 {
529 uint32_t event_mask;
530 nrfy_i2s_xfer_desc_t * p_xfer;
531
532 #if NRFX_API_VER_AT_LEAST(3, 3, 0)
533 p_xfer = &p_cb->current_buffers;
534 #else
535 nrfy_i2s_xfer_desc_t xfer = {
536 .p_rx_buffer = p_cb->current_buffers.p_rx_buffer,
537 .p_tx_buffer = p_cb->current_buffers.p_tx_buffer,
538 .buffer_size = p_cb->buffer_size,
539 };
540 p_xfer = &xfer;
541 #endif
542
543 event_mask = nrfy_i2s_events_process(p_reg,
544 NRFY_EVENT_TO_INT_BITMASK(NRF_I2S_EVENT_TXPTRUPD) |
545 NRFY_EVENT_TO_INT_BITMASK(NRF_I2S_EVENT_RXPTRUPD) |
546 NRFY_EVENT_TO_INT_BITMASK(NRF_I2S_EVENT_STOPPED),
547 p_xfer);
548
549 if (event_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_I2S_EVENT_TXPTRUPD))
550 {
551 p_cb->tx_ready = true;
552 if (p_cb->use_tx && p_cb->buffers_needed)
553 {
554 p_cb->buffers_reused = true;
555 }
556 }
557 if (event_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_I2S_EVENT_RXPTRUPD))
558 {
559 p_cb->rx_ready = true;
560 if (p_cb->use_rx && p_cb->buffers_needed)
561 {
562 p_cb->buffers_reused = true;
563 }
564 }
565
566 if (event_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_I2S_EVENT_STOPPED))
567 {
568 nrfy_i2s_int_disable(p_reg, NRF_I2S_INT_STOPPED_MASK);
569 nrfy_i2s_disable(p_reg);
570
571 // When stopped, release all buffers, including these scheduled for
572 // the next part of the transfer, and signal that the transfer has
573 // finished.
574
575 p_cb->handler(&p_cb->current_buffers, 0);
576
577 // Change the state of the driver before calling the handler with
578 // the flag signaling that the transfer has finished, so that it is
579 // possible to start a new transfer directly from the handler function.
580 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
581 NRFX_LOG_INFO("Stopped.");
582
583 p_cb->handler(&p_cb->next_buffers, NRFX_I2S_STATUS_TRANSFER_STOPPED);
584 }
585 else
586 {
587 // Check if the requested transfer has been completed:
588 // - full-duplex mode
589 if ((p_cb->use_tx && p_cb->use_rx &&
590 p_cb->tx_ready && p_cb->rx_ready) ||
591 // - TX only mode
592 (!p_cb->use_rx && p_cb->tx_ready) ||
593 // - RX only mode
594 (!p_cb->use_tx && p_cb->rx_ready))
595 {
596 p_cb->tx_ready = false;
597 p_cb->rx_ready = false;
598
599 // If the application did not supply the buffers for the next
600 // part of the transfer until this moment, the current buffers
601 // cannot be released, since the I2S peripheral already started
602 // using them. Signal this situation to the application by
603 // passing NULL instead of the structure with released buffers.
604 if (p_cb->buffers_reused)
605 {
606 p_cb->buffers_reused = false;
607 // This will most likely be set at this point. However, there is
608 // a small time window between TXPTRUPD and RXPTRUPD events,
609 // and it is theoretically possible that next buffers will be
610 // set in this window, so to be sure this flag is set to true,
611 // set it explicitly.
612 p_cb->buffers_needed = true;
613 p_cb->handler(NULL, NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED);
614 }
615 else
616 {
617 // Buffers that have been used by the I2S peripheral (current)
618 // are now released and will be returned to the application,
619 // and the ones scheduled to be used as next become the current
620 // ones.
621 nrfx_i2s_buffers_t released_buffers = p_cb->current_buffers;
622 p_cb->current_buffers = p_cb->next_buffers;
623 p_cb->next_buffers.p_rx_buffer = NULL;
624 p_cb->next_buffers.p_tx_buffer = NULL;
625 p_cb->buffers_needed = true;
626 p_cb->handler(&released_buffers, NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED);
627 }
628
629 }
630 }
631 }
632
633 NRFX_INSTANCE_IRQ_HANDLERS(I2S, i2s)
634
635 #endif // NRFX_CHECK(NRFX_I2S_ENABLED)
636