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