EVE 1.0
spi.h
Go to the documentation of this file.
1 #ifndef DRIVER_SPI_H
2 #define DRIVER_SPI_H
3 /**********************************************************************/
4 /*
5  * Copyright (c) 2013-2017, Jetro AS
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without modification,
9  * are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  * this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  * derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONRIBUTORS ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28  * OF SUCH DAMAGE.
29  *
30  * This file is part of the EVE platform.
31  */
32 
33 /**
34  * \file
35  * @brief Driver for the MCU's SPI blocks.
36  *
37  * @author KLO, Jetro AS
38  * @author DT, Jetro AS
39  */ /******************************************************************/
40 
41 #include <core/clk.h>
42 #include <lib/dlist.h>
43 #include <dev/data-buffer.h>
44 #include <dev/gpio.h>
45 #include <hal/nrf_spim.h>
46 
47 /**
48  * \defgroup spi nRF52 SPI bus master driver
49  * \ingroup nrf52
50  * \{
51  *
52  * This SPI driver provides interface to the MCU's SPI blocks.
53  *
54  * Functionality included:
55  * - Init and disable of SPI
56  * - Disable of chip-select
57  * - Enable of chip-select, including setup of clock, bitrate and TX/RX using SpiCsEnable()
58  * - With chip-select enabled, the following functions may be called:
59  * - SpiTransferAsync(), SpiRead(), SpiWrite(), SpiWriteRead(), SpiFlush(), SpiIsBusy() and SpiDisable()
60  *
61  * Currently only master mode is supported.
62  */
63 
64 
65 /***********************************************************************
66  * Global defines
67  ***********************************************************************/
68 
69 /**
70  * Enables fix for errata 58
71  */
72 #define ERRATA_58
73 
74 /**
75  * Size of the synchronous FIFO emulation buffer
76  */
77 #define SPI_SYNC_FIFO_DEPTH 4
78 
79 /*extern*/ struct work_t;
80 
81 /*forward*/ struct spi_t;
82 
83 /**
84  * SpiTransferSync flasg
85  */
87 {
88  SPI_TRANSFER_DEFAULT = 0,
89  SPI_TRANSFER_CAN_SLEEP = (1 << 0),
90 };
91 
92 /**
93  * Uninitialized chip select structure
94  */
95 #define SPI_CS_UNINITIALIZED ((struct spi_cs_t) { .CsUnInitialized = 1 })
96 
97 /**
98  * spi_mode_t defines mode 0-3.
99  *
100  */
102 {
103  SPI_MODE0 = NRF_SPIM_MODE_0, /**< SCK active high, sample on leading edge of clock. */
104  SPI_MODE1 = NRF_SPIM_MODE_1, /**< SCK active high, sample on trailing edge of clock. */
105  SPI_MODE2 = NRF_SPIM_MODE_2, /**< SCK active low, sample on leading edge of clock. */
106  SPI_MODE3 = NRF_SPIM_MODE_3 /**< SCK active low, sample on trailing edge of clock. */
107 };
108 
109 /**
110  * spi_cs_t structure defines SPI and chip select setup.
111  *
112  */
113 struct spi_cs_t
114 {
115  union {
116  struct {
117  uint32_t Mode : 2; /**< SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3 */
118  uint32_t Master : 1; /**< TRUE if Master, else FALSE - only Master functionality is implemented */
119  uint32_t MsbFirst : 1; /**< TRUE if MSB first, else FALSE */
120  uint32_t MosiPin : GPIO_PIN_ID_WIDTH; /**< MOSI pin number */
121  uint32_t MisoPin : GPIO_PIN_ID_WIDTH; /**< MISO pin number */
122  uint32_t ClkPin : GPIO_PIN_ID_WIDTH; /**< CLK pin number */
123  uint32_t CsPin : GPIO_PIN_ID_WIDTH; /**< CSn pin number */
124  uint32_t CsActiveHigh : 1; /**< TRUE if CSn is active high, FALSE otherwise */
125  uint32_t CsUnInitialized : 1; /**< Internal: Set to TRUE in SpiInit */
126  };
127  uint32_t Raw;
128  };
129 };
130 
131 /**
132  * The callback is called at completion of an asynchronous transfer.
133  *
134  * @param Spi SPI to be used
135  * @param CallbackData User-defined data
136  */
137 typedef void (*spi_async_callback_t)(const struct spi_t *Spi, void *CallbackData);
138 
139 /**
140  * spi_state_t structure holds internal state of the SPI driver.
141  *
142  */
144 {
145  struct spi_cs_t ChipSelect; /**< Active chip select */
146  struct data_buffer_t RxBuffer; /**< Receive buffer for asynchronous transfers */
147  struct data_buffer_t TxBuffer; /**< Transmit buffer for asynchronous transfers */
148  spi_async_callback_t Callback; /**< Asynchronous callback */
149  void *CallbackData; /**< Asynchronous callback data */
150  struct dlist_t PendingCsWorks; /**< List of works waiting for the block availability */
151  uint8_t Fifo[SPI_SYNC_FIFO_DEPTH]; /**< Synchronous FIFO emulation */
152  uint8_t FifoTxUsed; /**< Amount of bytes in the TX FIFO */
153  uint8_t FifoRxUsed; /**< Amount of bytes in the RX FIFO */
154  uint8_t FifoPos; /**< Position of the first byte in the FIFO */
155  volatile bool Busy; /**< SPI is busy with a transfer */
156 #ifdef ERRATA_58
157  bool Errata58; /**< Errata 58 workarownd is active */
158 #endif /* ERRATA_58 */
159 };
160 
161 /**
162  * spi_t structure is used for configuration of SPI.
163  * The structure must be initialized before the SPI driver may be used.
164  *
165  */
166 struct spi_t
167 {
168  NRF_SPIM_Type *Dev; /**< Pointer to the physical hardware interface */
169  uint32_t IrqPriority; /**< HW IRQ priority (see enum EVE_IRQ_PRIORITIES) */
170  struct spi_state_t *State; /**< Pointer to the mutable device state */
171  uint32_t DefaultBaudrate; /**< Default baudrate in bit/s (must be <= peripheral clock / 2) */
172 #ifdef ERRATA_58
173  uint8_t Errata58_PPI_ID; /**< PPI ID used internally for errata 58 workarownd */
174  uint8_t Errata58_GPIOTE_ID; /**< GPIOTE ID used internally for errata 58 workarownd */
175 #endif /* ERRATA_58 */
176 };
177 
178 /**
179  * @name Functions called from application programs
180  * @{
181  */
182 
183 /**********************************************************************/
184 /**
185  * @brief Name: SpiInit\n
186  * Initializes SPI based on selected device.
187  * Master operation: Baudrate is limited to 0.5*peripheral clock.
188  * Slave operation: Not implemented.
189  * Called from main program level.
190  *
191  * @param Spi SPI parameters to be used
192  ***********************************************************************/
193 extern void SpiInit(const struct spi_t *Spi);
194 
195 /**********************************************************************/
196 /**
197  * @brief Name: SpiDisable\n
198  * Disables SPI based on selected device.
199  * Called from main program level.
200  *
201  * @param Spi SPI parameters to be used
202  ***********************************************************************/
203 extern void SpiDisable(const struct spi_t *Spi);
204 
205 /**********************************************************************/
206 /**
207  * @brief Name: SpiRead\n
208  * WARNING: SpiWrite() must be called prior to this function.
209  * Waits for data received in RX FIFO.
210  *
211  * @param Spi SPI to be used
212  * @return Received data
213  ***********************************************************************/
214 extern uint8_t SpiRead(const struct spi_t *Spi);
215 
216 /**********************************************************************/
217 /**
218  * @brief Name: SpiWrite\n
219  * WARNING: SpiCsEnable() must be called prior to this function.
220  * Waits for empty transmit buffer, then sends 1 byte.
221  *
222  * @param Spi SPI to be used
223  * @param DataToSend Data to be sent
224  ***********************************************************************/
225 extern void SpiWrite(const struct spi_t *Spi, uint8_t DataToSend);
226 
227 /**********************************************************************/
228 /**
229  * @brief Name: SpiWriteRead\n
230  * WARNING: SpiCsEnable() must be called prior to this function.
231  * Waits for empty transmit buffer, sends 1 byte and waits for data
232  * received in RX FIFO.
233  *
234  * @param Spi SPI to be used
235  * @param DataToSend Data to be sent
236  * @return Received data
237  ***********************************************************************/
238 extern uint8_t SpiWriteRead(const struct spi_t *Spi, uint8_t DataToSend);
239 
240 /**********************************************************************/
241 /**
242  * @brief Name: SpiTransferAsync\n
243  * WARNING: SpiCsEnable() must be called prior to this function.
244  * Starts asynchronous data transfer (both transmit and receive).
245  *
246  * @param Spi SPI to be used
247  * @param TxBuffer Transmit buffer
248  * @param TxLength Amount of bytes to be sent
249  * @param RxBuffer Receive buffer
250  * @param RxLength Amount of bytes to be received
251  * @param Callback Pointer to the function to be called when transfer is finished
252  * @param CallbackData User-defined data for the callback
253  ***********************************************************************/
254 extern void SpiTransferAsync(const struct spi_t *Spi,
255  const void *TxBuffer, uint32_t TxLength,
256  void *RxBuffer, uint32_t RxLength,
258 
259 /**********************************************************************/
260 /**
261  * @brief Name: SpiTransferSync\n
262  * WARNING: SpiCsEnable() must be called prior to this function.
263  * Does synchronous data transfer (both transmit and receive).
264  *
265  * @param Spi SPI to be used
266  * @param TxBuffer Transmit buffer
267  * @param TxLength Amount of bytes to be sent
268  * @param RxBuffer Receive buffer
269  * @param RxLength Amount of bytes to be received
270  * @param Flags Flags of the transfer, bit combination of spi_transfer_flags_t
271  ***********************************************************************/
272 extern void SpiTransferSync(const struct spi_t *Spi,
273  const void *TxBuffer, uint32_t TxLength,
274  void *RxBuffer, uint32_t RxLength,
275  uint32_t Flags);
276 
277 /**********************************************************************/
278 /**
279  * @brief Name: SpiFlush\n
280  * WARNING: SpiCsEnable() must be called prior to this function.
281  * Waits for any previously transmission to be complete, then flushes RX FIFO.
282  *
283  * @param Spi SPI to be used
284  ***********************************************************************/
285 extern void SpiFlush(const struct spi_t *Spi);
286 
287 /**********************************************************************/
288 /**
289  * @brief Name: SpiIsBusy\n
290  * WARNING: SpiCsEnable() must be called prior to this function.
291  * Testes if transmitter is busy, i.e. if data in transmit buffer and/or shift register.
292  *
293  * @param Spi SPI to be used
294  * @return true if busy, else false
295  ***********************************************************************/
296 static inline bool SpiIsBusy(const struct spi_t *Spi)
297 {
298  struct spi_state_t *State = Spi->State;
299  return State->Busy;
300 }
301 
302 /**********************************************************************/
303 /**
304  * @brief Name: SpiCsInit\n
305  * Initializes SPI chip select instance.
306  * Called once from main program level before first SpiCsEnable() use.
307  *
308  * @param ChipSelect CS parameters to be used
309  * @param MaxBaudrate Maximal baudrate for this CS
310  ***********************************************************************/
311 extern void SpiCsInit(struct spi_cs_t ChipSelect, uint32_t MaxBaudrate);
312 
313 /**********************************************************************/
314 /**
315  * @brief Name: SpiCsEnable\n
316  * Enables peripheral clock for USART, updates SPI setting according to
317  * ChipSelect, and activates chip select pin.
318  *
319  * @param Spi SPI to be used
320  * @param ChipSelect Chip select structure
321  * @param Baudrate If Baudrate = 0, default baudrate is used
322  * @return false if SPI is already in use, else true
323  ***********************************************************************/
324 extern bool SpiCsEnable(const struct spi_t *Spi, struct spi_cs_t ChipSelect, uint32_t Baudrate);
325 
326 /**********************************************************************/
327 /**
328  * @brief Name: SpiCsRegisterWait\n
329  * Registers a work to be executed when the SPI block becomes available.
330  *
331  * @param Spi SPI to be used
332  * @param Work The work item will be scheduled as soon as the SPI block
333  * becomes available.
334  ***********************************************************************/
335 extern void SpiCsRegisterWait(const struct spi_t *Spi, struct work_t *Work);
336 
337 /**********************************************************************/
338 /**
339  * @brief Name: SpiCsWait\n
340  * Enables peripheral clock for USART, updates SPI setting according to
341  * ChipSelect, and activates chip select pin.
342  *
343  * @param Spi SPI to be used
344  * @param ChipSelect Chip select structure
345  * @param Baudrate If Baudrate = 0, default baudrate is used
346  * @param Work If SPI is already in use, the work item will be scheduled
347  * as soon as it becomes available again.
348  * @return false if SPI is already in use, else true
349  ***********************************************************************/
350 static inline bool __attribute__((warn_unused_result))
351  SpiCsWait(const struct spi_t *Spi, struct spi_cs_t ChipSelect, uint32_t Baudrate, struct work_t *Work)
352 {
353  bool Ret = SpiCsEnable(Spi, ChipSelect, Baudrate);
354  if (!Ret)
355  SpiCsRegisterWait(Spi, Work);
356  return Ret;
357 }
358 
359 /**********************************************************************/
360 /**
361  * @brief Name: SpiCsDisable\n
362  * Waits for any ongoing transmission to end, flush RX FIFO, disables
363  * chip select pin and disables peripheral clock for USART.
364  *
365  * @param Spi SPI to be used
366  * @param ChipSelect Chip select structure
367  ***********************************************************************/
368 extern void SpiCsDisable(const struct spi_t *Spi, struct spi_cs_t ChipSelect);
369 
370 /**********************************************************************/
371 /**
372  * @brief Name: SpiCsIsActive\n
373  * Checks that the given chip select is active.
374  *
375  * @param Spi SPI to be used
376  * @param ChipSelect Chip select structure
377  * @return true if the chip select is active, false otherwise
378  ***********************************************************************/
379 static inline bool SpiCsIsActive(const struct spi_t *Spi, struct spi_cs_t ChipSelect)
380 {
381  return (Spi->State->ChipSelect.Raw == ChipSelect.Raw);
382 }
383 
384 /**********************************************************************/
385 /**
386  * @brief Name: SpiInterruptHandler\n
387  * SPI interrupt handler
388  * Called from board.c at hardware interrupt context.
389  *
390  * @param Spi SPI parameters to be used
391  ***********************************************************************/
392 extern void SpiInterruptHandler(const struct spi_t *Spi);
393 
394 #if 0
395 /**********************************************************************/
396 /**
397  * @brief Name: SpiReadFast\n
398  * WARNING: SpiWriteFast() must be called prior to this function.
399  * Waits for data received in RX FIFO.
400  *
401  * @param Spi SPI to be used
402  * @return Received data
403  ***********************************************************************/
404 static inline uint8_t SpiReadFast(const struct spi_t *Spi)
405 {
406  register NRF_SPI_Type *Usart = Spi->Usart;
407 
408  while (Usart->EVENTS_READY == 0);
409  Usart->EVENTS_READY = 0;
410  return nrf_spi_rxd_get(Usart);
411 }
412 
413 /**********************************************************************/
414 /**
415  * @brief Name: SpiWriteFast\n
416  * WARNING: SpiCsEnable() must be called prior to this function.
417  * Sends 1 byte without waiting for available space in FIFO.
418  * Caller must take case for the TX FIFO status.
419  *
420  * @param Spi SPI to be used
421  * @param DataToSend Data to be sent
422  ***********************************************************************/
423 static inline void SpiWriteFast(const struct spi_t *Spi, uint8_t DataToSend)
424 {
425  register NRF_SPI_Type *Usart = Spi->Usart;
426 
427  nrf_spi_txd_set(Usart, DataToSend);
428 }
429 
430 /**********************************************************************/
431 /**
432  * @brief Name: SpiWriteReadFast\n
433  * WARNING: SpiCsEnable() must be called prior to this function.
434  * Sends 1 byte without waiting for available space in FIFO.
435  * Caller must take case for the TX FIFO status.
436  * Waits for data received in RX FIFO.
437  *
438  * @param Spi SPI to be used
439  * @param DataToSend Data to be sent
440  * @return Received data
441  ***********************************************************************/
442 static inline uint8_t SpiWriteReadFast(const struct spi_t *Spi, uint8_t DataToSend)
443 {
444  register NRF_SPI_Type *Usart = Spi->Usart;
445 
446  nrf_spi_txd_set(Usart, DataToSend);
447 
448  while (Usart->EVENTS_READY == 0);
449  Usart->EVENTS_READY = 0;
450  return nrf_spi_rxd_get(Usart);
451 }
452 #endif
453 /** \} */
454 
455 /** \} */
456 
457 #endif //DRIVER_SPI_H
Generic data buffer.
uint8_t SpiRead(const struct spi_t *Spi)
Name: SpiRead WARNING: SpiWrite() must be called prior to this function. Waits for data received in R...
uint32_t CsPin
Definition: spi.h:123
Definition: spi.h:106
void SpiCsRegisterWait(const struct spi_t *Spi, struct work_t *Work)
Name: SpiCsRegisterWait Registers a work to be executed when the SPI block becomes available...
void SpiInit(const struct spi_t *Spi)
Name: SpiInit Initializes SPI based on selected device. Master operation: Baudrate is limited to 0...
struct spi_state_t * State
Definition: spi.h:170
uint32_t Master
Definition: spi.h:118
void SpiDisable(const struct spi_t *Spi)
Name: SpiDisable Disables SPI based on selected device. Called from main program level.
void SpiCsDisable(const struct spi_t *Spi, struct spi_cs_t ChipSelect)
Name: SpiCsDisable Waits for any ongoing transmission to end, flush RX FIFO, disables chip select pin...
Driver for port initialisazion and IO functions for nRF52 uC.
Definition: spi.h:105
uint8_t FifoPos
Definition: spi.h:154
void SpiFlush(const struct spi_t *Spi)
Name: SpiFlush WARNING: SpiCsEnable() must be called prior to this function. Waits for any previously...
void SpiTransferSync(const struct spi_t *Spi, const void *TxBuffer, uint32_t TxLength, void *RxBuffer, uint32_t RxLength, uint32_t Flags)
Name: SpiTransferSync WARNING: SpiCsEnable() must be called prior to this function. Does synchronous data transfer (both transmit and receive).
static bool __attribute__((warn_unused_result)) SpiCsWait(const struct spi_t *Spi
Name: SpiCsWait Enables peripheral clock for USART, updates SPI setting according to ChipSelect...
struct data_buffer_t RxBuffer
Definition: spi.h:146
spi_async_callback_t Callback
Definition: spi.h:148
uint32_t IrqPriority
Definition: spi.h:169
static bool SpiIsBusy(const struct spi_t *Spi)
Name: SpiIsBusy WARNING: SpiCsEnable() must be called prior to this function. Testes if transmitter i...
Definition: spi.h:296
void SpiInterruptHandler(const struct spi_t *Spi)
Name: SpiInterruptHandler SPI interrupt handler Called from board.c at hardware interrupt context...
The code implements Dummy Headed Doubly Linked Circularlist (DHDLC) primitive.
uint32_t MsbFirst
Definition: spi.h:119
Definition: spi.h:113
uint8_t FifoTxUsed
Definition: spi.h:152
uint32_t DefaultBaudrate
Definition: spi.h:171
void(* spi_async_callback_t)(const struct spi_t *Spi, void *CallbackData)
Definition: spi.h:137
uint32_t ClkPin
Definition: spi.h:122
uint8_t Errata58_GPIOTE_ID
Definition: spi.h:174
Header file for the EVE clock management framework.
void * CallbackData
Definition: spi.h:149
NRF_SPIM_Type * Dev
Definition: spi.h:168
struct spi_cs_t ChipSelect
Definition: spi.h:145
uint32_t CsActiveHigh
Definition: spi.h:124
Definition: spi.h:104
uint8_t SpiWriteRead(const struct spi_t *Spi, uint8_t DataToSend)
Name: SpiWriteRead WARNING: SpiCsEnable() must be called prior to this function. Waits for empty tran...
uint32_t Mode
Definition: spi.h:117
Definition: dlist.h:66
Definition: spi.h:103
spi_transfer_flags_t
Definition: spi.h:86
void SpiWrite(const struct spi_t *Spi, uint8_t DataToSend)
Name: SpiWrite WARNING: SpiCsEnable() must be called prior to this function. Waits for empty transmit...
uint32_t MosiPin
Definition: spi.h:120
spi_mode_t
Definition: spi.h:101
uint32_t CsUnInitialized
Definition: spi.h:125
uint32_t MisoPin
Definition: spi.h:121
bool Errata58
Definition: spi.h:157
uint8_t FifoRxUsed
Definition: spi.h:153
void SpiCsInit(struct spi_cs_t ChipSelect, uint32_t MaxBaudrate)
Name: SpiCsInit Initializes SPI chip select instance. Called once from main program level before firs...
uint8_t Errata58_PPI_ID
Definition: spi.h:173
static bool SpiCsIsActive(const struct spi_t *Spi, struct spi_cs_t ChipSelect)
Name: SpiCsIsActive Checks that the given chip select is active.
Definition: spi.h:379
bool SpiCsEnable(const struct spi_t *Spi, struct spi_cs_t ChipSelect, uint32_t Baudrate)
Name: SpiCsEnable Enables peripheral clock for USART, updates SPI setting according to ChipSelect...
#define SPI_SYNC_FIFO_DEPTH
Definition: spi.h:77
volatile bool Busy
Definition: spi.h:155
Definition: spi.h:166
struct data_buffer_t TxBuffer
Definition: spi.h:147
Definition: work.h:140
void SpiTransferAsync(const struct spi_t *Spi, const void *TxBuffer, uint32_t TxLength, void *RxBuffer, uint32_t RxLength, spi_async_callback_t Callback, void *CallbackData)
Name: SpiTransferAsync WARNING: SpiCsEnable() must be called prior to this function. Starts asynchronous data transfer (both transmit and receive).