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