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 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 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 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 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 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 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 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