ChibiOS 21.11.5
hal_spi_v1.inc
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006-2026 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.inc
19 * @brief SPI (v1) Driver code.
20 *
21 * @addtogroup SPI_V1
22 * @{
23 */
24
25#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
26
27/*===========================================================================*/
28/* Driver local definitions. */
29/*===========================================================================*/
30
31/*===========================================================================*/
32/* Driver exported variables. */
33/*===========================================================================*/
34
35/*===========================================================================*/
36/* Driver local variables and types. */
37/*===========================================================================*/
38
39/*===========================================================================*/
40/* Driver local functions. */
41/*===========================================================================*/
42
43/*===========================================================================*/
44/* Driver exported functions. */
45/*===========================================================================*/
46
47/**
48 * @brief SPI Driver initialization.
49 * @note This function is implicitly invoked by @p halInit(), there is
50 * no need to explicitly initialize the driver.
51 *
52 * @init
53 */
54void spiInit(void) {
55
57}
58
59/**
60 * @brief Initializes the standard part of a @p SPIDriver structure.
61 *
62 * @param[out] spip pointer to the @p SPIDriver object
63 *
64 * @init
65 */
67
68 spip->state = SPI_STOP;
69 spip->config = NULL;
70#if SPI_USE_WAIT == TRUE
71 spip->thread = NULL;
72#endif
73#if SPI_USE_MUTUAL_EXCLUSION == TRUE
75#endif
76#if defined(SPI_DRIVER_EXT_INIT_HOOK)
77 SPI_DRIVER_EXT_INIT_HOOK(spip);
78#endif
79}
80
81/**
82 * @brief Configures and activates the SPI peripheral.
83 *
84 * @param[in] spip pointer to the @p SPIDriver object
85 * @param[in] config pointer to the @p SPIConfig object
86 * @return The operation status.
87 *
88 * @api
89 */
90msg_t spiStart(SPIDriver *spip, const SPIConfig *config) {
91 msg_t msg;
92
93 osalDbgCheck((spip != NULL) && (config != NULL));
94
96 osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY),
97 "invalid state");
98
99 spip->config = config;
100
101#if defined(SPI_LLD_ENHANCED_API)
102 msg = spi_lld_start(spip);
103#else
104 spi_lld_start(spip);
105 msg = HAL_RET_SUCCESS;
106#endif
107 if (msg == HAL_RET_SUCCESS) {
108 spip->state = SPI_READY;
109 }
110 else {
111 spip->state = SPI_STOP;
112 }
113
115
116 return msg;
117}
118
119/**
120 * @brief Deactivates the SPI peripheral.
121 *
122 * @param[in] spip pointer to the @p SPIDriver object
123 *
124 * @api
125 */
126void spiStop(SPIDriver *spip) {
127
128 osalDbgCheck(spip != NULL);
129
130 osalSysLock();
131
132 osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY),
133 "invalid state");
134
135 spi_lld_stop(spip);
136 spip->config = NULL;
137 spip->state = SPI_STOP;
138
140}
141
142/**
143 * @brief Asserts the slave select signal and prepares for transfers.
144 *
145 * @param[in] spip pointer to the @p SPIDriver object
146 *
147 * @api
148 */
149void spiSelect(SPIDriver *spip) {
150
151 osalDbgCheck(spip != NULL);
152
153 osalSysLock();
154 osalDbgAssert(spip->state == SPI_READY, "not ready");
155 spiSelectI(spip);
157}
158
159/**
160 * @brief Deasserts the slave select signal.
161 * @details The previously selected peripheral is unselected.
162 *
163 * @param[in] spip pointer to the @p SPIDriver object
164 *
165 * @api
166 */
168
169 osalDbgCheck(spip != NULL);
170
171 osalSysLock();
172 osalDbgAssert(spip->state == SPI_READY, "not ready");
173 spiUnselectI(spip);
175}
176
177/**
178 * @brief Ignores data on the SPI bus.
179 * @details This asynchronous function starts the transmission of a series of
180 * idle words on the SPI bus and ignores the received data.
181 * @pre A slave must have been selected using @p spiSelect() or
182 * @p spiSelectI().
183 * @post At the end of the operation the configured callback is invoked.
184 *
185 * @param[in] spip pointer to the @p SPIDriver object
186 * @param[in] n number of words to be ignored
187 *
188 * @api
189 */
190void spiStartIgnore(SPIDriver *spip, size_t n) {
191
192 osalDbgCheck((spip != NULL) && (n > 0U));
193
194 osalSysLock();
195 osalDbgAssert(spip->state == SPI_READY, "not ready");
196 spiStartIgnoreI(spip, n);
198}
199
200/**
201 * @brief Exchanges data on the SPI bus.
202 * @details This asynchronous function starts a simultaneous transmit/receive
203 * operation.
204 * @pre A slave must have been selected using @p spiSelect() or
205 * @p spiSelectI().
206 * @post At the end of the operation the configured callback is invoked.
207 * @note The buffers are organized as uint8_t arrays for data sizes below
208 * or equal to 8 bits else it is organized as uint16_t arrays.
209 *
210 * @param[in] spip pointer to the @p SPIDriver object
211 * @param[in] n number of words to be exchanged
212 * @param[in] txbuf the pointer to the transmit buffer
213 * @param[out] rxbuf the pointer to the receive buffer
214 *
215 * @api
216 */
217void spiStartExchange(SPIDriver *spip, size_t n,
218 const void *txbuf, void *rxbuf) {
219
220 osalDbgCheck((spip != NULL) && (n > 0U) &&
221 (rxbuf != NULL) && (txbuf != NULL));
222
223 osalSysLock();
224 osalDbgAssert(spip->state == SPI_READY, "not ready");
225 spiStartExchangeI(spip, n, txbuf, rxbuf);
227}
228
229/**
230 * @brief Sends data over the SPI bus.
231 * @details This asynchronous function starts a transmit operation.
232 * @pre A slave must have been selected using @p spiSelect() or
233 * @p spiSelectI().
234 * @post At the end of the operation the configured callback is invoked.
235 * @note The buffers are organized as uint8_t arrays for data sizes below
236 * or equal to 8 bits else it is organized as uint16_t arrays.
237 *
238 * @param[in] spip pointer to the @p SPIDriver object
239 * @param[in] n number of words to send
240 * @param[in] txbuf the pointer to the transmit buffer
241 *
242 * @api
243 */
244void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf) {
245
246 osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL));
247
248 osalSysLock();
249 osalDbgAssert(spip->state == SPI_READY, "not ready");
250 spiStartSendI(spip, n, txbuf);
252}
253
254/**
255 * @brief Receives data from the SPI bus.
256 * @details This asynchronous function starts a receive operation.
257 * @pre A slave must have been selected using @p spiSelect() or
258 * @p spiSelectI().
259 * @post At the end of the operation the configured callback is invoked.
260 * @note The buffers are organized as uint8_t arrays for data sizes below
261 * or equal to 8 bits else it is organized as uint16_t arrays.
262 *
263 * @param[in] spip pointer to the @p SPIDriver object
264 * @param[in] n number of words to receive
265 * @param[out] rxbuf the pointer to the receive buffer
266 *
267 * @api
268 */
269void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf) {
270
271 osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL));
272
273 osalSysLock();
274 osalDbgAssert(spip->state == SPI_READY, "not ready");
275 spiStartReceiveI(spip, n, rxbuf);
277}
278
279#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
280/**
281 * @brief Aborts the ongoing SPI operation.
282 *
283 * @param[in] spip pointer to the @p SPIDriver object
284 *
285 * @iclass
286 */
287void spiAbortI(SPIDriver *spip) {
288
290
291 osalDbgCheck(spip != NULL);
292 osalDbgAssert((spip->state == SPI_ACTIVE) || (spip->state == SPI_COMPLETE),
293 "invalid state");
294
295 spi_lld_abort(spip);
296 spip->state = SPI_READY;
297#if SPI_USE_WAIT == TRUE
299#endif
300}
301
302/**
303 * @brief Aborts the ongoing SPI operation, if any.
304 *
305 * @param[in] spip pointer to the @p SPIDriver object
306 *
307 * @api
308 */
309void spiAbort(SPIDriver *spip) {
310
311 osalSysLock();
312 osalDbgAssert((spip->state == SPI_READY) || (spip->state == SPI_ACTIVE),
313 "invalid state");
314 if (spip->state == SPI_ACTIVE) {
315 spiAbortI(spip);
317 }
319}
320#endif
321
322#if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
323/**
324 * @brief Ignores data on the SPI bus.
325 * @details This synchronous function performs the transmission of a series of
326 * idle words on the SPI bus and ignores the received data.
327 * @pre In order to use this function the option @p SPI_USE_WAIT must be
328 * enabled.
329 * @note If the configured callback starts another transfer before this
330 * function returns then the behavior is undefined.
331 *
332 * @param[in] spip pointer to the @p SPIDriver object
333 * @param[in] n number of words to be ignored
334 *
335 * @api
336 */
337void spiIgnore(SPIDriver *spip, size_t n) {
338
339 osalDbgCheck((spip != NULL) && (n > 0U));
340#if SPI_SUPPORTS_CIRCULAR
341 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
342#endif
343
344 osalSysLock();
345 osalDbgAssert(spip->state == SPI_READY, "not ready");
346 spiStartIgnoreI(spip, n);
347 (void) osalThreadSuspendS(&spip->thread);
349}
350
351/**
352 * @brief Exchanges data on the SPI bus.
353 * @details This synchronous function performs a simultaneous transmit/receive
354 * operation.
355 * @pre In order to use this function the option @p SPI_USE_WAIT must be
356 * enabled.
357 * @note The buffers are organized as uint8_t arrays for data sizes below
358 * or equal to 8 bits else it is organized as uint16_t arrays.
359 * @note If the configured callback starts another transfer before this
360 * function returns then the behavior is undefined.
361 *
362 * @param[in] spip pointer to the @p SPIDriver object
363 * @param[in] n number of words to be exchanged
364 * @param[in] txbuf the pointer to the transmit buffer
365 * @param[out] rxbuf the pointer to the receive buffer
366 *
367 * @api
368 */
369void spiExchange(SPIDriver *spip, size_t n,
370 const void *txbuf, void *rxbuf) {
371
372 osalDbgCheck((spip != NULL) && (n > 0U) &&
373 (rxbuf != NULL) && (txbuf != NULL));
374#if SPI_SUPPORTS_CIRCULAR
375 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
376#endif
377
378 osalSysLock();
379 osalDbgAssert(spip->state == SPI_READY, "not ready");
380 spiStartExchangeI(spip, n, txbuf, rxbuf);
381 (void) osalThreadSuspendS(&spip->thread);
383}
384
385/**
386 * @brief Sends data over the SPI bus.
387 * @details This synchronous function performs a transmit operation.
388 * @pre In order to use this function the option @p SPI_USE_WAIT must be
389 * enabled.
390 * @note The buffers are organized as uint8_t arrays for data sizes below
391 * or equal to 8 bits else it is organized as uint16_t arrays.
392 * @note If the configured callback starts another transfer before this
393 * function returns then the behavior is undefined.
394 *
395 * @param[in] spip pointer to the @p SPIDriver object
396 * @param[in] n number of words to send
397 * @param[in] txbuf the pointer to the transmit buffer
398 *
399 * @api
400 */
401void spiSend(SPIDriver *spip, size_t n, const void *txbuf) {
402
403 osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL));
404#if SPI_SUPPORTS_CIRCULAR
405 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
406#endif
407
408 osalSysLock();
409 osalDbgAssert(spip->state == SPI_READY, "not ready");
410 spiStartSendI(spip, n, txbuf);
411 (void) osalThreadSuspendS(&spip->thread);
413}
414
415/**
416 * @brief Receives data from the SPI bus.
417 * @details This synchronous function performs a receive operation.
418 * @pre In order to use this function the option @p SPI_USE_WAIT must be
419 * enabled.
420 * @note The buffers are organized as uint8_t arrays for data sizes below
421 * or equal to 8 bits else it is organized as uint16_t arrays.
422 * @note If the configured callback starts another transfer before this
423 * function returns then the behavior is undefined.
424 *
425 * @param[in] spip pointer to the @p SPIDriver object
426 * @param[in] n number of words to receive
427 * @param[out] rxbuf the pointer to the receive buffer
428 *
429 * @api
430 */
431void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
432
433 osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL));
434#if SPI_SUPPORTS_CIRCULAR
435 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
436#endif
437
438 osalSysLock();
439 osalDbgAssert(spip->state == SPI_READY, "not ready");
440 spiStartReceiveI(spip, n, rxbuf);
441 (void) osalThreadSuspendS(&spip->thread);
443}
444#endif /* SPI_USE_WAIT == TRUE */
445
446#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
447/**
448 * @brief Gains exclusive access to the SPI bus.
449 * @details This function tries to gain ownership to the SPI bus, if the bus
450 * is already being used then the invoking thread is queued.
451 * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
452 * must be enabled.
453 *
454 * @param[in] spip pointer to the @p SPIDriver object
455 *
456 * @api
457 */
459
460 osalDbgCheck(spip != NULL);
461
462 osalMutexLock(&spip->mutex);
463}
464
465/**
466 * @brief Releases exclusive access to the SPI bus.
467 * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
468 * must be enabled.
469 *
470 * @param[in] spip pointer to the @p SPIDriver object
471 *
472 * @api
473 */
475
476 osalDbgCheck(spip != NULL);
477
478 osalMutexUnlock(&spip->mutex);
479}
480#endif /* SPI_USE_MUTUAL_EXCLUSION == TRUE */
481
482#endif /* HAL_USE_SPI == TRUE */
483
484/** @} */
#define HAL_RET_SUCCESS
Definition hal.h:93
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition osal.h:601
static void osalMutexObjectInit(mutex_t *mp)
Initializes a mutex_t object.
Definition osal.h:753
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition osal.h:611
msg_t osalThreadSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition osal.c:183
void osalOsRescheduleS(void)
Checks if a reschedule is required and performs it.
Definition osal.c:119
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition osal.c:380
void osalThreadResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition osal.c:227
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition osal.c:400
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define osalDbgCheckClassI()
I-Class state check.
Definition osal.h:298
void spiSelect(SPIDriver *spip)
Asserts the slave select signal and prepares for transfers.
#define spiUnselectI(spip)
Deasserts the slave select signal.
Definition hal_spi_v1.h:265
void spiReleaseBus(SPIDriver *spip)
Releases exclusive access to the SPI bus.
void spi_lld_abort(SPIDriver *spip)
Aborts the ongoing SPI operation, if any.
#define spiStartReceiveI(spip, n, rxbuf)
Receives data from the SPI bus.
Definition hal_spi_v1.h:384
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:344
void spi_lld_init(void)
Low level SPI driver initialization.
Definition hal_spi_lld.c:65
void spiAcquireBus(SPIDriver *spip)
Gains exclusive access to the SPI bus.
void spiObjectInit(SPIDriver *spip)
Initializes the standard part of a SPIDriver structure.
void spi_lld_stop(SPIDriver *spip)
Deactivates the SPI peripheral.
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:364
void spiStop(SPIDriver *spip)
Deactivates the SPI peripheral.
#define spiStartIgnoreI(spip, n)
Ignores data on the SPI bus.
Definition hal_spi_v1.h:322
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 spi_lld_start(SPIDriver *spip)
Configures and activates the SPI peripheral.
Definition hal_spi_lld.c:80
#define spiSelectI(spip)
Asserts the slave select signal and prepares for transfers.
Definition hal_spi_v1.h:252
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_STOP
Definition hal_spi_v1.h:108
@ SPI_READY
Definition hal_spi_v1.h:109
@ SPI_COMPLETE
Definition hal_spi_v1.h:111
#define spiAbort(spip)
Compatibility API with SPI driver v1.
Definition hal_spi_v2.h:372
#define spiAbortI(spip)
Compatibility API with SPI driver v1.
Definition hal_spi_v2.h:363
int32_t msg_t
Definition chearly.h:87
#define MSG_OK
Normal wakeup message.
Definition chschd.h:38
bool circular
Enables the circular buffer mode.
Definition hal_spi_v1.h:144
const SPIConfig * config
Current configuration data.
Definition hal_spi_v1.h:198
thread_reference_t thread
Waiting thread.
Definition hal_spi_v1.h:203
mutex_t mutex
Mutex protecting the peripheral.
Definition hal_spi_v1.h:209
spistate_t state
Driver state.
Definition hal_spi_v1.h:194