ChibiOS/HAL  6.1.0
hal_spi.h
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /**
18  * @file hal_spi.h
19  * @brief SPI Driver macros and structures.
20  *
21  * @addtogroup SPI
22  * @{
23  */
24 
25 #ifndef HAL_SPI_H
26 #define HAL_SPI_H
27 
28 #if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
29 
30 /*===========================================================================*/
31 /* Driver constants. */
32 /*===========================================================================*/
33 
34 /**
35  * @name Chip Select modes
36  * @{
37  */
38 #define SPI_SELECT_MODE_NONE 0 /** @brief @p spiSelect() and
39  @p spiUnselect() do
40  nothing. */
41 #define SPI_SELECT_MODE_PAD 1 /** @brief Legacy mode. */
42 #define SPI_SELECT_MODE_PORT 2 /** @brief Fastest mode. */
43 #define SPI_SELECT_MODE_LINE 3 /** @brief Packed mode. */
44 #define SPI_SELECT_MODE_LLD 4 /** @brief LLD-defined mode.*/
45 /** @} */
46 
47 /*===========================================================================*/
48 /* Driver pre-compile time settings. */
49 /*===========================================================================*/
50 
51 /**
52  * @name SPI configuration options
53  * @{
54  */
55 /**
56  * @brief Enables synchronous APIs.
57  * @note Disabling this option saves both code and data space.
58  */
59 #if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
60 #define SPI_USE_WAIT TRUE
61 #endif
62 
63 /**
64  * @brief Enables circular transfers APIs.
65  * @note Disabling this option saves both code and data space.
66  */
67 #if !defined(SPI_USE_CIRCULAR) || defined(__DOXYGEN__)
68 #define SPI_USE_CIRCULAR FALSE
69 #endif
70 
71 /**
72  * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
73  * @note Disabling this option saves both code and data space.
74  */
75 #if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
76 #define SPI_USE_MUTUAL_EXCLUSION TRUE
77 #endif
78 
79 /**
80  * @brief Handling method for SPI CS line.
81  * @note Disabling this option saves both code and data space.
82  */
83 #if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
84 #define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
85 #endif
86 /** @} */
87 
88 /*===========================================================================*/
89 /* Derived constants and error checks. */
90 /*===========================================================================*/
91 
92 #if (SPI_SELECT_MODE != SPI_SELECT_MODE_NONE) && \
93  (SPI_SELECT_MODE != SPI_SELECT_MODE_PAD) && \
94  (SPI_SELECT_MODE != SPI_SELECT_MODE_PORT) && \
95  (SPI_SELECT_MODE != SPI_SELECT_MODE_LINE) && \
96  (SPI_SELECT_MODE != SPI_SELECT_MODE_LLD)
97 #error "invalid SPI_SELECT_MODE setting"
98 #endif
99 
100 /*===========================================================================*/
101 /* Driver data structures and types. */
102 /*===========================================================================*/
103 
104 /**
105  * @brief Driver state machine possible states.
106  */
107 typedef enum {
108  SPI_UNINIT = 0, /**< Not initialized. */
109  SPI_STOP = 1, /**< Stopped. */
110  SPI_READY = 2, /**< Ready. */
111  SPI_ACTIVE = 3, /**< Exchanging data. */
112  SPI_COMPLETE = 4 /**< Asynchronous operation complete. */
113 } spistate_t;
114 
115 #include "hal_spi_lld.h"
116 
117 /* Some more checks, must happen after inclusion of the LLD header, this is
118  why are placed here.*/
119 #if !defined(SPI_SUPPORTS_CIRCULAR)
120 #define SPI_SUPPORTS_CIRCULAR FALSE
121 #endif
122 
123 /*===========================================================================*/
124 /* Driver macros. */
125 /*===========================================================================*/
126 
127 /**
128  * @name Macro Functions
129  * @{
130  */
131 #if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
132 /**
133  * @brief Asserts the slave select signal and prepares for transfers.
134  *
135  * @param[in] spip pointer to the @p SPIDriver object
136  *
137  * @iclass
138  */
139 #define spiSelectI(spip) \
140 do { \
141  spi_lld_select(spip); \
142 } while (false)
143 
144 /**
145  * @brief Deasserts the slave select signal.
146  * @details The previously selected peripheral is unselected.
147  *
148  * @param[in] spip pointer to the @p SPIDriver object
149  *
150  * @iclass
151  */
152 #define spiUnselectI(spip) \
153 do { \
154  spi_lld_unselect(spip); \
155 } while (false)
156 
157 #elif SPI_SELECT_MODE == SPI_SELECT_MODE_LINE
158 #define spiSelectI(spip) \
159 do { \
160  palClearLine((spip)->config->ssline); \
161 } while (false)
162 
163 #define spiUnselectI(spip) \
164 do { \
165  palSetLine((spip)->config->ssline); \
166 } while (false)
167 
168 #elif SPI_SELECT_MODE == SPI_SELECT_MODE_PORT
169 #define spiSelectI(spip) \
170 do { \
171  palClearPort((spip)->config->ssport, (spip)->config->ssmask); \
172 } while (false)
173 
174 #define spiUnselectI(spip) \
175 do { \
176  palSetPort((spip)->config->ssport, (spip)->config->ssmask); \
177 } while (false)
178 
179 #elif SPI_SELECT_MODE == SPI_SELECT_MODE_PAD
180 #define spiSelectI(spip) \
181 do { \
182  palClearPad((spip)->config->ssport, (spip)->config->sspad); \
183 } while (false)
184 
185 #define spiUnselectI(spip) \
186 do { \
187  palSetPad((spip)->config->ssport, (spip)->config->sspad); \
188 } while (false)
189 
190 #elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
191 #define spiSelectI(spip)
192 
193 #define spiUnselectI(spip)
194 #endif
195 
196 /**
197  * @brief Ignores data on the SPI bus.
198  * @details This asynchronous function starts the transmission of a series of
199  * idle words on the SPI bus and ignores the received data.
200  * @pre A slave must have been selected using @p spiSelect() or
201  * @p spiSelectI().
202  * @post At the end of the operation the configured callback is invoked.
203  *
204  * @param[in] spip pointer to the @p SPIDriver object
205  * @param[in] n number of words to be ignored
206  *
207  * @iclass
208  */
209 #define spiStartIgnoreI(spip, n) { \
210  (spip)->state = SPI_ACTIVE; \
211  spi_lld_ignore(spip, n); \
212 }
213 
214 /**
215  * @brief Exchanges data on the SPI bus.
216  * @details This asynchronous function starts a simultaneous transmit/receive
217  * operation.
218  * @pre A slave must have been selected using @p spiSelect() or
219  * @p spiSelectI().
220  * @post At the end of the operation the configured callback is invoked.
221  * @note The buffers are organized as uint8_t arrays for data sizes below
222  * or equal to 8 bits else it is organized as uint16_t arrays.
223  *
224  * @param[in] spip pointer to the @p SPIDriver object
225  * @param[in] n number of words to be exchanged
226  * @param[in] txbuf the pointer to the transmit buffer
227  * @param[out] rxbuf the pointer to the receive buffer
228  *
229  * @iclass
230  */
231 #define spiStartExchangeI(spip, n, txbuf, rxbuf) { \
232  (spip)->state = SPI_ACTIVE; \
233  spi_lld_exchange(spip, n, txbuf, rxbuf); \
234 }
235 
236 /**
237  * @brief Sends data over the SPI bus.
238  * @details This asynchronous function starts a transmit operation.
239  * @pre A slave must have been selected using @p spiSelect() or
240  * @p spiSelectI().
241  * @post At the end of the operation the configured callback is invoked.
242  * @note The buffers are organized as uint8_t arrays for data sizes below
243  * or equal to 8 bits else it is organized as uint16_t arrays.
244  *
245  * @param[in] spip pointer to the @p SPIDriver object
246  * @param[in] n number of words to send
247  * @param[in] txbuf the pointer to the transmit buffer
248  *
249  * @iclass
250  */
251 #define spiStartSendI(spip, n, txbuf) { \
252  (spip)->state = SPI_ACTIVE; \
253  spi_lld_send(spip, n, txbuf); \
254 }
255 
256 /**
257  * @brief Receives data from the SPI bus.
258  * @details This asynchronous function starts a receive operation.
259  * @pre A slave must have been selected using @p spiSelect() or
260  * @p spiSelectI().
261  * @post At the end of the operation the configured callback is invoked.
262  * @note The buffers are organized as uint8_t arrays for data sizes below
263  * or equal to 8 bits else it is organized as uint16_t arrays.
264  *
265  * @param[in] spip pointer to the @p SPIDriver object
266  * @param[in] n number of words to receive
267  * @param[out] rxbuf the pointer to the receive buffer
268  *
269  * @iclass
270  */
271 #define spiStartReceiveI(spip, n, rxbuf) { \
272  (spip)->state = SPI_ACTIVE; \
273  spi_lld_receive(spip, n, rxbuf); \
274 }
275 
276 /**
277  * @brief Exchanges one frame using a polled wait.
278  * @details This synchronous function exchanges one frame using a polled
279  * synchronization method. This function is useful when exchanging
280  * small amount of data on high speed channels, usually in this
281  * situation is much more efficient just wait for completion using
282  * polling than suspending the thread waiting for an interrupt.
283  * @note This API is implemented as a macro in order to minimize latency.
284  *
285  * @param[in] spip pointer to the @p SPIDriver object
286  * @param[in] frame the data frame to send over the SPI bus
287  * @return The received data frame from the SPI bus.
288  */
289 #define spiPolledExchange(spip, frame) spi_lld_polled_exchange(spip, frame)
290 /** @} */
291 
292 /**
293  * @name Low level driver helper macros
294  * @{
295  */
296 #if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
297 /**
298  * @brief Wakes up the waiting thread.
299  *
300  * @param[in] spip pointer to the @p SPIDriver object
301  *
302  * @notapi
303  */
304 #define _spi_wakeup_isr(spip) { \
305  osalSysLockFromISR(); \
306  osalThreadResumeI(&(spip)->thread, MSG_OK); \
307  osalSysUnlockFromISR(); \
308 }
309 #else /* !SPI_USE_WAIT */
310 #define _spi_wakeup_isr(spip)
311 #endif /* !SPI_USE_WAIT */
312 
313 /**
314  * @brief Common ISR code.
315  * @details This code handles the portable part of the ISR code:
316  * - Callback invocation.
317  * - Waiting thread wakeup, if any.
318  * - Driver state transitions.
319  * .
320  * @note This macro is meant to be used in the low level drivers
321  * implementation only.
322  *
323  * @param[in] spip pointer to the @p SPIDriver object
324  *
325  * @notapi
326  */
327 #define _spi_isr_code(spip) { \
328  if ((spip)->config->end_cb) { \
329  (spip)->state = SPI_COMPLETE; \
330  (spip)->config->end_cb(spip); \
331  if ((spip)->state == SPI_COMPLETE) \
332  (spip)->state = SPI_READY; \
333  } \
334  else \
335  (spip)->state = SPI_READY; \
336  _spi_wakeup_isr(spip); \
337 }
338 
339 /**
340  * @brief Common ISR code in circular mode.
341  * @details This code handles the portable part of the ISR code:
342  * - Callback invocation.
343  * .
344  * @note This macro is meant to be used in the low level drivers
345  * implementation only.
346  *
347  * @param[in] spip pointer to the @p SPIDriver object
348  *
349  * @notapi
350  */
351 #define _spi_isr_code_half1(spip) { \
352  if ((spip)->config->end_cb) { \
353  (spip)->config->end_cb(spip); \
354  } \
355 }
356 
357 /**
358  * @brief Common ISR code in circular mode.
359  * @details This code handles the portable part of the ISR code:
360  * - Callback invocation.
361  * - Driver state transitions.
362  * .
363  * @note This macro is meant to be used in the low level drivers
364  * implementation only.
365  *
366  * @param[in] spip pointer to the @p SPIDriver object
367  *
368  * @notapi
369  */
370 #define _spi_isr_code_half2(spip) { \
371  if ((spip)->config->end_cb) { \
372  (spip)->state = SPI_COMPLETE; \
373  (spip)->config->end_cb(spip); \
374  if ((spip)->state == SPI_COMPLETE) \
375  (spip)->state = SPI_ACTIVE; \
376  } \
377 }
378 /** @} */
379 
380 /*===========================================================================*/
381 /* External declarations. */
382 /*===========================================================================*/
383 
384 #ifdef __cplusplus
385 extern "C" {
386 #endif
387  void spiInit(void);
388  void spiObjectInit(SPIDriver *spip);
389  void spiStart(SPIDriver *spip, const SPIConfig *config);
390  void spiStop(SPIDriver *spip);
391  void spiSelect(SPIDriver *spip);
392  void spiUnselect(SPIDriver *spip);
393  void spiStartIgnore(SPIDriver *spip, size_t n);
394  void spiStartExchange(SPIDriver *spip, size_t n,
395  const void *txbuf, void *rxbuf);
396  void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf);
397  void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf);
398 #if SPI_SUPPORTS_CIRCULAR == TRUE
399  void spiAbortI(SPIDriver *spip);
400  void spiAbort(SPIDriver *spip);
401 #endif
402 #if SPI_USE_WAIT == TRUE
403  void spiIgnore(SPIDriver *spip, size_t n);
404  void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);
405  void spiSend(SPIDriver *spip, size_t n, const void *txbuf);
406  void spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
407 #endif
408 #if SPI_USE_MUTUAL_EXCLUSION == TRUE
409  void spiAcquireBus(SPIDriver *spip);
410  void spiReleaseBus(SPIDriver *spip);
411 #endif
412 #ifdef __cplusplus
413 }
414 #endif
415 
416 #endif /* HAL_USE_SPI == TRUE */
417 
418 #endif /* HAL_SPI_H */
419 
420 /** @} */
void spiUnselect(SPIDriver *spip)
Deasserts the slave select signal.
Definition: hal_spi.c:152
spistate_t
Driver state machine possible states.
Definition: hal_spi.h:107
void spiStartExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf)
Exchanges data on the SPI bus.
Definition: hal_spi.c:202
void spiSelect(SPIDriver *spip)
Asserts the slave select signal and prepares for transfers.
Definition: hal_spi.c:134
void spiObjectInit(SPIDriver *spip)
Initializes the standard part of a SPIDriver structure.
Definition: hal_spi.c:68
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf)
Receives data from the SPI bus.
Definition: hal_spi.c:416
void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf)
Exchanges data on the SPI bus.
Definition: hal_spi.c:354
void spiAbortI(SPIDriver *spip)
Aborts the ongoing SPI operation.
Definition: hal_spi.c:272
void spiStart(SPIDriver *spip, const SPIConfig *config)
Configures and activates the SPI peripheral.
Definition: hal_spi.c:91
void spiAbort(SPIDriver *spip)
Aborts the ongoing SPI operation, if any.
Definition: hal_spi.c:294
void spiReleaseBus(SPIDriver *spip)
Releases exclusive access to the SPI bus.
Definition: hal_spi.c:459
void spiInit(void)
SPI Driver initialization.
Definition: hal_spi.c:56
void spiAcquireBus(SPIDriver *spip)
Gains exclusive access to the SPI bus.
Definition: hal_spi.c:443
Driver configuration structure.
Definition: hal_spi_lld.h:83
void spiStartIgnore(SPIDriver *spip, size_t n)
Ignores data on the SPI bus.
Definition: hal_spi.c:175
void spiIgnore(SPIDriver *spip, size_t n)
Ignores data on the SPI bus.
Definition: hal_spi.c:322
PLATFORM SPI subsystem low level driver header.
void spiSend(SPIDriver *spip, size_t n, const void *txbuf)
Sends data over the SPI bus.
Definition: hal_spi.c:386
void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf)
Sends data over the SPI bus.
Definition: hal_spi.c:229
void spiStop(SPIDriver *spip)
Deactivates the SPI peripheral.
Definition: hal_spi.c:111
Structure representing an SPI driver.
Definition: hal_spi_lld.h:128
void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf)
Receives data from the SPI bus.
Definition: hal_spi.c:254