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_SPIM_ENABLED) 35 36 #if !(NRFX_CHECK(NRFX_SPIM0_ENABLED) || NRFX_CHECK(NRFX_SPIM1_ENABLED) || \ 37 NRFX_CHECK(NRFX_SPIM2_ENABLED) || NRFX_CHECK(NRFX_SPIM3_ENABLED)) 38 #error "No enabled SPIM instances. Check <nrfx_config.h>." 39 #endif 40 41 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && !NRFX_CHECK(NRFX_SPIM3_ENABLED) 42 #error "Extended options are available only in SPIM3 on the nRF52840 SoC." 43 #endif 44 45 #include <nrfx_spim.h> 46 #include "prs/nrfx_prs.h" 47 #include <hal/nrf_gpio.h> 48 49 #define NRFX_LOG_MODULE SPIM 50 #include <nrfx_log.h> 51 52 #define SPIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \ 53 (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \ 54 NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len)) 55 56 #if NRFX_CHECK(NRFX_SPIM0_ENABLED) 57 #define SPIM0_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM0, __VA_ARGS__) 58 #else 59 #define SPIM0_LENGTH_VALIDATE(...) 0 60 #endif 61 62 #if NRFX_CHECK(NRFX_SPIM1_ENABLED) 63 #define SPIM1_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM1, __VA_ARGS__) 64 #else 65 #define SPIM1_LENGTH_VALIDATE(...) 0 66 #endif 67 68 #if NRFX_CHECK(NRFX_SPIM2_ENABLED) 69 #define SPIM2_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM2, __VA_ARGS__) 70 #else 71 #define SPIM2_LENGTH_VALIDATE(...) 0 72 #endif 73 74 #if NRFX_CHECK(NRFX_SPIM3_ENABLED) 75 #define SPIM3_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM3, __VA_ARGS__) 76 #else 77 #define SPIM3_LENGTH_VALIDATE(...) 0 78 #endif 79 80 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \ 81 (SPIM0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ 82 SPIM1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ 83 SPIM2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ 84 SPIM3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)) 85 86 #if defined(NRF52840_XXAA) && (NRFX_CHECK(NRFX_SPIM3_ENABLED)) 87 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable). 88 #define USE_WORKAROUND_FOR_ANOMALY_195 89 #endif 90 91 // Control block - driver instance local data. 92 typedef struct 93 { 94 nrfx_spim_evt_handler_t handler; 95 void * p_context; 96 nrfx_spim_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy. 97 nrfx_drv_state_t state; 98 volatile bool transfer_in_progress; 99 100 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 101 bool use_hw_ss; 102 #endif 103 104 // [no need for 'volatile' attribute for the following members, as they 105 // are not concurrently used in IRQ handlers and main line code] 106 bool ss_active_high; 107 uint8_t ss_pin; 108 uint8_t miso_pin; 109 uint8_t orc; 110 111 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) 112 size_t tx_length; 113 size_t rx_length; 114 #endif 115 } spim_control_block_t; 116 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT]; 117 118 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) 119 120 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted. 121 122 static uint32_t m_anomaly_198_preserved_value; 123 124 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len) 125 { 126 m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00); 127 128 if (buf_len == 0) 129 { 130 return; 131 } 132 uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len; 133 uint32_t block_addr = ((uint32_t)p_buffer) & ~0x1FFF; 134 uint32_t block_flag = (1UL << ((block_addr >> 13) & 0xFFFF)); 135 uint32_t occupied_blocks = 0; 136 137 if (block_addr >= 0x20010000) 138 { 139 occupied_blocks = (1UL << 8); 140 } 141 else 142 { 143 do { 144 occupied_blocks |= block_flag; 145 block_flag <<= 1; 146 block_addr += 0x2000; 147 } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000)); 148 } 149 150 *((volatile uint32_t *)0x40000E00) = occupied_blocks; 151 } 152 153 static void anomaly_198_disable(void) 154 { 155 *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value; 156 } 157 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) 158 159 nrfx_err_t nrfx_spim_init(nrfx_spim_t const * const p_instance, 160 nrfx_spim_config_t const * p_config, 161 nrfx_spim_evt_handler_t handler, 162 void * p_context) 163 { 164 NRFX_ASSERT(p_config); 165 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; 166 nrfx_err_t err_code; 167 168 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED) 169 { 170 err_code = NRFX_ERROR_INVALID_STATE; 171 NRFX_LOG_WARNING("Function: %s, error code: %s.", 172 __func__, 173 NRFX_LOG_ERROR_STRING_GET(err_code)); 174 return err_code; 175 } 176 177 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 178 // Currently, only SPIM3 in nRF52840 supports the extended features. 179 // Other instances must be checked. 180 if ((p_instance->drv_inst_idx != NRFX_SPIM3_INST_IDX) && 181 ((p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED) || 182 (p_config->frequency == NRF_SPIM_FREQ_16M) || 183 (p_config->frequency == NRF_SPIM_FREQ_32M) || 184 (p_config->use_hw_ss))) 185 { 186 err_code = NRFX_ERROR_NOT_SUPPORTED; 187 NRFX_LOG_WARNING("Function: %s, error code: %s.", 188 __func__, 189 NRFX_LOG_ERROR_STRING_GET(err_code)); 190 return err_code; 191 } 192 #endif 193 194 NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; 195 196 #if NRFX_CHECK(NRFX_PRS_ENABLED) 197 static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = { 198 #if NRFX_CHECK(NRFX_SPIM0_ENABLED) 199 nrfx_spim_0_irq_handler, 200 #endif 201 #if NRFX_CHECK(NRFX_SPIM1_ENABLED) 202 nrfx_spim_1_irq_handler, 203 #endif 204 #if NRFX_CHECK(NRFX_SPIM2_ENABLED) 205 nrfx_spim_2_irq_handler, 206 #endif 207 #if NRFX_CHECK(NRFX_SPIM3_ENABLED) 208 nrfx_spim_3_irq_handler, 209 #endif 210 }; 211 if (nrfx_prs_acquire(p_instance->p_reg, 212 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS) 213 { 214 err_code = NRFX_ERROR_BUSY; 215 NRFX_LOG_WARNING("Function: %s, error code: %s.", 216 __func__, 217 NRFX_LOG_ERROR_STRING_GET(err_code)); 218 return err_code; 219 } 220 #endif // NRFX_CHECK(NRFX_PRS_ENABLED) 221 222 p_cb->handler = handler; 223 p_cb->p_context = p_context; 224 225 uint32_t mosi_pin; 226 uint32_t miso_pin; 227 // Configure pins used by the peripheral: 228 // - SCK - output with initial value corresponding with the SPI mode used: 229 // 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1); 230 // according to the reference manual guidelines this pin and its input 231 // buffer must always be connected for the SPI to work. 232 if (p_config->mode <= NRF_SPIM_MODE_1) 233 { 234 nrf_gpio_pin_clear(p_config->sck_pin); 235 } 236 else 237 { 238 nrf_gpio_pin_set(p_config->sck_pin); 239 } 240 nrf_gpio_cfg(p_config->sck_pin, 241 NRF_GPIO_PIN_DIR_OUTPUT, 242 NRF_GPIO_PIN_INPUT_CONNECT, 243 NRF_GPIO_PIN_NOPULL, 244 NRF_GPIO_PIN_S0S1, 245 NRF_GPIO_PIN_NOSENSE); 246 // - MOSI (optional) - output with initial value 0, 247 if (p_config->mosi_pin != NRFX_SPIM_PIN_NOT_USED) 248 { 249 mosi_pin = p_config->mosi_pin; 250 nrf_gpio_pin_clear(mosi_pin); 251 nrf_gpio_cfg_output(mosi_pin); 252 } 253 else 254 { 255 mosi_pin = NRF_SPIM_PIN_NOT_CONNECTED; 256 } 257 // - MISO (optional) - input, 258 if (p_config->miso_pin != NRFX_SPIM_PIN_NOT_USED) 259 { 260 miso_pin = p_config->miso_pin; 261 nrf_gpio_cfg_input(miso_pin, (nrf_gpio_pin_pull_t)NRFX_SPIM_MISO_PULL_CFG); 262 } 263 else 264 { 265 miso_pin = NRF_SPIM_PIN_NOT_CONNECTED; 266 } 267 p_cb->miso_pin = p_config->miso_pin; 268 // - Slave Select (optional) - output with initial value 1 (inactive). 269 270 // 'p_cb->ss_pin' variable is used during transfers to check if SS pin should be toggled, 271 // so this field needs to be initialized even if the pin is not used. 272 p_cb->ss_pin = p_config->ss_pin; 273 274 if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED) 275 { 276 if (p_config->ss_active_high) 277 { 278 nrf_gpio_pin_clear(p_config->ss_pin); 279 } 280 else 281 { 282 nrf_gpio_pin_set(p_config->ss_pin); 283 } 284 nrf_gpio_cfg_output(p_config->ss_pin); 285 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 286 if (p_config->use_hw_ss) 287 { 288 p_cb->use_hw_ss = p_config->use_hw_ss; 289 nrf_spim_csn_configure(p_spim, 290 p_config->ss_pin, 291 (p_config->ss_active_high == true ? 292 NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW), 293 p_config->ss_duration); 294 } 295 #endif 296 p_cb->ss_active_high = p_config->ss_active_high; 297 } 298 299 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 300 // - DCX (optional) - output. 301 if (p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED) 302 { 303 nrf_gpio_pin_set(p_config->dcx_pin); 304 nrf_gpio_cfg_output(p_config->dcx_pin); 305 nrf_spim_dcx_pin_set(p_spim, p_config->dcx_pin); 306 } 307 308 // Change rx delay 309 nrf_spim_iftiming_set(p_spim, p_config->rx_delay); 310 #endif 311 312 313 nrf_spim_pins_set(p_spim, p_config->sck_pin, mosi_pin, miso_pin); 314 nrf_spim_frequency_set(p_spim, p_config->frequency); 315 nrf_spim_configure(p_spim, p_config->mode, p_config->bit_order); 316 317 nrf_spim_orc_set(p_spim, p_config->orc); 318 319 if (p_cb->handler) 320 { 321 nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK); 322 } 323 324 nrf_spim_enable(p_spim); 325 326 if (p_cb->handler) 327 { 328 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), 329 p_config->irq_priority); 330 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg)); 331 } 332 333 p_cb->transfer_in_progress = false; 334 p_cb->state = NRFX_DRV_STATE_INITIALIZED; 335 336 err_code = NRFX_SUCCESS; 337 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 338 return err_code; 339 } 340 341 void nrfx_spim_uninit(nrfx_spim_t const * const p_instance) 342 { 343 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; 344 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); 345 346 if (p_cb->handler) 347 { 348 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg)); 349 } 350 351 NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; 352 if (p_cb->handler) 353 { 354 nrf_spim_int_disable(p_spim, NRF_SPIM_ALL_INTS_MASK); 355 if (p_cb->transfer_in_progress) 356 { 357 // Ensure that SPI is not performing any transfer. 358 nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP); 359 while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED)) 360 {} 361 p_cb->transfer_in_progress = false; 362 } 363 } 364 365 if (p_cb->miso_pin != NRFX_SPIM_PIN_NOT_USED) 366 { 367 nrf_gpio_cfg_default(p_cb->miso_pin); 368 } 369 nrf_spim_disable(p_spim); 370 371 #ifdef USE_WORKAROUND_FOR_ANOMALY_195 372 if (p_spim == NRF_SPIM3) 373 { 374 *(volatile uint32_t *)0x4002F004 = 1; 375 } 376 #endif 377 378 #if NRFX_CHECK(NRFX_PRS_ENABLED) 379 nrfx_prs_release(p_instance->p_reg); 380 #endif 381 382 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; 383 } 384 385 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 386 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * const p_instance, 387 nrfx_spim_xfer_desc_t const * p_xfer_desc, 388 uint32_t flags, 389 uint8_t cmd_length) 390 { 391 NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD); 392 nrf_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length); 393 return nrfx_spim_xfer(p_instance, p_xfer_desc, 0); 394 } 395 #endif 396 397 static void finish_transfer(spim_control_block_t * p_cb) 398 { 399 // If Slave Select signal is used, this is the time to deactivate it. 400 if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED) 401 { 402 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 403 if (!p_cb->use_hw_ss) 404 #endif 405 { 406 if (p_cb->ss_active_high) 407 { 408 nrf_gpio_pin_clear(p_cb->ss_pin); 409 } 410 else 411 { 412 nrf_gpio_pin_set(p_cb->ss_pin); 413 } 414 } 415 } 416 417 // By clearing this flag before calling the handler we allow subsequent 418 // transfers to be started directly from the handler function. 419 p_cb->transfer_in_progress = false; 420 421 p_cb->evt.type = NRFX_SPIM_EVENT_DONE; 422 p_cb->handler(&p_cb->evt, p_cb->p_context); 423 } 424 425 __STATIC_INLINE void spim_int_enable(NRF_SPIM_Type * p_spim, bool enable) 426 { 427 if (!enable) 428 { 429 nrf_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK); 430 } 431 else 432 { 433 nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK); 434 } 435 } 436 437 __STATIC_INLINE void spim_list_enable_handle(NRF_SPIM_Type * p_spim, uint32_t flags) 438 { 439 if (NRFX_SPIM_FLAG_TX_POSTINC & flags) 440 { 441 nrf_spim_tx_list_enable(p_spim); 442 } 443 else 444 { 445 nrf_spim_tx_list_disable(p_spim); 446 } 447 448 if (NRFX_SPIM_FLAG_RX_POSTINC & flags) 449 { 450 nrf_spim_rx_list_enable(p_spim); 451 } 452 else 453 { 454 nrf_spim_rx_list_disable(p_spim); 455 } 456 } 457 458 static nrfx_err_t spim_xfer(NRF_SPIM_Type * p_spim, 459 spim_control_block_t * p_cb, 460 nrfx_spim_xfer_desc_t const * p_xfer_desc, 461 uint32_t flags) 462 { 463 nrfx_err_t err_code; 464 // EasyDMA requires that transfer buffers are placed in Data RAM region; 465 // signal error if they are not. 466 if ((p_xfer_desc->p_tx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_tx_buffer)) || 467 (p_xfer_desc->p_rx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_rx_buffer))) 468 { 469 p_cb->transfer_in_progress = false; 470 err_code = NRFX_ERROR_INVALID_ADDR; 471 NRFX_LOG_WARNING("Function: %s, error code: %s.", 472 __func__, 473 NRFX_LOG_ERROR_STRING_GET(err_code)); 474 return err_code; 475 } 476 477 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) 478 p_cb->tx_length = 0; 479 p_cb->rx_length = 0; 480 #endif 481 482 nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length); 483 nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, p_xfer_desc->rx_length); 484 485 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) 486 if (p_spim == NRF_SPIM3) 487 { 488 anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length); 489 } 490 #endif 491 492 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END); 493 494 spim_list_enable_handle(p_spim, flags); 495 496 if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER)) 497 { 498 nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START); 499 } 500 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) 501 if (flags & NRFX_SPIM_FLAG_HOLD_XFER) 502 { 503 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED); 504 p_cb->tx_length = p_xfer_desc->tx_length; 505 p_cb->rx_length = p_xfer_desc->rx_length; 506 nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, 0); 507 nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, 0); 508 nrf_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK); 509 } 510 #endif 511 512 if (!p_cb->handler) 513 { 514 while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)){} 515 516 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) 517 if (p_spim == NRF_SPIM3) 518 { 519 anomaly_198_disable(); 520 } 521 #endif 522 if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED) 523 { 524 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 525 if (!p_cb->use_hw_ss) 526 #endif 527 { 528 if (p_cb->ss_active_high) 529 { 530 nrf_gpio_pin_clear(p_cb->ss_pin); 531 } 532 else 533 { 534 nrf_gpio_pin_set(p_cb->ss_pin); 535 } 536 } 537 } 538 } 539 else 540 { 541 spim_int_enable(p_spim, !(flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)); 542 } 543 err_code = NRFX_SUCCESS; 544 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 545 return err_code; 546 } 547 548 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const * const p_instance, 549 nrfx_spim_xfer_desc_t const * p_xfer_desc, 550 uint32_t flags) 551 { 552 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; 553 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); 554 NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0); 555 NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0); 556 NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx, 557 p_xfer_desc->rx_length, 558 p_xfer_desc->tx_length)); 559 560 nrfx_err_t err_code = NRFX_SUCCESS; 561 562 if (p_cb->transfer_in_progress) 563 { 564 err_code = NRFX_ERROR_BUSY; 565 NRFX_LOG_WARNING("Function: %s, error code: %s.", 566 __func__, 567 NRFX_LOG_ERROR_STRING_GET(err_code)); 568 return err_code; 569 } 570 else 571 { 572 if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER | 573 NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER))) 574 { 575 p_cb->transfer_in_progress = true; 576 } 577 } 578 579 p_cb->evt.xfer_desc = *p_xfer_desc; 580 581 if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED) 582 { 583 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) 584 if (!p_cb->use_hw_ss) 585 #endif 586 { 587 if (p_cb->ss_active_high) 588 { 589 nrf_gpio_pin_set(p_cb->ss_pin); 590 } 591 else 592 { 593 nrf_gpio_pin_clear(p_cb->ss_pin); 594 } 595 } 596 } 597 598 return spim_xfer(p_instance->p_reg, p_cb, p_xfer_desc, flags); 599 } 600 601 void nrfx_spim_abort(nrfx_spim_t const * p_instance) 602 { 603 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; 604 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); 605 606 nrf_spim_task_trigger(p_instance->p_reg, NRF_SPIM_TASK_STOP); 607 while (!nrf_spim_event_check(p_instance->p_reg, NRF_SPIM_EVENT_STOPPED)) 608 {} 609 p_cb->transfer_in_progress = false; 610 } 611 612 uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance) 613 { 614 NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; 615 return nrf_spim_task_address_get(p_spim, NRF_SPIM_TASK_START); 616 } 617 618 uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance) 619 { 620 NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; 621 return nrf_spim_event_address_get(p_spim, NRF_SPIM_EVENT_END); 622 } 623 624 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb) 625 { 626 627 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) 628 if ((nrf_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK)) && 629 (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED)) ) 630 { 631 /* Handle first, zero-length, auxiliary transmission. */ 632 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED); 633 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END); 634 635 NRFX_ASSERT(p_spim->TXD.MAXCNT == 0); 636 p_spim->TXD.MAXCNT = p_cb->tx_length; 637 638 NRFX_ASSERT(p_spim->RXD.MAXCNT == 0); 639 p_spim->RXD.MAXCNT = p_cb->rx_length; 640 641 /* Disable STARTED interrupt, used only in auxiliary transmission. */ 642 nrf_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK); 643 644 /* Start the actual, glitch-free transmission. */ 645 nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START); 646 return; 647 } 648 #endif 649 650 if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)) 651 { 652 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) 653 if (p_spim == NRF_SPIM3) 654 { 655 anomaly_198_disable(); 656 } 657 #endif 658 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END); 659 NRFX_ASSERT(p_cb->handler); 660 NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END."); 661 finish_transfer(p_cb); 662 } 663 } 664 665 #if NRFX_CHECK(NRFX_SPIM0_ENABLED) 666 void nrfx_spim_0_irq_handler(void) 667 { 668 irq_handler(NRF_SPIM0, &m_cb[NRFX_SPIM0_INST_IDX]); 669 } 670 #endif 671 672 #if NRFX_CHECK(NRFX_SPIM1_ENABLED) 673 void nrfx_spim_1_irq_handler(void) 674 { 675 irq_handler(NRF_SPIM1, &m_cb[NRFX_SPIM1_INST_IDX]); 676 } 677 #endif 678 679 #if NRFX_CHECK(NRFX_SPIM2_ENABLED) 680 void nrfx_spim_2_irq_handler(void) 681 { 682 irq_handler(NRF_SPIM2, &m_cb[NRFX_SPIM2_INST_IDX]); 683 } 684 #endif 685 686 #if NRFX_CHECK(NRFX_SPIM3_ENABLED) 687 void nrfx_spim_3_irq_handler(void) 688 { 689 irq_handler(NRF_SPIM3, &m_cb[NRFX_SPIM3_INST_IDX]); 690 } 691 #endif 692 693 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED) 694