1 /* 2 * Copyright (c) 2013 - 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_SPIS_ENABLED) 35 36 #if !(NRFX_CHECK(NRFX_SPIS0_ENABLED) || \ 37 NRFX_CHECK(NRFX_SPIS1_ENABLED) || \ 38 NRFX_CHECK(NRFX_SPIS2_ENABLED) || \ 39 NRFX_CHECK(NRFX_SPIS3_ENABLED)) 40 #error "No enabled SPIS instances. Check <nrfx_config.h>." 41 #endif 42 43 #include <nrfx_spis.h> 44 #include "prs/nrfx_prs.h" 45 46 #define NRFX_LOG_MODULE SPIS 47 #include <nrfx_log.h> 48 49 #define EVT_TO_STR(event) \ 50 (event == NRF_SPIS_EVENT_ACQUIRED ? "NRF_SPIS_EVENT_ACQUIRED" : \ 51 (event == NRF_SPIS_EVENT_END ? "NRF_SPIS_EVENT_END" : \ 52 "UNKNOWN ERROR")) 53 54 #define SPISX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \ 55 (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \ 56 NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len)) 57 58 #if NRFX_CHECK(NRFX_SPIS0_ENABLED) 59 #define SPIS0_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS0, __VA_ARGS__) 60 #else 61 #define SPIS0_LENGTH_VALIDATE(...) 0 62 #endif 63 64 #if NRFX_CHECK(NRFX_SPIS1_ENABLED) 65 #define SPIS1_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS1, __VA_ARGS__) 66 #else 67 #define SPIS1_LENGTH_VALIDATE(...) 0 68 #endif 69 70 #if NRFX_CHECK(NRFX_SPIS2_ENABLED) 71 #define SPIS2_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS2, __VA_ARGS__) 72 #else 73 #define SPIS2_LENGTH_VALIDATE(...) 0 74 #endif 75 76 #if NRFX_CHECK(NRFX_SPIS3_ENABLED) 77 #define SPIS3_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS3, __VA_ARGS__) 78 #else 79 #define SPIS3_LENGTH_VALIDATE(...) 0 80 #endif 81 82 #define SPIS_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \ 83 (SPIS0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ 84 SPIS1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ 85 SPIS2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ 86 SPIS3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)) 87 88 89 #if NRFX_CHECK(NRFX_SPIS_NRF52_ANOMALY_109_WORKAROUND_ENABLED) 90 #include <nrfx_gpiote.h> 91 #define USE_DMA_ISSUE_WORKAROUND 92 // This handler is called by the GPIOTE driver when a falling edge is detected 93 // on the CSN line. There is no need to do anything here. The handling of the 94 // interrupt itself provides a protection for DMA transfers. 95 static void csn_event_handler(nrfx_gpiote_pin_t pin, 96 nrf_gpiote_polarity_t action) 97 { 98 } 99 #endif 100 101 102 /**@brief States of the SPI transaction state machine. */ 103 typedef enum 104 { 105 SPIS_STATE_INIT, /**< Initialization state. In this state the module waits for a call to @ref spi_slave_buffers_set. */ 106 SPIS_BUFFER_RESOURCE_REQUESTED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has started. */ 107 SPIS_BUFFER_RESOURCE_CONFIGURED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has completed. */ 108 SPIS_XFER_COMPLETED /**< State where SPI transaction has been completed. */ 109 } nrfx_spis_state_t; 110 111 /**@brief SPIS control block - driver instance local data. */ 112 typedef struct 113 { 114 volatile uint32_t tx_buffer_size; //!< SPI slave TX buffer size in bytes. 115 volatile uint32_t rx_buffer_size; //!< SPI slave RX buffer size in bytes. 116 nrfx_spis_event_handler_t handler; //!< SPI event handler. 117 volatile const uint8_t * tx_buffer; //!< SPI slave TX buffer. 118 volatile uint8_t * rx_buffer; //!< SPI slave RX buffer. 119 nrfx_drv_state_t state; //!< driver initialization state. 120 volatile nrfx_spis_state_t spi_state; //!< SPI slave state. 121 void * p_context; //!< Context set on initialization. 122 } spis_cb_t; 123 124 static spis_cb_t m_cb[NRFX_SPIS_ENABLED_COUNT]; 125 126 nrfx_err_t nrfx_spis_init(nrfx_spis_t const * const p_instance, 127 nrfx_spis_config_t const * p_config, 128 nrfx_spis_event_handler_t event_handler, 129 void * p_context) 130 { 131 NRFX_ASSERT(p_config); 132 NRFX_ASSERT(event_handler); 133 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx]; 134 nrfx_err_t err_code; 135 136 NRF_SPIS_Type * p_spis = p_instance->p_reg; 137 138 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED) 139 { 140 err_code = NRFX_ERROR_INVALID_STATE; 141 NRFX_LOG_WARNING("Function: %s, error code: %s.", 142 __func__, 143 NRFX_LOG_ERROR_STRING_GET(err_code)); 144 return err_code; 145 } 146 147 if ((uint32_t)p_config->mode > (uint32_t)NRF_SPIS_MODE_3) 148 { 149 err_code = NRFX_ERROR_INVALID_PARAM; 150 NRFX_LOG_WARNING("Function: %s, error code: %s.", 151 __func__, 152 NRFX_LOG_ERROR_STRING_GET(err_code)); 153 return err_code; 154 } 155 #if NRFX_CHECK(NRFX_PRS_ENABLED) 156 static nrfx_irq_handler_t const irq_handlers[NRFX_SPIS_ENABLED_COUNT] = { 157 #if NRFX_CHECK(NRFX_SPIS0_ENABLED) 158 nrfx_spis_0_irq_handler, 159 #endif 160 #if NRFX_CHECK(NRFX_SPIS1_ENABLED) 161 nrfx_spis_1_irq_handler, 162 #endif 163 #if NRFX_CHECK(NRFX_SPIS2_ENABLED) 164 nrfx_spis_2_irq_handler, 165 #endif 166 #if NRFX_CHECK(NRFX_SPIS3_ENABLED) 167 nrfx_spis_3_irq_handler, 168 #endif 169 }; 170 if (nrfx_prs_acquire(p_spis, 171 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS) 172 { 173 err_code = NRFX_ERROR_BUSY; 174 NRFX_LOG_WARNING("Function: %s, error code: %s.", 175 __func__, 176 NRFX_LOG_ERROR_STRING_GET(err_code)); 177 return err_code; 178 } 179 #endif // NRFX_CHECK(NRFX_PRS_ENABLED) 180 181 // Configure the SPI pins for input. 182 uint32_t mosi_pin; 183 uint32_t miso_pin; 184 185 if (p_config->miso_pin != NRFX_SPIS_PIN_NOT_USED) 186 { 187 nrf_gpio_cfg(p_config->miso_pin, 188 NRF_GPIO_PIN_DIR_INPUT, 189 NRF_GPIO_PIN_INPUT_CONNECT, 190 NRF_GPIO_PIN_NOPULL, 191 p_config->miso_drive, 192 NRF_GPIO_PIN_NOSENSE); 193 miso_pin = p_config->miso_pin; 194 } 195 else 196 { 197 miso_pin = NRF_SPIS_PIN_NOT_CONNECTED; 198 } 199 200 if (p_config->mosi_pin != NRFX_SPIS_PIN_NOT_USED) 201 { 202 nrf_gpio_cfg(p_config->mosi_pin, 203 NRF_GPIO_PIN_DIR_INPUT, 204 NRF_GPIO_PIN_INPUT_CONNECT, 205 NRF_GPIO_PIN_NOPULL, 206 NRF_GPIO_PIN_S0S1, 207 NRF_GPIO_PIN_NOSENSE); 208 mosi_pin = p_config->mosi_pin; 209 } 210 else 211 { 212 mosi_pin = NRF_SPIS_PIN_NOT_CONNECTED; 213 } 214 215 nrf_gpio_cfg(p_config->csn_pin, 216 NRF_GPIO_PIN_DIR_INPUT, 217 NRF_GPIO_PIN_INPUT_CONNECT, 218 p_config->csn_pullup, 219 NRF_GPIO_PIN_S0S1, 220 NRF_GPIO_PIN_NOSENSE); 221 222 nrf_gpio_cfg(p_config->sck_pin, 223 NRF_GPIO_PIN_DIR_INPUT, 224 NRF_GPIO_PIN_INPUT_CONNECT, 225 NRF_GPIO_PIN_NOPULL, 226 NRF_GPIO_PIN_S0S1, 227 NRF_GPIO_PIN_NOSENSE); 228 229 nrf_spis_pins_set(p_spis, p_config->sck_pin, mosi_pin, miso_pin, p_config->csn_pin); 230 231 nrf_spis_rx_buffer_set(p_spis, NULL, 0); 232 nrf_spis_tx_buffer_set(p_spis, NULL, 0); 233 234 // Configure SPI mode. 235 nrf_spis_configure(p_spis, p_config->mode, p_config->bit_order); 236 237 // Configure DEF and ORC characters. 238 nrf_spis_def_set(p_spis, p_config->def); 239 nrf_spis_orc_set(p_spis, p_config->orc); 240 241 // Clear possible pending events. 242 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END); 243 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED); 244 245 // Enable END_ACQUIRE shortcut. 246 nrf_spis_shorts_enable(p_spis, NRF_SPIS_SHORT_END_ACQUIRE); 247 248 p_cb->spi_state = SPIS_STATE_INIT; 249 p_cb->handler = event_handler; 250 p_cb->p_context = p_context; 251 252 #if defined(USE_DMA_ISSUE_WORKAROUND) 253 // Configure a GPIOTE channel to generate interrupts on each falling edge 254 // on the CSN line. Handling of these interrupts will make the CPU active, 255 // and thus will protect the DMA transfers started by SPIS right after it 256 // is selected for communication. 257 // [the GPIOTE driver may be already initialized at this point (by this 258 // driver when another SPIS instance is used, or by an application code), 259 // so just ignore the returned value] 260 (void)nrfx_gpiote_init(); 261 static nrfx_gpiote_in_config_t const csn_gpiote_config = 262 NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true); 263 nrfx_err_t gpiote_err_code = nrfx_gpiote_in_init(p_config->csn_pin, 264 &csn_gpiote_config, csn_event_handler); 265 if (gpiote_err_code != NRFX_SUCCESS) 266 { 267 err_code = NRFX_ERROR_INTERNAL; 268 NRFX_LOG_INFO("Function: %s, error code: %s.", 269 __func__, 270 NRFX_LOG_ERROR_STRING_GET(err_code)); 271 return err_code; 272 } 273 nrfx_gpiote_in_event_enable(p_config->csn_pin, true); 274 #endif 275 276 // Enable IRQ. 277 nrf_spis_int_enable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK | 278 NRF_SPIS_INT_END_MASK); 279 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), 280 p_config->irq_priority); 281 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg)); 282 283 p_cb->state = NRFX_DRV_STATE_INITIALIZED; 284 285 // Enable SPI slave device. 286 nrf_spis_enable(p_spis); 287 288 NRFX_LOG_INFO("Initialized."); 289 return NRFX_SUCCESS; 290 } 291 292 293 void nrfx_spis_uninit(nrfx_spis_t const * const p_instance) 294 { 295 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx]; 296 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); 297 298 NRF_SPIS_Type * p_spis = p_instance->p_reg; 299 300 #define DISABLE_ALL 0xFFFFFFFF 301 nrf_spis_disable(p_spis); 302 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg)); 303 nrf_spis_int_disable(p_spis, DISABLE_ALL); 304 #undef DISABLE_ALL 305 306 #if NRFX_CHECK(NRFX_PRS_ENABLED) 307 nrfx_prs_release(p_spis); 308 #endif 309 310 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; 311 NRFX_LOG_INFO("Uninitialized."); 312 } 313 314 315 /**@brief Function for executing the state entry action. */ 316 static void spis_state_entry_action_execute(NRF_SPIS_Type * p_spis, 317 spis_cb_t * p_cb) 318 { 319 nrfx_spis_evt_t event; 320 321 switch (p_cb->spi_state) 322 { 323 case SPIS_BUFFER_RESOURCE_REQUESTED: 324 nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_ACQUIRE); 325 break; 326 327 case SPIS_BUFFER_RESOURCE_CONFIGURED: 328 event.evt_type = NRFX_SPIS_BUFFERS_SET_DONE; 329 event.rx_amount = 0; 330 event.tx_amount = 0; 331 332 NRFX_ASSERT(p_cb->handler != NULL); 333 p_cb->handler(&event, p_cb->p_context); 334 break; 335 336 case SPIS_XFER_COMPLETED: 337 event.evt_type = NRFX_SPIS_XFER_DONE; 338 event.rx_amount = nrf_spis_rx_amount_get(p_spis); 339 event.tx_amount = nrf_spis_tx_amount_get(p_spis); 340 NRFX_LOG_INFO("Transfer rx_len:%d.", event.rx_amount); 341 NRFX_LOG_DEBUG("Rx data:"); 342 NRFX_LOG_HEXDUMP_DEBUG((uint8_t const *)p_cb->rx_buffer, 343 event.rx_amount * sizeof(p_cb->rx_buffer[0])); 344 NRFX_ASSERT(p_cb->handler != NULL); 345 p_cb->handler(&event, p_cb->p_context); 346 break; 347 348 default: 349 // No implementation required. 350 break; 351 } 352 } 353 354 /**@brief Function for changing the state of the SPI state machine. 355 * 356 * @param[in] p_spis SPIS instance register. 357 * @param[in] p_cb SPIS instance control block. 358 * @param[in] new_state State where the state machine transits to. 359 */ 360 static void spis_state_change(NRF_SPIS_Type * p_spis, 361 spis_cb_t * p_cb, 362 nrfx_spis_state_t new_state) 363 { 364 p_cb->spi_state = new_state; 365 spis_state_entry_action_execute(p_spis, p_cb); 366 } 367 368 nrfx_err_t nrfx_spis_buffers_set(nrfx_spis_t const * const p_instance, 369 uint8_t const * p_tx_buffer, 370 size_t tx_buffer_length, 371 uint8_t * p_rx_buffer, 372 size_t rx_buffer_length) 373 { 374 NRFX_ASSERT(p_tx_buffer != NULL || tx_buffer_length == 0); 375 NRFX_ASSERT(p_rx_buffer != NULL || rx_buffer_length == 0); 376 377 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx]; 378 nrfx_err_t err_code; 379 380 if (!SPIS_LENGTH_VALIDATE(p_instance->drv_inst_idx, 381 rx_buffer_length, 382 tx_buffer_length)) 383 { 384 return NRFX_ERROR_INVALID_LENGTH; 385 } 386 387 // EasyDMA requires that transfer buffers are placed in Data RAM region; 388 // signal error if they are not. 389 if ((p_tx_buffer != NULL && !nrfx_is_in_ram(p_tx_buffer)) || 390 (p_rx_buffer != NULL && !nrfx_is_in_ram(p_rx_buffer))) 391 { 392 err_code = NRFX_ERROR_INVALID_ADDR; 393 NRFX_LOG_WARNING("Function: %s, error code: %s.", 394 __func__, 395 NRFX_LOG_ERROR_STRING_GET(err_code)); 396 return err_code; 397 } 398 399 switch (p_cb->spi_state) 400 { 401 case SPIS_STATE_INIT: 402 case SPIS_XFER_COMPLETED: 403 case SPIS_BUFFER_RESOURCE_CONFIGURED: 404 p_cb->tx_buffer = p_tx_buffer; 405 p_cb->rx_buffer = p_rx_buffer; 406 p_cb->tx_buffer_size = tx_buffer_length; 407 p_cb->rx_buffer_size = rx_buffer_length; 408 err_code = NRFX_SUCCESS; 409 410 spis_state_change(p_instance->p_reg, p_cb, SPIS_BUFFER_RESOURCE_REQUESTED); 411 break; 412 413 case SPIS_BUFFER_RESOURCE_REQUESTED: 414 err_code = NRFX_ERROR_INVALID_STATE; 415 break; 416 417 default: 418 // @note: execution of this code path would imply internal error in the design. 419 err_code = NRFX_ERROR_INTERNAL; 420 break; 421 } 422 423 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 424 return err_code; 425 } 426 427 static void spis_irq_handler(NRF_SPIS_Type * p_spis, spis_cb_t * p_cb) 428 { 429 // @note: as multiple events can be pending for processing, the correct event processing order 430 // is as follows: 431 // - SPI semaphore acquired event. 432 // - SPI transaction complete event. 433 434 // Check for SPI semaphore acquired event. 435 if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_ACQUIRED)) 436 { 437 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED); 438 NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_ACQUIRED)); 439 440 switch (p_cb->spi_state) 441 { 442 case SPIS_BUFFER_RESOURCE_REQUESTED: 443 nrf_spis_tx_buffer_set(p_spis, (uint8_t *)p_cb->tx_buffer, p_cb->tx_buffer_size); 444 nrf_spis_rx_buffer_set(p_spis, (uint8_t *)p_cb->rx_buffer, p_cb->rx_buffer_size); 445 446 nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_RELEASE); 447 448 spis_state_change(p_spis, p_cb, SPIS_BUFFER_RESOURCE_CONFIGURED); 449 break; 450 451 default: 452 // No implementation required. 453 break; 454 } 455 } 456 457 // Check for SPI transaction complete event. 458 if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_END)) 459 { 460 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END); 461 NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_END)); 462 463 switch (p_cb->spi_state) 464 { 465 case SPIS_BUFFER_RESOURCE_CONFIGURED: 466 spis_state_change(p_spis, p_cb, SPIS_XFER_COMPLETED); 467 break; 468 469 default: 470 // No implementation required. 471 break; 472 } 473 } 474 } 475 476 #if NRFX_CHECK(NRFX_SPIS0_ENABLED) 477 void nrfx_spis_0_irq_handler(void) 478 { 479 spis_irq_handler(NRF_SPIS0, &m_cb[NRFX_SPIS0_INST_IDX]); 480 } 481 #endif 482 483 #if NRFX_CHECK(NRFX_SPIS1_ENABLED) 484 void nrfx_spis_1_irq_handler(void) 485 { 486 spis_irq_handler(NRF_SPIS1, &m_cb[NRFX_SPIS1_INST_IDX]); 487 } 488 #endif 489 490 #if NRFX_CHECK(NRFX_SPIS2_ENABLED) 491 void nrfx_spis_2_irq_handler(void) 492 { 493 spis_irq_handler(NRF_SPIS2, &m_cb[NRFX_SPIS2_INST_IDX]); 494 } 495 #endif 496 497 #if NRFX_CHECK(NRFX_SPIS3_ENABLED) 498 void nrfx_spis_3_irq_handler(void) 499 { 500 spis_irq_handler(NRF_SPIS3, &m_cb[NRFX_SPIS3_INST_IDX]); 501 } 502 #endif 503 504 #endif // NRFX_CHECK(NRFX_SPIS_ENABLED) 505