1 /*
2 * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <nrfx.h>
33
34 #if NRFX_CHECK(NRFX_I2S_ENABLED)
35
36 #include <nrfx_i2s.h>
37 #include <hal/nrf_gpio.h>
38
39 #define NRFX_LOG_MODULE I2S
40 #include <nrfx_log.h>
41
42 #define EVT_TO_STR(event) \
43 (event == NRF_I2S_EVENT_RXPTRUPD ? "NRF_I2S_EVENT_RXPTRUPD" : \
44 (event == NRF_I2S_EVENT_TXPTRUPD ? "NRF_I2S_EVENT_TXPTRUPD" : \
45 (event == NRF_I2S_EVENT_STOPPED ? "NRF_I2S_EVENT_STOPPED" : \
46 "UNKNOWN EVENT")))
47
48 #if !defined(USE_WORKAROUND_FOR_ANOMALY_194) && \
49 (defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
50 defined(NRF52840_XXAA))
51 // Enable workaround for nRF52832 and nRF52840 anomaly 194 (STOP task does not
52 // switch off all resources).
53 #define USE_WORKAROUND_FOR_ANOMALY_194 1
54 #else
55 #define USE_WORKAROUND_FOR_ANOMALY_194 0
56 #endif
57
58 // Control block - driver instance local data.
59 typedef struct
60 {
61 nrfx_i2s_data_handler_t handler;
62 nrfx_drv_state_t state;
63
64 bool use_rx : 1;
65 bool use_tx : 1;
66 bool rx_ready : 1;
67 bool tx_ready : 1;
68 bool buffers_needed : 1;
69 bool buffers_reused : 1;
70
71 uint16_t buffer_size;
72 nrfx_i2s_buffers_t next_buffers;
73 nrfx_i2s_buffers_t current_buffers;
74 } i2s_control_block_t;
75 static i2s_control_block_t m_cb;
76
77
configure_pins(nrfx_i2s_config_t const * p_config)78 static void configure_pins(nrfx_i2s_config_t const * p_config)
79 {
80 uint32_t mck_pin, sdout_pin, sdin_pin;
81
82 // Configure pins used by the peripheral:
83
84 // - SCK and LRCK (required) - depending on the mode of operation these
85 // pins are configured as outputs (in Master mode) or inputs (in Slave
86 // mode).
87 if (p_config->mode == NRF_I2S_MODE_MASTER)
88 {
89 nrf_gpio_cfg_output(p_config->sck_pin);
90 nrf_gpio_cfg_output(p_config->lrck_pin);
91 }
92 else
93 {
94 nrf_gpio_cfg_input(p_config->sck_pin, NRF_GPIO_PIN_NOPULL);
95 nrf_gpio_cfg_input(p_config->lrck_pin, NRF_GPIO_PIN_NOPULL);
96 }
97
98 // - MCK (optional) - always output,
99 if (p_config->mck_pin != NRFX_I2S_PIN_NOT_USED)
100 {
101 mck_pin = p_config->mck_pin;
102 nrf_gpio_cfg_output(mck_pin);
103 }
104 else
105 {
106 mck_pin = NRF_I2S_PIN_NOT_CONNECTED;
107 }
108
109 // - SDOUT (optional) - always output,
110 if (p_config->sdout_pin != NRFX_I2S_PIN_NOT_USED)
111 {
112 sdout_pin = p_config->sdout_pin;
113 nrf_gpio_cfg_output(sdout_pin);
114 }
115 else
116 {
117 sdout_pin = NRF_I2S_PIN_NOT_CONNECTED;
118 }
119
120 // - SDIN (optional) - always input.
121 if (p_config->sdin_pin != NRFX_I2S_PIN_NOT_USED)
122 {
123 sdin_pin = p_config->sdin_pin;
124 nrf_gpio_cfg_input(sdin_pin, NRF_GPIO_PIN_NOPULL);
125 }
126 else
127 {
128 sdin_pin = NRF_I2S_PIN_NOT_CONNECTED;
129 }
130
131 nrf_i2s_pins_set(NRF_I2S,
132 p_config->sck_pin,
133 p_config->lrck_pin,
134 mck_pin,
135 sdout_pin,
136 sdin_pin);
137 }
138
139
nrfx_i2s_init(nrfx_i2s_config_t const * p_config,nrfx_i2s_data_handler_t handler)140 nrfx_err_t nrfx_i2s_init(nrfx_i2s_config_t const * p_config,
141 nrfx_i2s_data_handler_t handler)
142 {
143 NRFX_ASSERT(p_config);
144 NRFX_ASSERT(handler);
145
146 nrfx_err_t err_code;
147
148 if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
149 {
150 err_code = NRFX_ERROR_INVALID_STATE;
151 NRFX_LOG_WARNING("Function: %s, error code: %s.",
152 __func__,
153 NRFX_LOG_ERROR_STRING_GET(err_code));
154 return err_code;
155 }
156
157 if (!nrf_i2s_configure(NRF_I2S,
158 p_config->mode,
159 p_config->format,
160 p_config->alignment,
161 p_config->sample_width,
162 p_config->channels,
163 p_config->mck_setup,
164 p_config->ratio))
165 {
166 err_code = NRFX_ERROR_INVALID_PARAM;
167 NRFX_LOG_WARNING("Function: %s, error code: %s.",
168 __func__,
169 NRFX_LOG_ERROR_STRING_GET(err_code));
170 return err_code;
171 }
172 configure_pins(p_config);
173
174 m_cb.handler = handler;
175
176 NRFX_IRQ_PRIORITY_SET(I2S_IRQn, p_config->irq_priority);
177 NRFX_IRQ_ENABLE(I2S_IRQn);
178
179 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
180
181 NRFX_LOG_INFO("Initialized.");
182 return NRFX_SUCCESS;
183 }
184
185
nrfx_i2s_uninit(void)186 void nrfx_i2s_uninit(void)
187 {
188 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
189
190 nrfx_i2s_stop();
191
192 NRFX_IRQ_DISABLE(I2S_IRQn);
193
194 nrf_i2s_pins_set(NRF_I2S,
195 NRF_I2S_PIN_NOT_CONNECTED,
196 NRF_I2S_PIN_NOT_CONNECTED,
197 NRF_I2S_PIN_NOT_CONNECTED,
198 NRF_I2S_PIN_NOT_CONNECTED,
199 NRF_I2S_PIN_NOT_CONNECTED);
200
201 m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
202 NRFX_LOG_INFO("Uninitialized.");
203 }
204
205
nrfx_i2s_start(nrfx_i2s_buffers_t const * p_initial_buffers,uint16_t buffer_size,uint8_t flags)206 nrfx_err_t nrfx_i2s_start(nrfx_i2s_buffers_t const * p_initial_buffers,
207 uint16_t buffer_size,
208 uint8_t flags)
209 {
210 NRFX_ASSERT(p_initial_buffers != NULL);
211 NRFX_ASSERT(p_initial_buffers->p_rx_buffer != NULL ||
212 p_initial_buffers->p_tx_buffer != NULL);
213 NRFX_ASSERT((p_initial_buffers->p_rx_buffer == NULL) ||
214 (nrfx_is_in_ram(p_initial_buffers->p_rx_buffer) &&
215 nrfx_is_word_aligned(p_initial_buffers->p_rx_buffer)));
216 NRFX_ASSERT((p_initial_buffers->p_tx_buffer == NULL) ||
217 (nrfx_is_in_ram(p_initial_buffers->p_tx_buffer) &&
218 nrfx_is_word_aligned(p_initial_buffers->p_tx_buffer)));
219 NRFX_ASSERT(buffer_size != 0);
220 (void)(flags);
221
222 nrfx_err_t err_code;
223
224 if (m_cb.state != NRFX_DRV_STATE_INITIALIZED)
225 {
226 err_code = NRFX_ERROR_INVALID_STATE;
227 NRFX_LOG_WARNING("Function: %s, error code: %s.",
228 __func__,
229 NRFX_LOG_ERROR_STRING_GET(err_code));
230 return err_code;
231 }
232
233 if (((p_initial_buffers->p_rx_buffer != NULL)
234 && !nrfx_is_in_ram(p_initial_buffers->p_rx_buffer))
235 ||
236 ((p_initial_buffers->p_tx_buffer != NULL)
237 && !nrfx_is_in_ram(p_initial_buffers->p_tx_buffer)))
238 {
239 err_code = NRFX_ERROR_INVALID_ADDR;
240 NRFX_LOG_WARNING("Function: %s, error code: %s.",
241 __func__,
242 NRFX_LOG_ERROR_STRING_GET(err_code));
243 return err_code;
244 }
245
246 m_cb.use_rx = (p_initial_buffers->p_rx_buffer != NULL);
247 m_cb.use_tx = (p_initial_buffers->p_tx_buffer != NULL);
248 m_cb.rx_ready = false;
249 m_cb.tx_ready = false;
250 m_cb.buffers_needed = false;
251 m_cb.buffer_size = buffer_size;
252
253 // Set the provided initial buffers as next, they will become the current
254 // ones after the IRQ handler is called for the first time, what will occur
255 // right after the START task is triggered.
256 m_cb.next_buffers = *p_initial_buffers;
257 m_cb.current_buffers.p_rx_buffer = NULL;
258 m_cb.current_buffers.p_tx_buffer = NULL;
259
260 nrf_i2s_transfer_set(NRF_I2S,
261 m_cb.buffer_size,
262 m_cb.next_buffers.p_rx_buffer,
263 m_cb.next_buffers.p_tx_buffer);
264
265 nrf_i2s_enable(NRF_I2S);
266
267 m_cb.state = NRFX_DRV_STATE_POWERED_ON;
268
269 nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_RXPTRUPD);
270 nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_TXPTRUPD);
271 nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_STOPPED);
272 nrf_i2s_int_enable(NRF_I2S, (m_cb.use_rx ? NRF_I2S_INT_RXPTRUPD_MASK : 0) |
273 (m_cb.use_tx ? NRF_I2S_INT_TXPTRUPD_MASK : 0) |
274 NRF_I2S_INT_STOPPED_MASK);
275 nrf_i2s_task_trigger(NRF_I2S, NRF_I2S_TASK_START);
276
277 NRFX_LOG_INFO("Started.");
278 return NRFX_SUCCESS;
279 }
280
281
nrfx_i2s_next_buffers_set(nrfx_i2s_buffers_t const * p_buffers)282 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_buffers_t const * p_buffers)
283 {
284 NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_POWERED_ON);
285 NRFX_ASSERT(p_buffers);
286 NRFX_ASSERT((p_buffers->p_rx_buffer == NULL) ||
287 (nrfx_is_in_ram(p_buffers->p_rx_buffer) &&
288 nrfx_is_word_aligned(p_buffers->p_rx_buffer)));
289 NRFX_ASSERT((p_buffers->p_tx_buffer == NULL) ||
290 (nrfx_is_in_ram(p_buffers->p_tx_buffer) &&
291 nrfx_is_word_aligned(p_buffers->p_tx_buffer)));
292
293 nrfx_err_t err_code;
294
295 if (!m_cb.buffers_needed)
296 {
297 err_code = NRFX_ERROR_INVALID_STATE;
298 NRFX_LOG_WARNING("Function: %s, error code: %s.",
299 __func__,
300 NRFX_LOG_ERROR_STRING_GET(err_code));
301 return err_code;
302 }
303
304 if (((p_buffers->p_rx_buffer != NULL)
305 && !nrfx_is_in_ram(p_buffers->p_rx_buffer))
306 ||
307 ((p_buffers->p_tx_buffer != NULL)
308 && !nrfx_is_in_ram(p_buffers->p_tx_buffer)))
309 {
310 err_code = NRFX_ERROR_INVALID_ADDR;
311 NRFX_LOG_WARNING("Function: %s, error code: %s.",
312 __func__,
313 NRFX_LOG_ERROR_STRING_GET(err_code));
314 return err_code;
315 }
316
317 if (m_cb.use_tx)
318 {
319 NRFX_ASSERT(p_buffers->p_tx_buffer != NULL);
320 nrf_i2s_tx_buffer_set(NRF_I2S, p_buffers->p_tx_buffer);
321 }
322 if (m_cb.use_rx)
323 {
324 NRFX_ASSERT(p_buffers->p_rx_buffer != NULL);
325 nrf_i2s_rx_buffer_set(NRF_I2S, p_buffers->p_rx_buffer);
326 }
327
328 m_cb.next_buffers = *p_buffers;
329 m_cb.buffers_needed = false;
330
331 return NRFX_SUCCESS;
332 }
333
334
nrfx_i2s_stop(void)335 void nrfx_i2s_stop(void)
336 {
337 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
338
339 m_cb.buffers_needed = false;
340
341 // First disable interrupts, then trigger the STOP task, so no spurious
342 // RXPTRUPD and TXPTRUPD events (see nRF52 anomaly 55) are processed.
343 nrf_i2s_int_disable(NRF_I2S, NRF_I2S_INT_RXPTRUPD_MASK |
344 NRF_I2S_INT_TXPTRUPD_MASK);
345 nrf_i2s_task_trigger(NRF_I2S, NRF_I2S_TASK_STOP);
346
347 #if USE_WORKAROUND_FOR_ANOMALY_194
348 *((volatile uint32_t *)0x40025038) = 1;
349 *((volatile uint32_t *)0x4002503C) = 1;
350 #endif
351 }
352
353
nrfx_i2s_irq_handler(void)354 void nrfx_i2s_irq_handler(void)
355 {
356 if (nrf_i2s_event_check(NRF_I2S, NRF_I2S_EVENT_TXPTRUPD))
357 {
358 nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_TXPTRUPD);
359 m_cb.tx_ready = true;
360 if (m_cb.use_tx && m_cb.buffers_needed)
361 {
362 m_cb.buffers_reused = true;
363 }
364 }
365 if (nrf_i2s_event_check(NRF_I2S, NRF_I2S_EVENT_RXPTRUPD))
366 {
367 nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_RXPTRUPD);
368 m_cb.rx_ready = true;
369 if (m_cb.use_rx && m_cb.buffers_needed)
370 {
371 m_cb.buffers_reused = true;
372 }
373 }
374
375 if (nrf_i2s_event_check(NRF_I2S, NRF_I2S_EVENT_STOPPED))
376 {
377 nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_STOPPED);
378 nrf_i2s_int_disable(NRF_I2S, NRF_I2S_INT_STOPPED_MASK);
379 nrf_i2s_disable(NRF_I2S);
380
381 // When stopped, release all buffers, including these scheduled for
382 // the next transfer.
383 m_cb.handler(&m_cb.current_buffers, 0);
384 m_cb.handler(&m_cb.next_buffers, 0);
385
386 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
387 NRFX_LOG_INFO("Stopped.");
388 }
389 else
390 {
391 // Check if the requested transfer has been completed:
392 // - full-duplex mode
393 if ((m_cb.use_tx && m_cb.use_rx && m_cb.tx_ready && m_cb.rx_ready) ||
394 // - TX only mode
395 (!m_cb.use_rx && m_cb.tx_ready) ||
396 // - RX only mode
397 (!m_cb.use_tx && m_cb.rx_ready))
398 {
399 m_cb.tx_ready = false;
400 m_cb.rx_ready = false;
401
402 // If the application did not supply the buffers for the next
403 // part of the transfer until this moment, the current buffers
404 // cannot be released, since the I2S peripheral already started
405 // using them. Signal this situation to the application by
406 // passing NULL instead of the structure with released buffers.
407 if (m_cb.buffers_reused)
408 {
409 m_cb.buffers_reused = false;
410 // This will most likely be set at this point. However, there is
411 // a small time window between TXPTRUPD and RXPTRUPD events,
412 // and it is theoretically possible that next buffers will be
413 // set in this window, so to be sure this flag is set to true,
414 // set it explicitly.
415 m_cb.buffers_needed = true;
416 m_cb.handler(NULL,
417 NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED);
418 }
419 else
420 {
421 // Buffers that have been used by the I2S peripheral (current)
422 // are now released and will be returned to the application,
423 // and the ones scheduled to be used as next become the current
424 // ones.
425 nrfx_i2s_buffers_t released_buffers = m_cb.current_buffers;
426 m_cb.current_buffers = m_cb.next_buffers;
427 m_cb.next_buffers.p_rx_buffer = NULL;
428 m_cb.next_buffers.p_tx_buffer = NULL;
429 m_cb.buffers_needed = true;
430 m_cb.handler(&released_buffers,
431 NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED);
432 }
433
434 }
435 }
436 }
437
438 #endif // NRFX_CHECK(NRFX_I2S_ENABLED)
439