1 /*
2  * Copyright (c) 2015 - 2025, 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_SPI_H__
35 #define NRFX_SPI_H__
36 
37 #include <nrfx.h>
38 #include <hal/nrf_spi.h>
39 #include <hal/nrf_gpio.h>
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /**
46  * @defgroup nrfx_spi SPI driver
47  * @{
48  * @ingroup nrf_spi
49  * @brief   Serial Peripheral Interface master (SPI) driver.
50  */
51 
52 /** @brief Data structure of the Serial Peripheral Interface master (SPI) driver instance. */
53 typedef struct
54 {
55     NRF_SPI_Type * p_reg;        ///< Pointer to a structure with SPI registers.
56     uint8_t        drv_inst_idx; ///< Index of the driver instance. For internal use only.
57 } nrfx_spi_t;
58 
59 #ifndef __NRFX_DOXYGEN__
60 enum {
61     /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */
62     NRFX_INSTANCE_ENUM_LIST(SPI)
63     NRFX_SPI_ENABLED_COUNT
64 };
65 #endif
66 
67 /** @brief Macro for creating an instance of the SPI master driver. */
68 #define NRFX_SPI_INSTANCE(id)                               \
69 {                                                           \
70     .p_reg        = NRFX_CONCAT(NRF_, SPI, id),             \
71     .drv_inst_idx = NRFX_CONCAT(NRFX_SPI, id, _INST_IDX),   \
72 }
73 
74 /**
75  * @brief This value can be provided instead of a pin number for signals MOSI,
76  *        MISO, and Slave Select to specify that the given signal is not used and
77  *        therefore does not need to be connected to a pin.
78  */
79 #define NRFX_SPI_PIN_NOT_USED  0xFF
80 
81 /** @brief Configuration structure of the SPI master driver instance. */
82 typedef struct
83 {
84     uint8_t             sck_pin;       ///< SCK pin number.
85     uint8_t             mosi_pin;      ///< MOSI pin number (optional).
86                                        /**< Set to @ref NRFX_SPI_PIN_NOT_USED
87                                         *   if this signal is not needed. */
88     uint8_t             miso_pin;      ///< MISO pin number (optional).
89                                        /**< Set to @ref NRFX_SPI_PIN_NOT_USED
90                                         *   if this signal is not needed. */
91     uint8_t             ss_pin;        ///< Slave Select pin number (optional).
92                                        /**< Set to @ref NRFX_SPI_PIN_NOT_USED
93                                         *   if this signal is not needed. The driver
94                                         *   supports only active low for this signal.
95                                         *   If the signal must be active high,
96                                         *   it must be controlled externally.
97                                         *   @note Unlike the other fields that specify
98                                         *   pin numbers, this one cannot be omitted
99                                         *   when both GPIO configuration and pin
100                                         *   selection are to be skipped, as the driver
101                                         *   must control the signal as a regular GPIO. */
102     uint8_t             irq_priority;  ///< Interrupt priority.
103     uint8_t             orc;           ///< Overrun character.
104                                        /**< This character is used when all bytes from the TX buffer are sent,
105                                         *   but the transfer continues due to RX. */
106     nrf_spi_frequency_t frequency;     ///< SPI frequency.
107     nrf_spi_mode_t      mode;          ///< SPI mode.
108     nrf_spi_bit_order_t bit_order;     ///< SPI bit order.
109     nrf_gpio_pin_pull_t miso_pull;     ///< MISO pull up configuration.
110     bool                skip_gpio_cfg; ///< Skip GPIO configuration of pins.
111                                        /**< When set to true, the driver does not modify
112                                         *   any GPIO parameters of the used pins. Those
113                                         *   parameters are supposed to be configured
114                                         *   externally before the driver is initialized. */
115     bool                skip_psel_cfg; ///< Skip pin selection configuration.
116                                        /**< When set to true, the driver does not modify
117                                         *   pin select registers in the peripheral.
118                                         *   Those registers are supposed to be set up
119                                         *   externally before the driver is initialized.
120                                         *   @note When both GPIO configuration and pin
121                                         *   selection are to be skipped, the structure
122                                         *   fields that specify pins can be omitted,
123                                         *   as they are ignored anyway. This does not
124                                         *   apply to the @p ss_pin field. */
125 } nrfx_spi_config_t;
126 
127 /**
128  * @brief SPI master instance default configuration.
129  * This configuration sets up SPI with the following options:
130  * - over-run character set to 0xFF
131  * - clock frequency 4 MHz
132  * - mode 0 enabled (SCK active high, sample on leading edge of clock)
133  * - MSB shifted out first
134  * - MISO pull-up disabled
135  *
136  * @param[in] _pin_sck  SCK pin.
137  * @param[in] _pin_mosi MOSI pin.
138  * @param[in] _pin_miso MISO pin.
139  * @param[in] _pin_ss   SS pin.
140  */
141 #define NRFX_SPI_DEFAULT_CONFIG(_pin_sck, _pin_mosi, _pin_miso, _pin_ss)    \
142 {                                                                           \
143     .sck_pin      = _pin_sck,                                               \
144     .mosi_pin     = _pin_mosi,                                              \
145     .miso_pin     = _pin_miso,                                              \
146     .ss_pin       = _pin_ss,                                                \
147     .irq_priority = NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY,                   \
148     .orc          = 0xFF,                                                   \
149     .frequency    = NRF_SPI_FREQ_4M,                                        \
150     .mode         = NRF_SPI_MODE_0,                                         \
151     .bit_order    = NRF_SPI_BIT_ORDER_MSB_FIRST,                            \
152     .miso_pull    = NRF_GPIO_PIN_NOPULL,                                    \
153 }
154 
155 /** @brief Single transfer descriptor structure. */
156 typedef struct
157 {
158     uint8_t const * p_tx_buffer; ///< Pointer to TX buffer.
159     size_t          tx_length;   ///< TX buffer length.
160     uint8_t       * p_rx_buffer; ///< Pointer to RX buffer.
161     size_t          rx_length;   ///< RX buffer length.
162 }nrfx_spi_xfer_desc_t;
163 
164 /**
165  * @brief Macro for setting up single transfer descriptor.
166  *
167  * This macro is for internal use only.
168  */
169 #define NRFX_SPI_SINGLE_XFER(p_tx, tx_len, p_rx, rx_len) \
170 {                                                        \
171     .p_tx_buffer = (uint8_t const *)(p_tx),              \
172     .tx_length = (tx_len),                               \
173     .p_rx_buffer = (p_rx),                               \
174     .rx_length = (rx_len),                               \
175 }
176 
177 /** @brief Macro for setting the duplex TX RX transfer. */
178 #define NRFX_SPI_XFER_TRX(p_tx_buf, tx_length, p_rx_buf, rx_length) \
179         NRFX_SPI_SINGLE_XFER(p_tx_buf, tx_length, p_rx_buf, rx_length)
180 
181 /** @brief Macro for setting the TX transfer. */
182 #define NRFX_SPI_XFER_TX(p_buf, length) \
183         NRFX_SPI_SINGLE_XFER(p_buf, length, NULL, 0)
184 
185 /** @brief Macro for setting the RX transfer. */
186 #define NRFX_SPI_XFER_RX(p_buf, length) \
187         NRFX_SPI_SINGLE_XFER(NULL, 0, p_buf, length)
188 
189 /**
190  * @brief SPI master driver event types, passed to the handler routine provided
191  *        during initialization.
192  */
193 typedef enum
194 {
195     NRFX_SPI_EVENT_DONE, ///< Transfer done.
196 } nrfx_spi_evt_type_t;
197 
198 /** @brief SPI master event description with transmission details. */
199 typedef struct
200 {
201     nrfx_spi_evt_type_t  type;      ///< Event type.
202     nrfx_spi_xfer_desc_t xfer_desc; ///< Transfer details.
203 } nrfx_spi_evt_t;
204 
205 /** @brief SPI master driver event handler type. */
206 typedef void (* nrfx_spi_evt_handler_t)(nrfx_spi_evt_t const * p_event,
207                                         void *                 p_context);
208 
209 /**
210  * @brief Function for initializing the SPI master driver instance.
211  *
212  * This function configures and enables the specified peripheral.
213  *
214  * @param[in] p_instance Pointer to the driver instance structure.
215  * @param[in] p_config   Pointer to the structure with the initial configuration.
216  * @param[in] handler    Event handler provided by the user. If NULL, transfers
217  *                       will be performed in blocking mode.
218  * @param[in] p_context  Context passed to the event handler.
219  *
220  * @retval NRFX_SUCCESS             Initialization was successful.
221  * @retval NRFX_ERROR_ALREADY       The driver is already initialized.
222  * @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
223  *                                  Deprecated - use @ref NRFX_ERROR_ALREADY instead.
224  * @retval NRFX_ERROR_BUSY          Some other peripheral with the same
225  *                                  instance ID is already in use. This is
226  *                                  possible only if @ref nrfx_prs module
227  *                                  is enabled.
228  */
229 nrfx_err_t nrfx_spi_init(nrfx_spi_t const *        p_instance,
230                          nrfx_spi_config_t const * p_config,
231                          nrfx_spi_evt_handler_t    handler,
232                          void *                    p_context);
233 
234 /**
235  * @brief Function for reconfiguring the SPI master driver instance.
236  *
237  * @param[in] p_instance Pointer to the driver instance structure.
238  * @param[in] p_config   Pointer to the structure with the configuration.
239  *
240  * @retval NRFX_SUCCESS             Reconfiguration was successful.
241  * @retval NRFX_ERROR_BUSY          The driver is during transfer.
242  * @retval NRFX_ERROR_INVALID_STATE The driver is uninitialized.
243  */
244 nrfx_err_t nrfx_spi_reconfigure(nrfx_spi_t const *        p_instance,
245                                 nrfx_spi_config_t const * p_config);
246 
247 /**
248  * @brief Function for uninitializing the SPI master driver instance.
249  *
250  * @param[in] p_instance Pointer to the driver instance structure.
251  */
252 void nrfx_spi_uninit(nrfx_spi_t const * p_instance);
253 
254 /**
255  * @brief Function for checking if the SPI driver instance is initialized.
256  *
257  * @param[in] p_instance Pointer to the driver instance structure.
258  *
259  * @retval true  Instance is already initialized.
260  * @retval false Instance is not initialized.
261  */
262 bool nrfx_spi_init_check(nrfx_spi_t const * p_instance);
263 
264 /**
265  * @brief Function for starting the SPI data transfer.
266  *
267  * If an event handler was provided in the @ref nrfx_spi_init call, this function
268  * returns immediately and the handler is called when the transfer is done.
269  * Otherwise, the transfer is performed in blocking mode, which means that this function
270  * returns when the transfer is finished.
271  *
272  * @param p_instance  Pointer to the driver instance structure.
273  * @param p_xfer_desc Pointer to the transfer descriptor.
274  * @param flags       Transfer options (0 for default settings).
275  *                    Currently, no additional flags are available.
276  *
277  * @retval NRFX_SUCCESS             The procedure is successful.
278  * @retval NRFX_ERROR_BUSY          The driver is not ready for a new transfer.
279  * @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported.
280  */
281 nrfx_err_t nrfx_spi_xfer(nrfx_spi_t const *           p_instance,
282                          nrfx_spi_xfer_desc_t const * p_xfer_desc,
283                          uint32_t                     flags);
284 
285 /**
286  * @brief Function for aborting the ongoing transfer.
287  *
288  * @param[in] p_instance Pointer to the driver instance structure.
289  */
290 void nrfx_spi_abort(nrfx_spi_t const * p_instance);
291 
292 /**
293  * @brief Macro returning SPI interrupt handler.
294  *
295  * param[in] idx SPI index.
296  *
297  * @return Interrupt handler.
298  */
299 #define NRFX_SPI_INST_HANDLER_GET(idx) NRFX_CONCAT_3(nrfx_spi_, idx, _irq_handler)
300 
301 /** @} */
302 
303 /*
304  * Declare interrupt handlers for all enabled driver instances in the following format:
305  * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_spi_0_irq_handler).
306  *
307  * A specific interrupt handler for the driver instance can be retrieved by using
308  * the NRFX_SPI_INST_HANDLER_GET macro.
309  *
310  * Here is a sample of using the NRFX_SPI_INST_HANDLER_GET macro to map an interrupt handler
311  * in a Zephyr application:
312  *
313  * IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPI_INST_GET(\<instance_index\>)), \<priority\>,
314  *             NRFX_SPI_INST_HANDLER_GET(\<instance_index\>), 0, 0);
315  */
316 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(SPI, spi)
317 
318 
319 #ifdef __cplusplus
320 }
321 #endif
322 
323 #endif // NRFX_SPI_H__
324