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