ChibiOS 21.11.4
hal_spi_v1.inc
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.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 *
330 * @param[in] spip pointer to the @p SPIDriver object
331 * @param[in] n number of words to be ignored
332 *
333 * @api
334 */
335void spiIgnore(SPIDriver *spip, size_t n) {
336
337 osalDbgCheck((spip != NULL) && (n > 0U));
338#if SPI_SUPPORTS_CIRCULAR
339 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
340#endif
341
342 osalSysLock();
343 osalDbgAssert(spip->state == SPI_READY, "not ready");
344 spiStartIgnoreI(spip, n);
345 (void) osalThreadSuspendS(&spip->thread);
347}
348
349/**
350 * @brief Exchanges data on the SPI bus.
351 * @details This synchronous function performs a simultaneous transmit/receive
352 * operation.
353 * @pre In order to use this function the option @p SPI_USE_WAIT must be
354 * enabled.
355 * @note The buffers are organized as uint8_t arrays for data sizes below
356 * or equal to 8 bits else it is organized as uint16_t arrays.
357 *
358 * @param[in] spip pointer to the @p SPIDriver object
359 * @param[in] n number of words to be exchanged
360 * @param[in] txbuf the pointer to the transmit buffer
361 * @param[out] rxbuf the pointer to the receive buffer
362 *
363 * @api
364 */
365void spiExchange(SPIDriver *spip, size_t n,
366 const void *txbuf, void *rxbuf) {
367
368 osalDbgCheck((spip != NULL) && (n > 0U) &&
369 (rxbuf != NULL) && (txbuf != NULL));
370#if SPI_SUPPORTS_CIRCULAR
371 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
372#endif
373
374 osalSysLock();
375 osalDbgAssert(spip->state == SPI_READY, "not ready");
376 spiStartExchangeI(spip, n, txbuf, rxbuf);
377 (void) osalThreadSuspendS(&spip->thread);
379}
380
381/**
382 * @brief Sends data over the SPI bus.
383 * @details This synchronous function performs a transmit operation.
384 * @pre In order to use this function the option @p SPI_USE_WAIT must be
385 * enabled.
386 * @note The buffers are organized as uint8_t arrays for data sizes below
387 * or equal to 8 bits else it is organized as uint16_t arrays.
388 *
389 * @param[in] spip pointer to the @p SPIDriver object
390 * @param[in] n number of words to send
391 * @param[in] txbuf the pointer to the transmit buffer
392 *
393 * @api
394 */
395void spiSend(SPIDriver *spip, size_t n, const void *txbuf) {
396
397 osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL));
398#if SPI_SUPPORTS_CIRCULAR
399 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
400#endif
401
402 osalSysLock();
403 osalDbgAssert(spip->state == SPI_READY, "not ready");
404 spiStartSendI(spip, n, txbuf);
405 (void) osalThreadSuspendS(&spip->thread);
407}
408
409/**
410 * @brief Receives data from the SPI bus.
411 * @details This synchronous function performs a receive operation.
412 * @pre In order to use this function the option @p SPI_USE_WAIT must be
413 * enabled.
414 * @note The buffers are organized as uint8_t arrays for data sizes below
415 * or equal to 8 bits else it is organized as uint16_t arrays.
416 *
417 * @param[in] spip pointer to the @p SPIDriver object
418 * @param[in] n number of words to receive
419 * @param[out] rxbuf the pointer to the receive buffer
420 *
421 * @api
422 */
423void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
424
425 osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL));
426#if SPI_SUPPORTS_CIRCULAR
427 osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
428#endif
429
430 osalSysLock();
431 osalDbgAssert(spip->state == SPI_READY, "not ready");
432 spiStartReceiveI(spip, n, rxbuf);
433 (void) osalThreadSuspendS(&spip->thread);
435}
436#endif /* SPI_USE_WAIT == TRUE */
437
438#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
439/**
440 * @brief Gains exclusive access to the SPI bus.
441 * @details This function tries to gain ownership to the SPI bus, if the bus
442 * is already being used then the invoking thread is queued.
443 * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
444 * must be enabled.
445 *
446 * @param[in] spip pointer to the @p SPIDriver object
447 *
448 * @api
449 */
451
452 osalDbgCheck(spip != NULL);
453
454 osalMutexLock(&spip->mutex);
455}
456
457/**
458 * @brief Releases exclusive access to the SPI bus.
459 * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
460 * must be enabled.
461 *
462 * @param[in] spip pointer to the @p SPIDriver object
463 *
464 * @api
465 */
467
468 osalDbgCheck(spip != NULL);
469
470 osalMutexUnlock(&spip->mutex);
471}
472#endif /* SPI_USE_MUTUAL_EXCLUSION == TRUE */
473
474#endif /* HAL_USE_SPI == TRUE */
475
476/** @} */
#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:254
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: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
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: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 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:241
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:361
#define spiAbortI(spip)
Compatibility API with SPI driver v1.
Definition hal_spi_v2.h:352
int32_t msg_t
Definition chearly.h:88
#define MSG_OK
Normal wakeup message.
Definition chschd.h:39
bool circular
Enables the circular buffer mode.
Definition hal_spi_v1.h:143
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