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