ChibiOS 21.11.4
hal_spi_v1.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_v1.h
19 * @brief SPI (v1) Driver macros and structures.
20 *
21 * @addtogroup SPI_V1
22 * @{
23 */
24
25#ifndef HAL_SPI_V1_H
26#define HAL_SPI_V1_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 the @p spiAcquireBus() and @p spiReleaseBus() APIs.
65 * @note Disabling this option saves both code and data space.
66 */
67#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
68#define SPI_USE_MUTUAL_EXCLUSION TRUE
69#endif
70
71/**
72 * @brief Handling method for SPI CS line.
73 * @note Disabling this option saves both code and data space.
74 */
75#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
76#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
77#endif
78/** @} */
79
80/*===========================================================================*/
81/* Derived constants and error checks. */
82/*===========================================================================*/
83
84#if (SPI_SELECT_MODE != SPI_SELECT_MODE_NONE) && \
85 (SPI_SELECT_MODE != SPI_SELECT_MODE_PAD) && \
86 (SPI_SELECT_MODE != SPI_SELECT_MODE_PORT) && \
87 (SPI_SELECT_MODE != SPI_SELECT_MODE_LINE) && \
88 (SPI_SELECT_MODE != SPI_SELECT_MODE_LLD)
89#error "invalid SPI_SELECT_MODE setting"
90#endif
91
92/* Some modes have a dependency on the PAL driver, making the required
93 checks here.*/
94#if ((SPI_SELECT_MODE != SPI_SELECT_MODE_PAD) || \
95 (SPI_SELECT_MODE != SPI_SELECT_MODE_PORT) || \
96 (SPI_SELECT_MODE != SPI_SELECT_MODE_LINE)) && \
97 (HAL_USE_PAL != TRUE)
98#error "current SPI_SELECT_MODE requires HAL_USE_PAL"
99#endif
100
101/*===========================================================================*/
102/* Driver data structures and types. */
103/*===========================================================================*/
104
105/**
106 * @brief Driver state machine possible states.
107 */
108typedef enum {
109 SPI_UNINIT = 0, /**< Not initialized. */
110 SPI_STOP = 1, /**< Stopped. */
111 SPI_READY = 2, /**< Ready. */
112 SPI_ACTIVE = 3, /**< Exchanging data. */
113 SPI_COMPLETE = 4 /**< Asynchronous operation complete. */
114} spistate_t;
115
116/**
117 * @brief Type of a structure representing an SPI driver.
118 */
119typedef struct hal_spi_driver SPIDriver;
120/**
121 * @brief Type of a SPI driver configuration structure.
122 */
123typedef struct hal_spi_config SPIConfig;
124
125/**
126 * @brief SPI notification callback type.
127 *
128 * @param[in] spip pointer to the @p SPIDriver object triggering the
129 * callback
130 */
131typedef void (*spicallback_t)(SPIDriver *spip);
132
133/* Including the low level driver header, it exports information required
134 for completing types.*/
135#include "hal_spi_lld.h"
136
137/**
138 * @brief Driver configuration structure.
139 */
140struct hal_spi_config {
141#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
142 /**
143 * @brief Enables the circular buffer mode.
144 */
145 bool circular;
146#endif
147 /**
148 * @brief Operation complete callback or @p NULL.
149 */
151#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LINE) || defined(__DOXYGEN__)
152 /**
153 * @brief The chip select line.
154 */
156#endif
157#if (SPI_SELECT_MODE == SPI_SELECT_MODE_PORT) || defined(__DOXYGEN__)
158 /**
159 * @brief The chip select port.
160 */
162 /**
163 * @brief The chip select port mask.
164 */
166#endif
167#if (SPI_SELECT_MODE == SPI_SELECT_MODE_PAD) || defined(__DOXYGEN__)
168 /**
169 * @brief The chip select port.
170 */
172 /**
173 * @brief The chip select pad number.
174 */
175 uint_fast8_t sspad;
176#endif
177 /* End of the mandatory fields.*/
179};
180
181/**
182 * @brief Structure representing an SPI driver.
183 */
184struct hal_spi_driver {
185 /**
186 * @brief Driver state.
187 */
189 /**
190 * @brief Current configuration data.
191 */
192 const SPIConfig *config;
193#if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
194 /**
195 * @brief Waiting thread.
196 */
198#endif /* SPI_USE_WAIT == TRUE */
199#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
200 /**
201 * @brief Mutex protecting the peripheral.
202 */
204#endif /* SPI_USE_MUTUAL_EXCLUSION == TRUE */
205#if defined(SPI_DRIVER_EXT_FIELDS)
206 SPI_DRIVER_EXT_FIELDS
207#endif
208 /* End of the mandatory fields.*/
210};
211
212/*===========================================================================*/
213/* Driver macros. */
214/*===========================================================================*/
215
216/**
217 * @name Macro Functions
218 * @{
219 */
220/**
221 * @brief Buffer state.
222 * @note This function is meant to be called from the SPI callback only.
223 *
224 * @param[in] spip pointer to the @p SPIDriver object
225 * @return The buffer state.
226 * @retval false if the driver filled/sent the first half of the
227 * buffer.
228 * @retval true if the driver filled/sent the second half of the
229 * buffer.
230 *
231 * @special
232 */
233#define spiIsBufferComplete(spip) ((bool)((spip)->state == SPI_COMPLETE))
234
235#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
236/**
237 * @brief Asserts the slave select signal and prepares for transfers.
238 *
239 * @param[in] spip pointer to the @p SPIDriver object
240 *
241 * @iclass
242 */
243#define spiSelectI(spip) \
244do { \
245 spi_lld_select(spip); \
246} while (false)
247
248/**
249 * @brief Deasserts the slave select signal.
250 * @details The previously selected peripheral is unselected.
251 *
252 * @param[in] spip pointer to the @p SPIDriver object
253 *
254 * @iclass
255 */
256#define spiUnselectI(spip) \
257do { \
258 spi_lld_unselect(spip); \
259} while (false)
260
261#elif SPI_SELECT_MODE == SPI_SELECT_MODE_LINE
262#define spiSelectI(spip) \
263do { \
264 palClearLine((spip)->config->ssline); \
265} while (false)
266
267#define spiUnselectI(spip) \
268do { \
269 palSetLine((spip)->config->ssline); \
270} while (false)
271
272#elif SPI_SELECT_MODE == SPI_SELECT_MODE_PORT
273#define spiSelectI(spip) \
274do { \
275 palClearPort((spip)->config->ssport, (spip)->config->ssmask); \
276} while (false)
277
278#define spiUnselectI(spip) \
279do { \
280 palSetPort((spip)->config->ssport, (spip)->config->ssmask); \
281} while (false)
282
283#elif SPI_SELECT_MODE == SPI_SELECT_MODE_PAD
284#define spiSelectI(spip) \
285do { \
286 palClearPad((spip)->config->ssport, (spip)->config->sspad); \
287} while (false)
288
289#define spiUnselectI(spip) \
290do { \
291 palSetPad((spip)->config->ssport, (spip)->config->sspad); \
292} while (false)
293
294#elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
295#define spiSelectI(spip)
296
297#define spiUnselectI(spip)
298#endif
299
300/**
301 * @brief Ignores data on the SPI bus.
302 * @details This asynchronous function starts the transmission of a series of
303 * idle words on the SPI bus and ignores the received data.
304 * @pre A slave must have been selected using @p spiSelect() or
305 * @p spiSelectI().
306 * @post At the end of the operation the configured callback is invoked.
307 *
308 * @param[in] spip pointer to the @p SPIDriver object
309 * @param[in] n number of words to be ignored
310 *
311 * @iclass
312 */
313#define spiStartIgnoreI(spip, n) { \
314 (spip)->state = SPI_ACTIVE; \
315 spi_lld_ignore(spip, n); \
316}
317
318/**
319 * @brief Exchanges data on the SPI bus.
320 * @details This asynchronous function starts a simultaneous transmit/receive
321 * operation.
322 * @pre A slave must have been selected using @p spiSelect() or
323 * @p spiSelectI().
324 * @post At the end of the operation the configured callback is invoked.
325 * @note The buffers are organized as uint8_t arrays for data sizes below
326 * or equal to 8 bits else it is organized as uint16_t arrays.
327 *
328 * @param[in] spip pointer to the @p SPIDriver object
329 * @param[in] n number of words to be exchanged
330 * @param[in] txbuf the pointer to the transmit buffer
331 * @param[out] rxbuf the pointer to the receive buffer
332 *
333 * @iclass
334 */
335#define spiStartExchangeI(spip, n, txbuf, rxbuf) { \
336 (spip)->state = SPI_ACTIVE; \
337 spi_lld_exchange(spip, n, txbuf, rxbuf); \
338}
339
340/**
341 * @brief Sends data over the SPI bus.
342 * @details This asynchronous function starts a transmit operation.
343 * @pre A slave must have been selected using @p spiSelect() or
344 * @p spiSelectI().
345 * @post At the end of the operation the configured callback is invoked.
346 * @note The buffers are organized as uint8_t arrays for data sizes below
347 * or equal to 8 bits else it is organized as uint16_t arrays.
348 *
349 * @param[in] spip pointer to the @p SPIDriver object
350 * @param[in] n number of words to send
351 * @param[in] txbuf the pointer to the transmit buffer
352 *
353 * @iclass
354 */
355#define spiStartSendI(spip, n, txbuf) { \
356 (spip)->state = SPI_ACTIVE; \
357 spi_lld_send(spip, n, txbuf); \
358}
359
360/**
361 * @brief Receives data from the SPI bus.
362 * @details This asynchronous function starts a receive operation.
363 * @pre A slave must have been selected using @p spiSelect() or
364 * @p spiSelectI().
365 * @post At the end of the operation the configured callback is invoked.
366 * @note The buffers are organized as uint8_t arrays for data sizes below
367 * or equal to 8 bits else it is organized as uint16_t arrays.
368 *
369 * @param[in] spip pointer to the @p SPIDriver object
370 * @param[in] n number of words to receive
371 * @param[out] rxbuf the pointer to the receive buffer
372 *
373 * @iclass
374 */
375#define spiStartReceiveI(spip, n, rxbuf) { \
376 (spip)->state = SPI_ACTIVE; \
377 spi_lld_receive(spip, n, rxbuf); \
378}
379
380/**
381 * @brief Exchanges one frame using a polled wait.
382 * @details This synchronous function exchanges one frame using a polled
383 * synchronization method. This function is useful when exchanging
384 * small amount of data on high speed channels, usually in this
385 * situation is much more efficient just wait for completion using
386 * polling than suspending the thread waiting for an interrupt.
387 * @note This API is implemented as a macro in order to minimize latency.
388 *
389 * @param[in] spip pointer to the @p SPIDriver object
390 * @param[in] frame the data frame to send over the SPI bus
391 * @return The received data frame from the SPI bus.
392 */
393#define spiPolledExchange(spip, frame) spi_lld_polled_exchange(spip, frame)
394/** @} */
395
396/**
397 * @name Low level driver helper macros
398 * @{
399 */
400#if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
401/**
402 * @brief Wakes up the waiting thread.
403 *
404 * @param[in] spip pointer to the @p SPIDriver object
405 *
406 * @notapi
407 */
408#define _spi_wakeup_isr(spip) { \
409 osalSysLockFromISR(); \
410 osalThreadResumeI(&(spip)->thread, MSG_OK); \
411 osalSysUnlockFromISR(); \
412}
413#else /* !SPI_USE_WAIT */
414#define _spi_wakeup_isr(spip)
415#endif /* !SPI_USE_WAIT */
416
417/**
418 * @brief Common ISR code when circular mode is not supported.
419 * @details This code handles the portable part of the ISR code:
420 * - Callback invocation.
421 * - Waiting thread wakeup, if any.
422 * - Driver state transitions.
423 * .
424 * @note This macro is meant to be used in the low level drivers
425 * implementation only.
426 *
427 * @param[in] spip pointer to the @p SPIDriver object
428 *
429 * @notapi
430 */
431#define _spi_isr_code(spip) { \
432 if ((spip)->config->end_cb) { \
433 (spip)->state = SPI_COMPLETE; \
434 (spip)->config->end_cb(spip); \
435 if ((spip)->state == SPI_COMPLETE) \
436 (spip)->state = SPI_READY; \
437 } \
438 else \
439 (spip)->state = SPI_READY; \
440 _spi_wakeup_isr(spip); \
441}
442
443/**
444 * @brief Half buffer filled ISR code in circular mode.
445 * @details This code handles the portable part of the ISR code:
446 * - Callback invocation.
447 * .
448 * @note This macro is meant to be used in the low level drivers
449 * implementation only.
450 *
451 * @param[in] spip pointer to the @p SPIDriver object
452 *
453 * @notapi
454 */
455#define _spi_isr_half_code(spip) { \
456 if ((spip)->config->end_cb) { \
457 (spip)->config->end_cb(spip); \
458 } \
459}
460
461/**
462 * @brief Full buffer filled ISR code in circular mode.
463 * @details This code handles the portable part of the ISR code:
464 * - Callback invocation.
465 * - Driver state transitions.
466 * .
467 * @note This macro is meant to be used in the low level drivers
468 * implementation only.
469 *
470 * @param[in] spip pointer to the @p SPIDriver object
471 *
472 * @notapi
473 */
474#define _spi_isr_full_code(spip) { \
475 if ((spip)->config->end_cb) { \
476 (spip)->state = SPI_COMPLETE; \
477 (spip)->config->end_cb(spip); \
478 if ((spip)->state == SPI_COMPLETE) \
479 (spip)->state = SPI_ACTIVE; \
480 } \
481}
482/** @} */
483
484/*===========================================================================*/
485/* External declarations. */
486/*===========================================================================*/
487
488#ifdef __cplusplus
489extern "C" {
490#endif
491 void spiInit(void);
492 void spiObjectInit(SPIDriver *spip);
493 msg_t spiStart(SPIDriver *spip, const SPIConfig *config);
494 void spiStop(SPIDriver *spip);
495 void spiSelect(SPIDriver *spip);
496 void spiUnselect(SPIDriver *spip);
497 void spiStartIgnore(SPIDriver *spip, size_t n);
498 void spiStartExchange(SPIDriver *spip, size_t n,
499 const void *txbuf, void *rxbuf);
500 void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf);
501 void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf);
502#if SPI_SUPPORTS_CIRCULAR == TRUE
503 void spiAbortI(SPIDriver *spip);
504 void spiAbort(SPIDriver *spip);
505#endif
506#if SPI_USE_WAIT == TRUE
507 void spiIgnore(SPIDriver *spip, size_t n);
508 void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);
509 void spiSend(SPIDriver *spip, size_t n, const void *txbuf);
510 void spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
511#endif
512#if SPI_USE_MUTUAL_EXCLUSION == TRUE
513 void spiAcquireBus(SPIDriver *spip);
514 void spiReleaseBus(SPIDriver *spip);
515#endif
516#ifdef __cplusplus
517}
518#endif
519
520#endif /* HAL_USE_SPI == TRUE */
521
522#endif /* HAL_SPI_V1_H */
523
524/** @} */
uint32_t ioportid_t
Port Identifier.
uint32_t ioportmask_t
Digital I/O port sized unsigned type.
uint32_t ioline_t
Type of an I/O line.
void spiSelect(SPIDriver *spip)
Asserts the slave select signal and prepares for transfers.
void spiReleaseBus(SPIDriver *spip)
Releases exclusive access to the SPI bus.
spistate_t
Driver state machine possible states.
Definition hal_spi_v1.h:106
#define spi_lld_driver_fields
Low level fields of the SPI driver structure.
Definition hal_spi_lld.h:72
void spiSend(SPIDriver *spip, size_t n, const void *txbuf)
Sends data over the SPI bus.
void spiInit(void)
SPI Driver initialization.
void spiIgnore(SPIDriver *spip, size_t n)
Ignores data on the SPI bus.
struct hal_spi_config SPIConfig
Type of a SPI driver configuration structure.
Definition hal_spi_v1.h:121
#define spi_lld_config_fields
Low level fields of the SPI configuration structure.
Definition hal_spi_lld.h:79
void spiAcquireBus(SPIDriver *spip)
Gains exclusive access to the SPI bus.
void spiObjectInit(SPIDriver *spip)
Initializes the standard part of a SPIDriver structure.
void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf)
Sends data over the SPI bus.
msg_t spiStart(SPIDriver *spip, const SPIConfig *config)
Configures and activates the SPI peripheral.
void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf)
Receives data from the SPI bus.
void spiStartIgnore(SPIDriver *spip, size_t n)
Ignores data on the SPI bus.
struct hal_spi_driver SPIDriver
Type of a structure representing an SPI driver.
Definition hal_spi_v1.h:117
void spiStop(SPIDriver *spip)
Deactivates the SPI peripheral.
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf)
Receives data from the SPI bus.
void spiUnselect(SPIDriver *spip)
Deasserts the slave select signal.
void(* spicallback_t)(SPIDriver *spip)
SPI notification callback type.
Definition hal_spi_v1.h:129
void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf)
Exchanges data on the SPI bus.
void spiStartExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf)
Exchanges data on the SPI bus.
@ SPI_ACTIVE
Definition hal_spi_v1.h:110
@ SPI_UNINIT
Definition hal_spi_v1.h:107
@ SPI_STOP
Definition hal_spi_v1.h:108
@ SPI_READY
Definition hal_spi_v1.h:109
@ SPI_COMPLETE
Definition hal_spi_v1.h:111
spistate_t
Driver state machine possible states.
Definition hal_spi_v2.h:116
struct hal_spi_config SPIConfig
Type of a SPI driver configuration structure.
Definition hal_spi_v2.h:132
#define spiAbort(spip)
Compatibility API with SPI driver v1.
Definition hal_spi_v2.h:361
#define spiAbortI(spip)
Compatibility API with SPI driver v1.
Definition hal_spi_v2.h:352
struct ch_mutex mutex_t
Type of a mutex structure.
Definition chmtx.h:52
int32_t msg_t
Definition chearly.h:88
thread_t * thread_reference_t
Type of a thread reference.
Definition chobjects.h:138
PLATFORM SPI (v1) subsystem low level driver header.
Driver configuration structure.
Definition hal_spi_v1.h:138
ioportid_t ssport
The chip select port.
Definition hal_spi_v1.h:159
spicallback_t end_cb
Operation complete callback or NULL.
Definition hal_spi_v1.h:148
ioportmask_t ssmask
The chip select port mask.
Definition hal_spi_v1.h:163
bool circular
Enables the circular buffer mode.
Definition hal_spi_v1.h:143
uint_fast8_t sspad
The chip select pad number.
Definition hal_spi_v1.h:173
ioline_t ssline
The chip select line.
Definition hal_spi_v1.h:153
Structure representing an SPI driver.
Definition hal_spi_v1.h:182
const SPIConfig * config
Current configuration data.
Definition hal_spi_v1.h:190
thread_reference_t thread
Waiting thread.
Definition hal_spi_v1.h:195
mutex_t mutex
Mutex protecting the peripheral.
Definition hal_spi_v1.h:201
spistate_t state
Driver state.
Definition hal_spi_v1.h:186