ChibiOS 21.11.4
hal_uart.c
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_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 *
375 * @param[in] uartp pointer to the @p UARTDriver object
376 * @param[in,out] np number of data frames to transmit, on exit the number
377 * of frames actually transmitted
378 * @param[in] txbuf the pointer to the transmit buffer
379 * @param[in] timeout operation timeout
380 * @return The operation status.
381 * @retval MSG_OK if the operation completed successfully.
382 * @retval MSG_TIMEOUT if the operation timed out.
383 *
384 * @api
385 */
387 const void *txbuf, sysinterval_t timeout) {
388 msg_t msg;
389
390 osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
391
392 osalSysLock();
393 osalDbgAssert(uartp->state == UART_READY, "is active");
394 osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
395
396 /* Transmission start.*/
397 uartp->early = true;
398 uart_lld_start_send(uartp, *np, txbuf);
399 uartp->txstate = UART_TX_ACTIVE;
400
401 /* Waiting for result.*/
402 msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout);
403 if (msg != MSG_OK) {
404 *np -= uartStopSendI(uartp);
405 }
407
408 return msg;
409}
410
411/**
412 * @brief Performs a transmission on the UART peripheral.
413 * @note The function returns when the specified number of frames have been
414 * physically transmitted or on timeout.
415 * @note The buffers are organized as uint8_t arrays for data sizes below
416 * or equal to 8 bits else it is organized as uint16_t arrays.
417 * @note This function implements a software timeout, it does not use
418 * any underlying HW timeout mechanism.
419 *
420 * @param[in] uartp pointer to the @p UARTDriver object
421 * @param[in,out] np number of data frames to transmit, on exit the number
422 * of frames actually transmitted
423 * @param[in] txbuf the pointer to the transmit buffer
424 * @param[in] timeout operation timeout
425 * @return The operation status.
426 * @retval MSG_OK if the operation completed successfully.
427 * @retval MSG_TIMEOUT if the operation timed out.
428 *
429 * @api
430 */
432 const void *txbuf, sysinterval_t timeout) {
433 msg_t msg;
434
435 osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
436
437 osalSysLock();
438 osalDbgAssert(uartp->state == UART_READY, "is active");
439 osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
440
441 /* Transmission start.*/
442 uartp->early = false;
443 uart_lld_start_send(uartp, *np, txbuf);
444 uartp->txstate = UART_TX_ACTIVE;
445
446 /* Waiting for result.*/
447 msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout);
448 if (msg != MSG_OK) {
449 *np -= uartStopSendI(uartp);
450 }
452
453 return msg;
454}
455
456/**
457 * @brief Performs a receive operation on the UART peripheral.
458 * @note The function returns when the specified number of frames have been
459 * received or on error/timeout.
460 * @note The buffers are organized as uint8_t arrays for data sizes below
461 * or equal to 8 bits else it is organized as uint16_t arrays.
462 * @note This function implements a software timeout, it does not use
463 * any underlying HW timeout mechanism.
464 *
465 * @param[in] uartp pointer to the @p UARTDriver object
466 * @param[in,out] np number of data frames to receive, on exit the number
467 * of frames actually received
468 * @param[in] rxbuf the pointer to the receive buffer
469 * @param[in] timeout operation timeout
470 *
471 * @return The operation status.
472 * @retval MSG_OK if the operation completed successfully.
473 * @retval MSG_TIMEOUT if the operation timed out.
474 * @retval MSG_RESET in case of a receive error.
475 *
476 * @api
477 */
479 void *rxbuf, sysinterval_t timeout) {
480 msg_t msg;
481
482 osalDbgCheck((uartp != NULL) && (*np > 0U) && (rxbuf != NULL));
483
484 osalSysLock();
485 osalDbgAssert(uartp->state == UART_READY, "is active");
486 osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active");
487
488 /* Receive start.*/
489 uart_lld_start_receive(uartp, *np, rxbuf);
490 uartp->rxstate = UART_RX_ACTIVE;
491
492 /* Waiting for result.*/
493 msg = osalThreadSuspendTimeoutS(&uartp->threadrx, timeout);
494 if (msg != MSG_OK) {
495 *np -= uartStopReceiveI(uartp);
496 }
498
499 return msg;
500}
501#endif
502
503#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
504/**
505 * @brief Gains exclusive access to the UART bus.
506 * @details This function tries to gain ownership to the UART bus, if the bus
507 * is already being used then the invoking thread is queued.
508 * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
509 * must be enabled.
510 *
511 * @param[in] uartp pointer to the @p UARTDriver object
512 *
513 * @api
514 */
516
517 osalDbgCheck(uartp != NULL);
518
519 osalMutexLock(&uartp->mutex);
520}
521
522/**
523 * @brief Releases exclusive access to the UART bus.
524 * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
525 * must be enabled.
526 *
527 * @param[in] uartp pointer to the @p UARTDriver object
528 *
529 * @api
530 */
532
533 osalDbgCheck(uartp != NULL);
534
535 osalMutexUnlock(&uartp->mutex);
536}
537#endif
538
539#endif /* HAL_USE_UART == TRUE */
540
541/** @} */
#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:515
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:478
void uartReleaseBus(UARTDriver *uartp)
Releases exclusive access to the UART bus.
Definition hal_uart.c:531
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:431
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:386
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:109
@ UART_RX_IDLE
Definition hal_uart.h:108
@ UART_TX_IDLE
Definition hal_uart.h:99
@ UART_TX_ACTIVE
Definition hal_uart.h:100
int32_t msg_t
Definition chearly.h:88
#define MSG_OK
Normal wakeup message.
Definition chschd.h:39
uint64_t sysinterval_t
Type of time interval.
Definition chtime.h:119
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.