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 NRF_SPI_H__
35 #define NRF_SPI_H__
36 
37 #include <nrfx.h>
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /**
44  * @defgroup nrf_spi_hal SPI HAL
45  * @{
46  * @ingroup nrf_spi
47  * @brief   Hardware access layer for managing the SPI peripheral.
48  */
49 
50 /**
51  * @brief Macro getting pointer to the structure of registers of the SPI peripheral.
52  *
53  * @param[in] idx SPI instance index.
54  *
55  * @return Pointer to the structure of registers of the SPI peripheral.
56  */
57 #define NRF_SPI_INST_GET(idx) NRFX_CONCAT(NRF_, SPI, idx)
58 
59 /**
60  * @brief This value can be used as a parameter for the @ref nrf_spi_pins_set
61  *        function to specify that a given SPI signal (SCK, MOSI, or MISO)
62  *        shall not be connected to a physical pin.
63  */
64 #define NRF_SPI_PIN_NOT_CONNECTED  0xFFFFFFFF
65 
66 
67 /** @brief SPI events. */
68 typedef enum
69 {
70     NRF_SPI_EVENT_READY = offsetof(NRF_SPI_Type, EVENTS_READY) ///< TXD byte sent and RXD byte received.
71 } nrf_spi_event_t;
72 
73 /** @brief SPI interrupts. */
74 typedef enum
75 {
76     NRF_SPI_INT_READY_MASK = SPI_INTENSET_READY_Msk, ///< Interrupt on READY event.
77     NRF_SPI_ALL_INTS_MASK  = SPI_INTENSET_READY_Msk  ///< All SPI interrupts.
78 } nrf_spi_int_mask_t;
79 
80 /** @brief SPI data rates. */
81 typedef enum
82 {
83     NRF_SPI_FREQ_125K = SPI_FREQUENCY_FREQUENCY_K125,   ///< 125 kbps.
84     NRF_SPI_FREQ_250K = SPI_FREQUENCY_FREQUENCY_K250,   ///< 250 kbps.
85     NRF_SPI_FREQ_500K = SPI_FREQUENCY_FREQUENCY_K500,   ///< 500 kbps.
86     NRF_SPI_FREQ_1M   = SPI_FREQUENCY_FREQUENCY_M1,     ///< 1 Mbps.
87     NRF_SPI_FREQ_2M   = SPI_FREQUENCY_FREQUENCY_M2,     ///< 2 Mbps.
88     NRF_SPI_FREQ_4M   = SPI_FREQUENCY_FREQUENCY_M4,     ///< 4 Mbps.
89     // [conversion to 'int' needed to prevent compilers from complaining
90     //  that the provided value (0x80000000UL) is out of range of "int"]
91     NRF_SPI_FREQ_8M   = (int)SPI_FREQUENCY_FREQUENCY_M8 ///< 8 Mbps.
92 } nrf_spi_frequency_t;
93 
94 /** @brief SPI modes. */
95 typedef enum
96 {
97     NRF_SPI_MODE_0, ///< SCK active high, sample on leading edge of clock.
98     NRF_SPI_MODE_1, ///< SCK active high, sample on trailing edge of clock.
99     NRF_SPI_MODE_2, ///< SCK active low, sample on leading edge of clock.
100     NRF_SPI_MODE_3  ///< SCK active low, sample on trailing edge of clock.
101 } nrf_spi_mode_t;
102 
103 /** @brief SPI bit orders. */
104 typedef enum
105 {
106     NRF_SPI_BIT_ORDER_MSB_FIRST = SPI_CONFIG_ORDER_MsbFirst, ///< Most significant bit shifted out first.
107     NRF_SPI_BIT_ORDER_LSB_FIRST = SPI_CONFIG_ORDER_LsbFirst  ///< Least significant bit shifted out first.
108 } nrf_spi_bit_order_t;
109 
110 
111 /**
112  * @brief Function for clearing the specified SPI event.
113  *
114  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
115  * @param[in] event Event to be cleared.
116  */
117 NRF_STATIC_INLINE void nrf_spi_event_clear(NRF_SPI_Type *  p_reg,
118                                            nrf_spi_event_t event);
119 
120 /**
121  * @brief Function for retrieving the state of the SPI event.
122  *
123  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
124  * @param[in] event Event to be checked.
125  *
126  * @retval true  The event has been generated.
127  * @retval false The event has not been generated.
128  */
129 NRF_STATIC_INLINE bool nrf_spi_event_check(NRF_SPI_Type const * p_reg,
130                                            nrf_spi_event_t      event);
131 
132 /**
133  * @brief Function for getting the address of the specified SPI event register.
134  *
135  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
136  * @param[in] event The specified event.
137  *
138  * @return Address of the specified event register.
139  */
140 NRF_STATIC_INLINE uint32_t nrf_spi_event_address_get(NRF_SPI_Type const * p_reg,
141                                                      nrf_spi_event_t      event);
142 
143 /**
144  * @brief Function for enabling the specified interrupts.
145  *
146  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
147  * @param[in] mask  Mask of interrupts to be enabled.
148  *                  Use @ref nrf_spi_int_mask_t values for bit masking.
149  */
150 NRF_STATIC_INLINE void nrf_spi_int_enable(NRF_SPI_Type * p_reg,
151                                           uint32_t       mask);
152 
153 /**
154  * @brief Function for disabling the specified interrupts.
155  *
156  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
157  * @param[in] mask  Mask of interrupts to be disabled.
158  *                  Use @ref nrf_spi_int_mask_t values for bit masking.
159  */
160 NRF_STATIC_INLINE void nrf_spi_int_disable(NRF_SPI_Type * p_reg,
161                                            uint32_t       mask);
162 
163 /**
164  * @brief Function for checking if the specified interrupts are enabled.
165  *
166  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
167  * @param[in] mask  Mask of interrupts to be checked.
168  *                  Use @ref nrf_spi_int_mask_t values for bit masking.
169  *
170  * @return Mask of enabled interrupts.
171  */
172 NRF_STATIC_INLINE uint32_t nrf_spi_int_enable_check(NRF_SPI_Type const * p_reg, uint32_t mask);
173 
174 /**
175  * @brief Function for enabling the SPI peripheral.
176  *
177  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
178  */
179 NRF_STATIC_INLINE void nrf_spi_enable(NRF_SPI_Type * p_reg);
180 
181 /**
182  * @brief Function for disabling the SPI peripheral.
183  *
184  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
185  */
186 NRF_STATIC_INLINE void nrf_spi_disable(NRF_SPI_Type * p_reg);
187 
188 /**
189  * @brief Function for configuring SPI pins.
190  *
191  * If a given signal is not needed, pass the @ref NRF_SPI_PIN_NOT_CONNECTED
192  * value instead of its pin number.
193  *
194  * @param[in] p_reg    Pointer to the structure of registers of the peripheral.
195  * @param[in] sck_pin  SCK pin number.
196  * @param[in] mosi_pin MOSI pin number.
197  * @param[in] miso_pin MISO pin number.
198  */
199 NRF_STATIC_INLINE void nrf_spi_pins_set(NRF_SPI_Type * p_reg,
200                                         uint32_t       sck_pin,
201                                         uint32_t       mosi_pin,
202                                         uint32_t       miso_pin);
203 
204 /**
205  * @brief Function for setting the SCK pin.
206  *
207  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
208  * @param[in] pin   SCK pin number.
209  */
210 NRF_STATIC_INLINE void nrf_spi_sck_pin_set(NRF_SPI_Type * p_reg, uint32_t pin);
211 
212 /**
213  * @brief Function for setting the MOSI pin
214  *
215  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
216  * @param[in] pin   MOSI pin number.
217  */
218 NRF_STATIC_INLINE void nrf_spi_mosi_pin_set(NRF_SPI_Type * p_reg, uint32_t pin);
219 
220 /**
221  * @brief Function for setting the MISO pin.
222  *
223  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
224  * @param[in] pin   MISO pin number.
225  */
226 NRF_STATIC_INLINE void nrf_spi_miso_pin_set(NRF_SPI_Type * p_reg, uint32_t pin);
227 
228 /**
229  * @brief Function for getting the SCK pin selection.
230  *
231  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
232  *
233  * @return SCK pin selection;
234  */
235 NRF_STATIC_INLINE uint32_t nrf_spi_sck_pin_get(NRF_SPI_Type const * p_reg);
236 
237 /**
238  * @brief Function for getting the MOSI pin selection.
239  *
240  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
241  *
242  * @return MOSI pin selection;
243  */
244 NRF_STATIC_INLINE uint32_t nrf_spi_mosi_pin_get(NRF_SPI_Type const * p_reg);
245 
246 /**
247  * @brief Function for getting the MISO pin selection.
248  *
249  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
250  *
251  * @return MISO pin selection;
252  */
253 NRF_STATIC_INLINE uint32_t nrf_spi_miso_pin_get(NRF_SPI_Type const * p_reg);
254 
255 /**
256  * @brief Function for writing data to the SPI transmitter register.
257  *
258  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
259  * @param[in] data  TX data to send.
260  */
261 NRF_STATIC_INLINE void nrf_spi_txd_set(NRF_SPI_Type * p_reg, uint8_t data);
262 
263 /**
264  * @brief Function for reading data from the SPI receiver register.
265  *
266  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
267  *
268  * @return RX data received.
269  */
270 NRF_STATIC_INLINE uint8_t nrf_spi_rxd_get(NRF_SPI_Type const * p_reg);
271 
272 /**
273  * @brief Function for setting the SPI master data rate.
274  *
275  * @param[in] p_reg     Pointer to the structure of registers of the peripheral.
276  * @param[in] frequency SPI frequency.
277  */
278 NRF_STATIC_INLINE void nrf_spi_frequency_set(NRF_SPI_Type *      p_reg,
279                                              nrf_spi_frequency_t frequency);
280 
281 /**
282  * @brief Function for setting the SPI configuration.
283  *
284  * @param[in] p_reg         Pointer to the structure of registers of the peripheral.
285  * @param[in] spi_mode      SPI mode.
286  * @param[in] spi_bit_order SPI bit order.
287  */
288 NRF_STATIC_INLINE void nrf_spi_configure(NRF_SPI_Type *      p_reg,
289                                          nrf_spi_mode_t      spi_mode,
290                                          nrf_spi_bit_order_t spi_bit_order);
291 
292 
293 #ifndef NRF_DECLARE_ONLY
294 
nrf_spi_event_clear(NRF_SPI_Type * p_reg,nrf_spi_event_t event)295 NRF_STATIC_INLINE void nrf_spi_event_clear(NRF_SPI_Type *  p_reg,
296                                            nrf_spi_event_t event)
297 {
298     *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
299     nrf_event_readback((uint8_t *)p_reg + (uint32_t)event);
300 }
301 
nrf_spi_event_check(NRF_SPI_Type const * p_reg,nrf_spi_event_t event)302 NRF_STATIC_INLINE bool nrf_spi_event_check(NRF_SPI_Type const * p_reg,
303                                            nrf_spi_event_t      event)
304 {
305     return nrf_event_check(p_reg, event);
306 }
307 
nrf_spi_event_address_get(NRF_SPI_Type const * p_reg,nrf_spi_event_t event)308 NRF_STATIC_INLINE uint32_t nrf_spi_event_address_get(NRF_SPI_Type const * p_reg,
309                                                      nrf_spi_event_t      event)
310 {
311     return nrf_task_event_address_get(p_reg, event);
312 }
313 
nrf_spi_int_enable(NRF_SPI_Type * p_reg,uint32_t mask)314 NRF_STATIC_INLINE void nrf_spi_int_enable(NRF_SPI_Type * p_reg,
315                                           uint32_t       mask)
316 {
317     p_reg->INTENSET = mask;
318 }
319 
nrf_spi_int_disable(NRF_SPI_Type * p_reg,uint32_t mask)320 NRF_STATIC_INLINE void nrf_spi_int_disable(NRF_SPI_Type * p_reg,
321                                            uint32_t       mask)
322 {
323     p_reg->INTENCLR = mask;
324 }
325 
nrf_spi_int_enable_check(NRF_SPI_Type const * p_reg,uint32_t mask)326 NRF_STATIC_INLINE uint32_t nrf_spi_int_enable_check(NRF_SPI_Type const * p_reg, uint32_t mask)
327 {
328     return p_reg->INTENSET & mask;
329 }
330 
nrf_spi_enable(NRF_SPI_Type * p_reg)331 NRF_STATIC_INLINE void nrf_spi_enable(NRF_SPI_Type * p_reg)
332 {
333     p_reg->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);
334 }
335 
nrf_spi_disable(NRF_SPI_Type * p_reg)336 NRF_STATIC_INLINE void nrf_spi_disable(NRF_SPI_Type * p_reg)
337 {
338     p_reg->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos);
339 }
340 
nrf_spi_pins_set(NRF_SPI_Type * p_reg,uint32_t sck_pin,uint32_t mosi_pin,uint32_t miso_pin)341 NRF_STATIC_INLINE void nrf_spi_pins_set(NRF_SPI_Type * p_reg,
342                                         uint32_t       sck_pin,
343                                         uint32_t       mosi_pin,
344                                         uint32_t       miso_pin)
345 {
346 #if defined(SPI_PSEL_SCK_CONNECT_Pos)
347     p_reg->PSEL.SCK = sck_pin;
348 #else
349     p_reg->PSELSCK  = sck_pin;
350 #endif
351 
352 #if defined(SPI_PSEL_MOSI_CONNECT_Pos)
353     p_reg->PSEL.MOSI = mosi_pin;
354 #else
355     p_reg->PSELMOSI = mosi_pin;
356 #endif
357 
358 #if defined(SPI_PSEL_MISO_CONNECT_Pos)
359     p_reg->PSEL.MISO = miso_pin;
360 #else
361     p_reg->PSELMISO = miso_pin;
362 #endif
363 }
364 
nrf_spi_sck_pin_set(NRF_SPI_Type * p_reg,uint32_t pin)365 NRF_STATIC_INLINE void nrf_spi_sck_pin_set(NRF_SPI_Type * p_reg, uint32_t pin)
366 {
367 #if defined(SPI_PSEL_SCK_CONNECT_Pos)
368     p_reg->PSEL.SCK = pin;
369 #else
370     p_reg->PSELSCK  = pin;
371 #endif
372 }
373 
nrf_spi_mosi_pin_set(NRF_SPI_Type * p_reg,uint32_t pin)374 NRF_STATIC_INLINE void nrf_spi_mosi_pin_set(NRF_SPI_Type * p_reg, uint32_t pin)
375 {
376 #if defined(SPI_PSEL_MOSI_CONNECT_Pos)
377     p_reg->PSEL.MOSI = pin;
378 #else
379     p_reg->PSELMOSI = pin;
380 #endif
381 }
382 
nrf_spi_miso_pin_set(NRF_SPI_Type * p_reg,uint32_t pin)383 NRF_STATIC_INLINE void nrf_spi_miso_pin_set(NRF_SPI_Type * p_reg, uint32_t pin)
384 {
385 #if defined(SPI_PSEL_MISO_CONNECT_Pos)
386     p_reg->PSEL.MISO = pin;
387 #else
388     p_reg->PSELMISO = pin;
389 #endif
390 }
391 
nrf_spi_sck_pin_get(NRF_SPI_Type const * p_reg)392 NRF_STATIC_INLINE uint32_t nrf_spi_sck_pin_get(NRF_SPI_Type const * p_reg)
393 {
394 #if defined(SPI_PSEL_SCK_CONNECT_Pos)
395     return p_reg->PSEL.SCK;
396 #else
397     return p_reg->PSELSCK;
398 #endif
399 }
400 
nrf_spi_mosi_pin_get(NRF_SPI_Type const * p_reg)401 NRF_STATIC_INLINE uint32_t nrf_spi_mosi_pin_get(NRF_SPI_Type const * p_reg)
402 {
403 #if defined(SPI_PSEL_MOSI_CONNECT_Pos)
404     return p_reg->PSEL.MOSI;
405 #else
406     return p_reg->PSELMOSI;
407 #endif
408 }
409 
nrf_spi_miso_pin_get(NRF_SPI_Type const * p_reg)410 NRF_STATIC_INLINE uint32_t nrf_spi_miso_pin_get(NRF_SPI_Type const * p_reg)
411 {
412 #if defined(SPI_PSEL_MISO_CONNECT_Pos)
413     return p_reg->PSEL.MISO;
414 #else
415     return p_reg->PSELMISO;
416 #endif
417 }
418 
nrf_spi_txd_set(NRF_SPI_Type * p_reg,uint8_t data)419 NRF_STATIC_INLINE void nrf_spi_txd_set(NRF_SPI_Type * p_reg, uint8_t data)
420 {
421     p_reg->TXD = data;
422 }
423 
nrf_spi_rxd_get(NRF_SPI_Type const * p_reg)424 NRF_STATIC_INLINE uint8_t nrf_spi_rxd_get(NRF_SPI_Type const * p_reg)
425 {
426     return (uint8_t)p_reg->RXD;
427 }
428 
nrf_spi_frequency_set(NRF_SPI_Type * p_reg,nrf_spi_frequency_t frequency)429 NRF_STATIC_INLINE void nrf_spi_frequency_set(NRF_SPI_Type *      p_reg,
430                                              nrf_spi_frequency_t frequency)
431 {
432     p_reg->FREQUENCY = (uint32_t)frequency;
433 }
434 
nrf_spi_configure(NRF_SPI_Type * p_reg,nrf_spi_mode_t spi_mode,nrf_spi_bit_order_t spi_bit_order)435 NRF_STATIC_INLINE void nrf_spi_configure(NRF_SPI_Type *      p_reg,
436                                          nrf_spi_mode_t      spi_mode,
437                                          nrf_spi_bit_order_t spi_bit_order)
438 {
439     uint32_t config = (spi_bit_order == NRF_SPI_BIT_ORDER_MSB_FIRST ?
440         SPI_CONFIG_ORDER_MsbFirst : SPI_CONFIG_ORDER_LsbFirst);
441     switch (spi_mode)
442     {
443     default:
444     case NRF_SPI_MODE_0:
445         config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos) |
446                   (SPI_CONFIG_CPHA_Leading    << SPI_CONFIG_CPHA_Pos);
447         break;
448 
449     case NRF_SPI_MODE_1:
450         config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos) |
451                   (SPI_CONFIG_CPHA_Trailing   << SPI_CONFIG_CPHA_Pos);
452         break;
453 
454     case NRF_SPI_MODE_2:
455         config |= (SPI_CONFIG_CPOL_ActiveLow  << SPI_CONFIG_CPOL_Pos) |
456                   (SPI_CONFIG_CPHA_Leading    << SPI_CONFIG_CPHA_Pos);
457         break;
458 
459     case NRF_SPI_MODE_3:
460         config |= (SPI_CONFIG_CPOL_ActiveLow  << SPI_CONFIG_CPOL_Pos) |
461                   (SPI_CONFIG_CPHA_Trailing   << SPI_CONFIG_CPHA_Pos);
462         break;
463     }
464     p_reg->CONFIG = config;
465 }
466 
467 #endif // NRF_DECLARE_ONLY
468 
469 /** @} */
470 
471 #ifdef __cplusplus
472 }
473 #endif
474 
475 #endif // NRF_SPI_H__
476