1 /* 2 * Copyright (c) 2015 - 2021, 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 #ifndef NRFX_SPIM_H__ 35 #define NRFX_SPIM_H__ 36 37 #include <stdint.h> 38 #include <string.h> 39 #include "board.h" 40 #include "rtconfig.h" 41 42 #include <nrfx.h> 43 #include <hal/nrf_spim.h> 44 #include <hal/nrf_gpio.h> 45 46 #ifdef __cplusplus 47 extern "C" { 48 #endif 49 50 /** 51 * @defgroup nrfx_spim SPIM driver 52 * @{ 53 * @ingroup nrf_spim 54 * @brief Serial Peripheral Interface Master with EasyDMA (SPIM) driver. 55 */ 56 57 /** @brief Data structure of the Serial Peripheral Interface Master with EasyDMA (SPIM) driver instance. */ 58 typedef struct 59 { 60 NRF_SPIM_Type * p_reg; /* /< Pointer to a structure with SPIM registers. */ 61 uint8_t drv_inst_idx; /* /< Index of the driver instance. For internal use only. */ 62 } nrfx_spim_t; 63 64 #ifndef __NRFX_DOXYGEN__ 65 enum { 66 #if NRFX_CHECK(NRFX_SPIM0_ENABLED) 67 NRFX_SPIM0_INST_IDX, 68 #endif 69 #if NRFX_CHECK(NRFX_SPIM1_ENABLED) 70 NRFX_SPIM1_INST_IDX, 71 #endif 72 #if NRFX_CHECK(NRFX_SPIM2_ENABLED) 73 NRFX_SPIM2_INST_IDX, 74 #endif 75 #if NRFX_CHECK(NRFX_SPIM3_ENABLED) 76 NRFX_SPIM3_INST_IDX, 77 #endif 78 #if NRFX_CHECK(NRFX_SPIM4_ENABLED) 79 NRFX_SPIM4_INST_IDX, 80 #endif 81 NRFX_SPIM_ENABLED_COUNT 82 }; 83 #endif 84 85 /** @brief Macro for creating an instance of the SPIM driver. */ 86 #define NRFX_SPIM_INSTANCE(id) \ 87 { \ 88 .p_reg = NRFX_CONCAT_2(NRF_SPIM, id), \ 89 .drv_inst_idx = NRFX_CONCAT_3(NRFX_SPIM, id, _INST_IDX), \ 90 } 91 92 /** 93 * @brief This value can be provided instead of a pin number for signals MOSI, 94 * MISO, and Slave Select to specify that the given signal is not used and 95 * therefore does not need to be connected to a pin. 96 */ 97 #define NRFX_SPIM_PIN_NOT_USED 0xFF 98 99 /** @brief Configuration structure of the SPIM driver instance. */ 100 typedef struct 101 { 102 uint8_t sck_pin; /* /< SCK pin number. */ 103 uint8_t mosi_pin; /* /< MOSI pin number (optional). */ 104 /**< Set to @ref NRFX_SPIM_PIN_NOT_USED 105 * if this signal is not needed. */ 106 uint8_t miso_pin; /* /< MISO pin number (optional). */ 107 /**< Set to @ref NRFX_SPIM_PIN_NOT_USED 108 * if this signal is not needed. */ 109 uint8_t ss_pin; /* /< Slave Select pin number (optional). */ 110 /**< Set to @ref NRFX_SPIM_PIN_NOT_USED 111 * if this signal is not needed. */ 112 bool ss_active_high; /* /< Polarity of the Slave Select pin during transmission. */ 113 uint8_t irq_priority; /* /< Interrupt priority. */ 114 uint8_t orc; /* /< Overrun character. */ 115 /**< This character is used when all bytes from the TX buffer are sent, 116 but the transfer continues due to RX. */ 117 nrf_spim_frequency_t frequency; /* /< SPIM frequency. */ 118 nrf_spim_mode_t mode; /* /< SPIM mode. */ 119 nrf_spim_bit_order_t bit_order; /* /< SPIM bit order. */ 120 nrf_gpio_pin_pull_t miso_pull; /* /< MISO pull up configuration. */ 121 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) || defined(__NRFX_DOXYGEN__) 122 uint8_t dcx_pin; /* /< D/CX pin number (optional). */ 123 uint8_t rx_delay; /* /< Sample delay for input serial data on MISO. */ 124 /**< The value specifies the delay, in number of 64 MHz clock cycles 125 * (15.625 ns), from the the sampling edge of SCK (leading edge for 126 * CONFIG.CPHA = 0, trailing edge for CONFIG.CPHA = 1) until 127 * the input serial data is sampled. */ 128 bool use_hw_ss; /* /< Indication to use software or hardware controlled Slave Select pin. */ 129 uint8_t ss_duration; /* /< Slave Select duration before and after transmission. */ 130 /**< Minimum duration between the edge of CSN and the edge of SCK. 131 * Also, minimum duration of CSN inactivity between transactions. 132 * The value is specified in number of 64 MHz clock cycles (15.625 ns). 133 * Supported only for hardware-controlled Slave Select. */ 134 #endif 135 } nrfx_spim_config_t; 136 137 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) || defined(__NRFX_DOXYGEN__) 138 /** 139 * @brief SPIM driver extended default configuration. 140 * 141 * This configuration sets up SPIM additional options with the following values: 142 * - DCX pin disabled 143 * - RX sampling delay: 2 clock cycles 144 * - hardware SS disabled 145 * - hardware SS duration before and after transmission: 2 clock cycles 146 */ 147 #define NRFX_SPIM_DEFAULT_EXTENDED_CONFIG \ 148 .dcx_pin = NRFX_SPIM_PIN_NOT_USED, \ 149 .rx_delay = 0x02, \ 150 .use_hw_ss = false, \ 151 .ss_duration = 0x02, 152 #else 153 #define NRFX_SPIM_DEFAULT_EXTENDED_CONFIG 154 #endif 155 156 /** 157 * @brief SPIM driver default configuration. 158 * 159 * This configuration sets up SPIM with the following options: 160 * - SS pin active low 161 * - over-run character set to 0xFF 162 * - clock frequency: 4 MHz 163 * - mode: 0 (SCK active high, sample on leading edge of the clock signal;) 164 * - MSB shifted out first 165 * - MISO pull-up disabled 166 * 167 * @param[in] _pin_sck SCK pin. 168 * @param[in] _pin_mosi MOSI pin. 169 * @param[in] _pin_miso MISO pin. 170 * @param[in] _pin_ss SS pin. 171 */ 172 #define NRFX_SPIM_DEFAULT_CONFIG(_pin_sck, _pin_mosi, _pin_miso, _pin_ss) \ 173 { \ 174 .sck_pin = _pin_sck, \ 175 .mosi_pin = _pin_mosi, \ 176 .miso_pin = _pin_miso, \ 177 .ss_pin = _pin_ss, \ 178 .ss_active_high = false, \ 179 .irq_priority = NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY, \ 180 .orc = 0xFF, \ 181 .frequency = NRF_SPIM_FREQ_4M, \ 182 .mode = NRF_SPIM_MODE_0, \ 183 .bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST, \ 184 .miso_pull = NRF_GPIO_PIN_NOPULL, \ 185 NRFX_SPIM_DEFAULT_EXTENDED_CONFIG \ 186 } 187 188 /** @brief Flag indicating that TX buffer address will be incremented after transfer. */ 189 #define NRFX_SPIM_FLAG_TX_POSTINC (1UL << 0) 190 /** @brief Flag indicating that RX buffer address will be incremented after transfer. */ 191 #define NRFX_SPIM_FLAG_RX_POSTINC (1UL << 1) 192 /** @brief Flag indicating that the interrupt after each transfer will be suppressed, and the event handler will not be called. */ 193 #define NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER (1UL << 2) 194 /** @brief Flag indicating that the transfer will be set up, but not started. */ 195 #define NRFX_SPIM_FLAG_HOLD_XFER (1UL << 3) 196 /** @brief Flag indicating that the transfer will be executed multiple times. */ 197 #define NRFX_SPIM_FLAG_REPEATED_XFER (1UL << 4) 198 199 /** @brief Single transfer descriptor structure. */ 200 typedef struct 201 { 202 uint8_t const * p_tx_buffer; /* /< Pointer to TX buffer. */ 203 size_t tx_length; /* /< TX buffer length. */ 204 uint8_t * p_rx_buffer; /* /< Pointer to RX buffer. */ 205 size_t rx_length; /* /< RX buffer length. */ 206 } nrfx_spim_xfer_desc_t; 207 208 /** 209 * @brief Macro for setting up single transfer descriptor. 210 * 211 * This macro is for internal use only. 212 */ 213 #define NRFX_SPIM_SINGLE_XFER(p_tx, tx_len, p_rx, rx_len) \ 214 { \ 215 .p_tx_buffer = (uint8_t const *)(p_tx), \ 216 .tx_length = (tx_len), \ 217 .p_rx_buffer = (p_rx), \ 218 .rx_length = (rx_len), \ 219 } 220 221 /** @brief Macro for setting the duplex TX RX transfer. */ 222 #define NRFX_SPIM_XFER_TRX(p_tx_buf, tx_length, p_rx_buf, rx_length) \ 223 NRFX_SPIM_SINGLE_XFER(p_tx_buf, tx_length, p_rx_buf, rx_length) 224 225 /** @brief Macro for setting the TX transfer. */ 226 #define NRFX_SPIM_XFER_TX(p_buf, length) \ 227 NRFX_SPIM_SINGLE_XFER(p_buf, length, NULL, 0) 228 229 /** @brief Macro for setting the RX transfer. */ 230 #define NRFX_SPIM_XFER_RX(p_buf, length) \ 231 NRFX_SPIM_SINGLE_XFER(NULL, 0, p_buf, length) 232 233 /** 234 * @brief SPIM master driver event types, passed to the handler routine provided 235 * during initialization. 236 */ 237 typedef enum 238 { 239 NRFX_SPIM_EVENT_DONE, /* /< Transfer done. */ 240 } nrfx_spim_evt_type_t; 241 242 /** @brief SPIM event description with transmission details. */ 243 typedef struct 244 { 245 nrfx_spim_evt_type_t type; /* /< Event type. */ 246 nrfx_spim_xfer_desc_t xfer_desc; /* /< Transfer details. */ 247 } nrfx_spim_evt_t; 248 249 /** @brief SPIM driver event handler type. */ 250 typedef void (* nrfx_spim_evt_handler_t)(nrfx_spim_evt_t const * p_event, 251 void * p_context); 252 253 /** 254 * @brief Function for initializing the SPIM driver instance. 255 * 256 * This function configures and enables the specified peripheral. 257 * 258 * @param[in] p_instance Pointer to the driver instance structure. 259 * @param[in] p_config Pointer to the structure with the initial configuration. 260 * @param[in] handler Event handler provided by the user. If NULL, transfers 261 * will be performed in blocking mode. 262 * @param[in] p_context Context passed to event handler. 263 * 264 * @warning On nRF5340, 32 MHz setting for SPIM4 peripheral instance is supported 265 * only on the dedicated pins with @ref NRF_GPIO_PIN_MCUSEL_PERIPHERAL configuration. 266 * See the chapter <a href=@nRF5340pinAssignmentsURL>Pin assignments</a> in the Product Specification. 267 * 268 * @retval NRFX_SUCCESS Initialization was successful. 269 * @retval NRFX_ERROR_INVALID_STATE The driver was already initialized. 270 * @retval NRFX_ERROR_BUSY Some other peripheral with the same 271 * instance ID is already in use. This is 272 * possible only if @ref nrfx_prs module 273 * is enabled. 274 * @retval NRFX_ERROR_NOT_SUPPORTED Requested configuration is not supported 275 * by the SPIM instance. 276 * @retval NRFX_ERROR_INVALID_PARAM Requested frequency is not available on the specified pins. 277 */ 278 nrfx_err_t nrfx_spim_init(nrfx_spim_t const * p_instance, 279 nrfx_spim_config_t const * p_config, 280 nrfx_spim_evt_handler_t handler, 281 void * p_context); 282 283 /** 284 * @brief Function for uninitializing the SPIM driver instance. 285 * 286 * @param[in] p_instance Pointer to the driver instance structure. 287 */ 288 void nrfx_spim_uninit(nrfx_spim_t const * p_instance); 289 290 /** 291 * @brief Function for starting the SPIM data transfer. 292 * 293 * Additional options are provided using the @c flags parameter: 294 * 295 * - @ref NRFX_SPIM_FLAG_TX_POSTINC and @ref NRFX_SPIM_FLAG_RX_POSTINC - 296 * Post-incrementation of buffer addresses. 297 * - @ref NRFX_SPIM_FLAG_HOLD_XFER - Driver is not starting the transfer. Use this 298 * flag if the transfer is triggered externally by PPI. Use 299 * @ref nrfx_spim_start_task_get to get the address of the start task. 300 * Chip select must be configured to @ref NRFX_SPIM_PIN_NOT_USED and managed outside the driver. 301 * - @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER - No user event handler after transfer 302 * completion. This also means no interrupt at the end of the transfer. 303 * If @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER is used, the driver does not set the instance into 304 * busy state, so you must ensure that the next transfers are set up when SPIM is not active. 305 * @ref nrfx_spim_end_event_get function can be used to detect end of transfer. Option can be used 306 * together with @ref NRFX_SPIM_FLAG_REPEATED_XFER to prepare a sequence of SPI transfers 307 * without interruptions. 308 * - @ref NRFX_SPIM_FLAG_REPEATED_XFER - Prepare for repeated transfers. You can set 309 * up a number of transfers that will be triggered externally (for example by PPI). An example is 310 * a TXRX transfer with the options @ref NRFX_SPIM_FLAG_RX_POSTINC, 311 * @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER, and @ref NRFX_SPIM_FLAG_REPEATED_XFER. After the 312 * transfer is set up, a set of transfers can be triggered by PPI that will read, for example, 313 * the same register of an external component and put it into a RAM buffer without any interrupts. 314 * @ref nrfx_spim_end_event_get can be used to get the address of the END event, which can be 315 * used to count the number of transfers. If @ref NRFX_SPIM_FLAG_REPEATED_XFER is used, 316 * the driver does not set the instance into busy state, so you must ensure that the next 317 * transfers are set up when SPIM is not active. 318 * 319 * @note Peripherals using EasyDMA (including SPIM) require the transfer buffers 320 * to be placed in the Data RAM region. If this condition is not met, 321 * this function will fail with the error code NRFX_ERROR_INVALID_ADDR. 322 * 323 * @param p_instance Pointer to the driver instance structure. 324 * @param p_xfer_desc Pointer to the transfer descriptor. 325 * @param flags Transfer options (0 for default settings). 326 * 327 * @retval NRFX_SUCCESS The procedure is successful. 328 * @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer. 329 * @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported. 330 * @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed in the Data 331 * RAM region. 332 */ 333 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const * p_instance, 334 nrfx_spim_xfer_desc_t const * p_xfer_desc, 335 uint32_t flags); 336 337 nrfx_err_t rtt_nrfx_spim_xfer(nrfx_spim_t const * p_instance, 338 nrfx_spim_xfer_desc_t const * p_xfer_desc, 339 uint32_t flags, 340 struct rt_spi_message * message, 341 struct rt_spi_device * dev); 342 343 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) || defined(__NRFX_DOXYGEN__) 344 /** 345 * @brief Function for starting the SPIM data transfer with DCX control. 346 * 347 * See @ref nrfx_spim_xfer for description of additional options of transfer 348 * provided by the @c flags parameter. 349 * 350 * @note Peripherals that use EasyDMA (including SPIM) require the transfer buffers 351 * to be placed in the Data RAM region. If this condition is not met, 352 * this function will fail with the error code NRFX_ERROR_INVALID_ADDR. 353 * 354 * @param p_instance Pointer to the driver instance structure. 355 * @param p_xfer_desc Pointer to the transfer descriptor. 356 * @param flags Transfer options (0 for default settings). 357 * @param cmd_length Length of the command bytes preceding the data 358 * bytes. The DCX line will be low during transmission 359 * of command bytes and high during transmission of data bytes. 360 * Maximum value available for dividing the transmitted bytes 361 * into command bytes and data bytes is @ref NRF_SPIM_DCX_CNT_ALL_CMD - 1. 362 * The @ref NRF_SPIM_DCX_CNT_ALL_CMD value passed as the 363 * @c cmd_length parameter causes all transmitted bytes 364 * to be marked as command bytes. 365 * 366 * @retval NRFX_SUCCESS The procedure is successful. 367 * @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer. 368 * @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported. 369 * @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed in the Data 370 * RAM region. 371 */ 372 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * p_instance, 373 nrfx_spim_xfer_desc_t const * p_xfer_desc, 374 uint32_t flags, 375 uint8_t cmd_length); 376 #endif 377 378 /** 379 * @brief Function for returning the address of a SPIM start task. 380 * 381 * This function is to be used if @ref nrfx_spim_xfer was called with the flag @ref NRFX_SPIM_FLAG_HOLD_XFER. 382 * In that case, the transfer is not started by the driver, but it must be started externally by PPI. 383 * 384 * @param[in] p_instance Pointer to the driver instance structure. 385 * 386 * @return Start task address. 387 */ 388 uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance); 389 390 /** 391 * @brief Function for returning the address of a END SPIM event. 392 * 393 * The END event can be used to detect the end of a transfer 394 * if the @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER option is used. 395 * 396 * @param[in] p_instance Pointer to the driver instance structure. 397 * 398 * @return END event address. 399 */ 400 uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance); 401 402 /** 403 * @brief Function for aborting ongoing transfer. 404 * 405 * @param[in] p_instance Pointer to the driver instance structure. 406 */ 407 void nrfx_spim_abort(nrfx_spim_t const * p_instance); 408 409 /** @} */ 410 411 412 void nrfx_spim_0_irq_handler(void); 413 void nrfx_spim_1_irq_handler(void); 414 void nrfx_spim_2_irq_handler(void); 415 void nrfx_spim_3_irq_handler(void); 416 417 418 #ifdef __cplusplus 419 } 420 #endif 421 422 #endif /* NRFX_SPIM_H__ */ 423 424