ChibiOS 21.11.5
hal_uart.c
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_uart.c
19 * @brief UART Driver code.
20 *
21 * @addtogroup UART
22 * @{
23 */
24
25#include "hal.h"
26
27#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__)
28
29/*===========================================================================*/
30/* Driver local definitions. */
31/*===========================================================================*/
32
33/*===========================================================================*/
34/* Driver exported variables. */
35/*===========================================================================*/
36
37/*===========================================================================*/
38/* Driver local variables and types. */
39/*===========================================================================*/
40
41/*===========================================================================*/
42/* Driver local functions. */
43/*===========================================================================*/
44
45/*===========================================================================*/
46/* Driver exported functions. */
47/*===========================================================================*/
48
49/**
50 * @brief UART Driver initialization.
51 * @note This function is implicitly invoked by @p halInit(), there is
52 * no need to explicitly initialize the driver.
53 *
54 * @init
55 */
56void uartInit(void) {
57
59}
60
61/**
62 * @brief Initializes the standard part of a @p UARTDriver structure.
63 *
64 * @param[out] uartp pointer to the @p UARTDriver object
65 *
66 * @init
67 */
69
70 uartp->state = UART_STOP;
71 uartp->txstate = UART_TX_IDLE;
72 uartp->rxstate = UART_RX_IDLE;
73 uartp->config = NULL;
74#if UART_USE_WAIT == TRUE
75 uartp->early = false;
76 uartp->threadrx = NULL;
77 uartp->threadtx = NULL;
78#endif /* UART_USE_WAIT */
79#if UART_USE_MUTUAL_EXCLUSION == TRUE
81#endif /* UART_USE_MUTUAL_EXCLUSION */
82
83 /* Optional, user-defined initializer.*/
84#if defined(UART_DRIVER_EXT_INIT_HOOK)
85 UART_DRIVER_EXT_INIT_HOOK(uartp);
86#endif
87}
88
89/**
90 * @brief Configures and activates the UART peripheral.
91 *
92 * @param[in] uartp pointer to the @p UARTDriver object
93 * @param[in] config pointer to the @p UARTConfig object
94 * @return The operation status.
95 *
96 * @api
97 */
98msg_t uartStart(UARTDriver *uartp, const UARTConfig *config) {
99 msg_t msg;
100
101 osalDbgCheck((uartp != NULL) && (config != NULL));
102
103 osalSysLock();
104 osalDbgAssert((uartp->state == UART_STOP) || (uartp->state == UART_READY),
105 "invalid state");
106
107 uartp->config = config;
108
109#if defined(UART_LLD_ENHANCED_API)
110 msg = uart_lld_start(uartp);
111 if (msg == HAL_RET_SUCCESS) {
112 uartp->state = UART_READY;
113 }
114 else {
115 uartp->state = UART_STOP;
116 }
117#else
118 uart_lld_start(uartp);
119 uartp->state = UART_READY;
120 msg = HAL_RET_SUCCESS;
121#endif
122
124
125 return msg;
126}
127
128/**
129 * @brief Deactivates the UART peripheral.
130 *
131 * @param[in] uartp pointer to the @p UARTDriver object
132 *
133 * @api
134 */
135void uartStop(UARTDriver *uartp) {
136
137 osalDbgCheck(uartp != NULL);
138
139 osalSysLock();
140
141 osalDbgAssert((uartp->state == UART_STOP) || (uartp->state == UART_READY),
142 "invalid state");
143
144 uart_lld_stop(uartp);
145 uartp->config = NULL;
146 uartp->state = UART_STOP;
147 uartp->txstate = UART_TX_IDLE;
148 uartp->rxstate = UART_RX_IDLE;
149
151}
152
153/**
154 * @brief Starts a transmission on the UART peripheral.
155 * @note The buffers are organized as uint8_t arrays for data sizes below
156 * or equal to 8 bits else it is organized as uint16_t arrays.
157 *
158 * @param[in] uartp pointer to the @p UARTDriver object
159 * @param[in] n number of data frames to send
160 * @param[in] txbuf the pointer to the transmit buffer
161 *
162 * @api
163 */
164void uartStartSend(UARTDriver *uartp, size_t n, const void *txbuf) {
165
166 osalDbgCheck((uartp != NULL) && (n > 0U) && (txbuf != NULL));
167
168 osalSysLock();
169 osalDbgAssert(uartp->state == UART_READY, "is active");
170 osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
171
172 uart_lld_start_send(uartp, n, txbuf);
173 uartp->txstate = UART_TX_ACTIVE;
175}
176
177/**
178 * @brief Starts a transmission on the UART peripheral.
179 * @note The buffers are organized as uint8_t arrays for data sizes below
180 * or equal to 8 bits else it is organized as uint16_t arrays.
181 * @note This function has to be invoked from a lock zone.
182 *
183 * @param[in] uartp pointer to the @p UARTDriver object
184 * @param[in] n number of data frames to send
185 * @param[in] txbuf the pointer to the transmit buffer
186 *
187 * @iclass
188 */
189void uartStartSendI(UARTDriver *uartp, size_t n, const void *txbuf) {
190
192 osalDbgCheck((uartp != NULL) && (n > 0U) && (txbuf != NULL));
193 osalDbgAssert(uartp->state == UART_READY, "is active");
194 osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
195
196 uart_lld_start_send(uartp, n, txbuf);
197 uartp->txstate = UART_TX_ACTIVE;
198}
199
200/**
201 * @brief Stops any ongoing transmission.
202 * @note Stopping a transmission also suppresses the transmission callbacks.
203 *
204 * @param[in] uartp pointer to the @p UARTDriver object
205 *
206 * @return The number of data frames not transmitted by the
207 * stopped transmit operation.
208 * @retval UART_ERR_NOT_ACTIVE if there was no transmit operation in progress.
209 *
210 * @api
211 */
212size_t uartStopSend(UARTDriver *uartp) {
213 size_t n;
214
215 osalDbgCheck(uartp != NULL);
216
217 osalSysLock();
218 osalDbgAssert(uartp->state == UART_READY, "not active");
219
220 if (uartp->txstate == UART_TX_ACTIVE) {
221 n = uart_lld_stop_send(uartp);
222 uartp->txstate = UART_TX_IDLE;
223 }
224 else {
226 }
228
229 return n;
230}
231
232/**
233 * @brief Stops any ongoing transmission.
234 * @note Stopping a transmission also suppresses the transmission callbacks.
235 * @note This function has to be invoked from a lock zone.
236 *
237 * @param[in] uartp pointer to the @p UARTDriver object
238 *
239 * @return The number of data frames not transmitted by the
240 * stopped transmit operation.
241 * @retval UART_ERR_NOT_ACTIVE if there was no transmit operation in progress.
242 *
243 * @iclass
244 */
245size_t uartStopSendI(UARTDriver *uartp) {
246
248 osalDbgCheck(uartp != NULL);
249 osalDbgAssert(uartp->state == UART_READY, "not active");
250
251 if (uartp->txstate == UART_TX_ACTIVE) {
252 size_t n = uart_lld_stop_send(uartp);
253 uartp->txstate = UART_TX_IDLE;
254 return n;
255 }
256 return UART_ERR_NOT_ACTIVE;
257}
258
259/**
260 * @brief Starts a receive operation on the UART peripheral.
261 * @note The buffers are organized as uint8_t arrays for data sizes below
262 * or equal to 8 bits else it is organized as uint16_t arrays.
263 *
264 * @param[in] uartp pointer to the @p UARTDriver object
265 * @param[in] n number of data frames to receive
266 * @param[in] rxbuf the pointer to the receive buffer
267 *
268 * @api
269 */
270void uartStartReceive(UARTDriver *uartp, size_t n, void *rxbuf) {
271
272 osalDbgCheck((uartp != NULL) && (n > 0U) && (rxbuf != NULL));
273
274 osalSysLock();
275 osalDbgAssert(uartp->state == UART_READY, "is active");
276 osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active");
277
278 uart_lld_start_receive(uartp, n, rxbuf);
279 uartp->rxstate = UART_RX_ACTIVE;
281}
282
283/**
284 * @brief Starts a receive operation on the UART peripheral.
285 * @note The buffers are organized as uint8_t arrays for data sizes below
286 * or equal to 8 bits else it is organized as uint16_t arrays.
287 * @note This function has to be invoked from a lock zone.
288 *
289 * @param[in] uartp pointer to the @p UARTDriver object
290 * @param[in] n number of data frames to receive
291 * @param[out] rxbuf the pointer to the receive buffer
292 *
293 * @iclass
294 */
295void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf) {
296
298 osalDbgCheck((uartp != NULL) && (n > 0U) && (rxbuf != NULL));
299 osalDbgAssert(uartp->state == UART_READY, "is active");
300 osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active");
301
302 uart_lld_start_receive(uartp, n, rxbuf);
303 uartp->rxstate = UART_RX_ACTIVE;
304}
305
306/**
307 * @brief Stops any ongoing receive operation.
308 * @note Stopping a receive operation also suppresses the receive callbacks.
309 *
310 * @param[in] uartp pointer to the @p UARTDriver object
311 *
312 * @return The number of data frames not received by the
313 * stopped receive operation.
314 * @retval UART_ERR_NOT_ACTIVE if there was no receive operation in progress.
315 *
316 * @api
317 */
319 size_t n;
320
321 osalDbgCheck(uartp != NULL);
322
323 osalSysLock();
324 osalDbgAssert(uartp->state == UART_READY, "not active");
325
326 if (uartp->rxstate == UART_RX_ACTIVE) {
327 n = uart_lld_stop_receive(uartp);
328 uartp->rxstate = UART_RX_IDLE;
329 }
330 else {
332 }
334
335 return n;
336}
337
338/**
339 * @brief Stops any ongoing receive operation.
340 * @note Stopping a receive operation also suppresses the receive callbacks.
341 * @note This function has to be invoked from a lock zone.
342 *
343 * @param[in] uartp pointer to the @p UARTDriver object
344 *
345 * @return The number of data frames not received by the
346 * stopped receive operation.
347 * @retval UART_ERR_NOT_ACTIVE if there was no receive operation in progress.
348 *
349 * @iclass
350 */
352
354 osalDbgCheck(uartp != NULL);
355 osalDbgAssert(uartp->state == UART_READY, "not active");
356
357 if (uartp->rxstate == UART_RX_ACTIVE) {
358 size_t n = uart_lld_stop_receive(uartp);
359 uartp->rxstate = UART_RX_IDLE;
360 return n;
361 }
362 return UART_ERR_NOT_ACTIVE;
363}
364
365#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
366/**
367 * @brief Performs a transmission on the UART peripheral.
368 * @note The function returns when the specified number of frames have been
369 * sent to the UART or on timeout.
370 * @note The buffers are organized as uint8_t arrays for data sizes below
371 * or equal to 8 bits else it is organized as uint16_t arrays.
372 * @note This function implements a software timeout, it does not use
373 * any underlying HW timeout mechanism.
374 * @note If the configured callback starts another transmission before this
375 * function returns then the behavior is undefined.
376 *
377 * @param[in] uartp pointer to the @p UARTDriver object
378 * @param[in,out] np number of data frames to transmit, on exit the number
379 * of frames actually transmitted
380 * @param[in] txbuf the pointer to the transmit buffer
381 * @param[in] timeout operation timeout
382 * @return The operation status.
383 * @retval MSG_OK if the operation completed successfully.
384 * @retval MSG_TIMEOUT if the operation timed out.
385 *
386 * @api
387 */
389 const void *txbuf, sysinterval_t timeout) {
390 msg_t msg;
391
392 osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
393
394 osalSysLock();
395 osalDbgAssert(uartp->state == UART_READY, "is active");
396 osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
397
398 /* Transmission start.*/
399 uartp->early = true;
400 uart_lld_start_send(uartp, *np, txbuf);
401 uartp->txstate = UART_TX_ACTIVE;
402
403 /* Waiting for result.*/
404 msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout);
405 if (msg != MSG_OK) {
406 *np -= uartStopSendI(uartp);
407 }
409
410 return msg;
411}
412
413/**
414 * @brief Performs a transmission on the UART peripheral.
415 * @note The function returns when the specified number of frames have been
416 * physically transmitted or on timeout.
417 * @note The buffers are organized as uint8_t arrays for data sizes below
418 * or equal to 8 bits else it is organized as uint16_t arrays.
419 * @note This function implements a software timeout, it does not use
420 * any underlying HW timeout mechanism.
421 * @note If the configured callback starts another transmission before this
422 * function returns then the behavior is undefined.
423 *
424 * @param[in] uartp pointer to the @p UARTDriver object
425 * @param[in,out] np number of data frames to transmit, on exit the number
426 * of frames actually transmitted
427 * @param[in] txbuf the pointer to the transmit buffer
428 * @param[in] timeout operation timeout
429 * @return The operation status.
430 * @retval MSG_OK if the operation completed successfully.
431 * @retval MSG_TIMEOUT if the operation timed out.
432 *
433 * @api
434 */
436 const void *txbuf, sysinterval_t timeout) {
437 msg_t msg;
438
439 osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
440
441 osalSysLock();
442 osalDbgAssert(uartp->state == UART_READY, "is active");
443 osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
444
445 /* Transmission start.*/
446 uartp->early = false;
447 uart_lld_start_send(uartp, *np, txbuf);
448 uartp->txstate = UART_TX_ACTIVE;
449
450 /* Waiting for result.*/
451 msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout);
452 if (msg != MSG_OK) {
453 *np -= uartStopSendI(uartp);
454 }
456
457 return msg;
458}
459
460/**
461 * @brief Performs a receive operation on the UART peripheral.
462 * @note The function returns when the specified number of frames have been
463 * received or on error/timeout.
464 * @note The buffers are organized as uint8_t arrays for data sizes below
465 * or equal to 8 bits else it is organized as uint16_t arrays.
466 * @note This function implements a software timeout, it does not use
467 * any underlying HW timeout mechanism.
468 * @note If the configured callback starts another receive operation before
469 * this function returns then the behavior is undefined.
470 *
471 * @param[in] uartp pointer to the @p UARTDriver object
472 * @param[in,out] np number of data frames to receive, on exit the number
473 * of frames actually received
474 * @param[in] rxbuf the pointer to the receive buffer
475 * @param[in] timeout operation timeout
476 *
477 * @return The operation status.
478 * @retval MSG_OK if the operation completed successfully.
479 * @retval MSG_TIMEOUT if the operation timed out.
480 * @retval MSG_RESET in case of a receive error.
481 *
482 * @api
483 */
485 void *rxbuf, sysinterval_t timeout) {
486 msg_t msg;
487
488 osalDbgCheck((uartp != NULL) && (*np > 0U) && (rxbuf != NULL));
489
490 osalSysLock();
491 osalDbgAssert(uartp->state == UART_READY, "is active");
492 osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active");
493
494 /* Receive start.*/
495 uart_lld_start_receive(uartp, *np, rxbuf);
496 uartp->rxstate = UART_RX_ACTIVE;
497
498 /* Waiting for result.*/
499 msg = osalThreadSuspendTimeoutS(&uartp->threadrx, timeout);
500 if (msg != MSG_OK) {
501 *np -= uartStopReceiveI(uartp);
502 }
504
505 return msg;
506}
507#endif
508
509#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
510/**
511 * @brief Gains exclusive access to the UART bus.
512 * @details This function tries to gain ownership to the UART bus, if the bus
513 * is already being used then the invoking thread is queued.
514 * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
515 * must be enabled.
516 *
517 * @param[in] uartp pointer to the @p UARTDriver object
518 *
519 * @api
520 */
522
523 osalDbgCheck(uartp != NULL);
524
525 osalMutexLock(&uartp->mutex);
526}
527
528/**
529 * @brief Releases exclusive access to the UART bus.
530 * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
531 * must be enabled.
532 *
533 * @param[in] uartp pointer to the @p UARTDriver object
534 *
535 * @api
536 */
538
539 osalDbgCheck(uartp != NULL);
540
541 osalMutexUnlock(&uartp->mutex);
542}
543#endif
544
545#endif /* HAL_USE_UART == TRUE */
546
547/** @} */
#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
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition osal.c:380
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition osal.c:400
msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition osal.c:208
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define osalDbgCheckClassI()
I-Class state check.
Definition osal.h:298
struct hal_uart_config UARTConfig
Driver configuration structure.
void uartInit(void)
UART Driver initialization.
Definition hal_uart.c:56
void uartStartSend(UARTDriver *uartp, size_t n, const void *txbuf)
Starts a transmission on the UART peripheral.
Definition hal_uart.c:164
void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf)
Starts a transmission on the UART peripheral.
void uartStartSendI(UARTDriver *uartp, size_t n, const void *txbuf)
Starts a transmission on the UART peripheral.
Definition hal_uart.c:189
void uartObjectInit(UARTDriver *uartp)
Initializes the standard part of a UARTDriver structure.
Definition hal_uart.c:68
void uart_lld_start(UARTDriver *uartp)
Configures and activates the UART peripheral.
void uartAcquireBus(UARTDriver *uartp)
Gains exclusive access to the UART bus.
Definition hal_uart.c:521
msg_t uartStart(UARTDriver *uartp, const UARTConfig *config)
Configures and activates the UART peripheral.
Definition hal_uart.c:98
void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf)
Starts a receive operation on the UART peripheral.
Definition hal_uart.c:295
msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np, void *rxbuf, sysinterval_t timeout)
Performs a receive operation on the UART peripheral.
Definition hal_uart.c:484
void uartReleaseBus(UARTDriver *uartp)
Releases exclusive access to the UART bus.
Definition hal_uart.c:537
msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np, const void *txbuf, sysinterval_t timeout)
Performs a transmission on the UART peripheral.
Definition hal_uart.c:435
void uartStop(UARTDriver *uartp)
Deactivates the UART peripheral.
Definition hal_uart.c:135
#define UART_ERR_NOT_ACTIVE
Definition hal_uart.h:50
void uart_lld_init(void)
Low level UART driver initialization.
void uartStartReceive(UARTDriver *uartp, size_t n, void *rxbuf)
Starts a receive operation on the UART peripheral.
Definition hal_uart.c:270
size_t uartStopSend(UARTDriver *uartp)
Stops any ongoing transmission.
Definition hal_uart.c:212
size_t uart_lld_stop_send(UARTDriver *uartp)
Stops any ongoing transmission.
size_t uartStopReceive(UARTDriver *uartp)
Stops any ongoing receive operation.
Definition hal_uart.c:318
size_t uartStopSendI(UARTDriver *uartp)
Stops any ongoing transmission.
Definition hal_uart.c:245
size_t uartStopReceiveI(UARTDriver *uartp)
Stops any ongoing receive operation.
Definition hal_uart.c:351
void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf)
Starts a receive operation on the UART peripheral.
msg_t uartSendTimeout(UARTDriver *uartp, size_t *np, const void *txbuf, sysinterval_t timeout)
Performs a transmission on the UART peripheral.
Definition hal_uart.c:388
size_t uart_lld_stop_receive(UARTDriver *uartp)
Stops any ongoing receive operation.
void uart_lld_stop(UARTDriver *uartp)
Deactivates the UART peripheral.
struct hal_uart_driver UARTDriver
Type of structure representing an UART driver.
@ UART_READY
Definition hal_uart.h:92
@ UART_STOP
Definition hal_uart.h:91
@ UART_RX_ACTIVE
Definition hal_uart.h:108
@ UART_RX_IDLE
Definition hal_uart.h:107
@ UART_TX_IDLE
Definition hal_uart.h:99
@ UART_TX_ACTIVE
Definition hal_uart.h:100
int32_t msg_t
Definition chearly.h:87
#define MSG_OK
Normal wakeup message.
Definition chschd.h:38
uint64_t sysinterval_t
Type of time interval.
Definition chtime.h:118
HAL subsystem header.
const UARTConfig * config
Current configuration data.
uartstate_t state
Driver state.
thread_reference_t threadrx
Waiting thread on RX.
uartrxstate_t rxstate
Receiver state.
thread_reference_t threadtx
Waiting thread on TX.
bool early
Synchronization flag for transmit operations.
mutex_t mutex
Mutex protecting the peripheral.
uarttxstate_t txstate
Transmitter state.