aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiovanni Di Sirio <gdisirio@gmail.com>2015-11-13 12:33:18 +0000
committerGiovanni Di Sirio <gdisirio@gmail.com>2015-11-13 12:33:18 +0000
commitf098e079d0fd66419adbb226d7045ca810fe9890 (patch)
treee8f37bb7d9a2e04b18ea8a9474b76ef0f14012af
parent4fb6d9644ed9672096ddf813262f7d869dbfbb93 (diff)
downloadChibiOS-f098e079d0fd66419adbb226d7045ca810fe9890.tar.gz
ChibiOS-f098e079d0fd66419adbb226d7045ca810fe9890.tar.bz2
ChibiOS-f098e079d0fd66419adbb226d7045ca810fe9890.zip
Improved UART driver.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8479 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r--os/hal/include/spi.h4
-rw-r--r--os/hal/include/uart.h223
-rw-r--r--os/hal/ports/STM32/LLD/USARTv1/uart_lld.c35
-rw-r--r--os/hal/ports/STM32/LLD/USARTv1/uart_lld.h20
-rw-r--r--os/hal/ports/STM32/LLD/USARTv2/uart_lld.c35
-rw-r--r--os/hal/ports/STM32/LLD/USARTv2/uart_lld.h20
-rw-r--r--os/hal/src/uart.c187
-rw-r--r--os/hal/templates/uart_lld.h20
-rw-r--r--readme.txt1
9 files changed, 483 insertions, 62 deletions
diff --git a/os/hal/include/spi.h b/os/hal/include/spi.h
index 40592776d..2db152ada 100644
--- a/os/hal/include/spi.h
+++ b/os/hal/include/spi.h
@@ -270,13 +270,13 @@ extern "C" {
const void *txbuf, void *rxbuf);
void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf);
-#if SPI_USE_WAIT
+#if SPI_USE_WAIT == TRUE
void spiIgnore(SPIDriver *spip, size_t n);
void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);
void spiSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
#endif
-#if SPI_USE_MUTUAL_EXCLUSION
+#if SPI_USE_MUTUAL_EXCLUSION == TRUE
void spiAcquireBus(SPIDriver *spip);
void spiReleaseBus(SPIDriver *spip);
#endif
diff --git a/os/hal/include/uart.h b/os/hal/include/uart.h
index 75a9e2b58..f619599d9 100644
--- a/os/hal/include/uart.h
+++ b/os/hal/include/uart.h
@@ -47,6 +47,27 @@
/* Driver pre-compile time settings. */
/*===========================================================================*/
+/**
+ * @name UART configuration options
+ * @{
+ */
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION TRUE
+#endif
+/** @} */
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -88,6 +109,196 @@ typedef enum {
/* Driver macros. */
/*===========================================================================*/
+/**
+ * @name Low level driver helper macros
+ * @{
+ */
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of early TX complete.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_tx1_isr(uartp) { \
+ if ((uartp)->early == true) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadtx, MSG_OK); \
+ osalSysUnlockFromISR(); \
+ } \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_tx1_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of late TX complete.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_tx2_isr(uartp) { \
+ if ((uartp)->early == false) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadtx, MSG_OK); \
+ osalSysUnlockFromISR(); \
+ } \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_tx2_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of RX complete.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_rx_complete_isr(uartp) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadrx, MSG_OK); \
+ osalSysUnlockFromISR(); \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_rx_complete_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of RX error.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_rx_error_isr(uartp) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadrx, MSG_RESET); \
+ osalSysUnlockFromISR(); \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_rx_error_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+/**
+ * @brief Common ISR code for early TX.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_tx1_isr_code(uartp) { \
+ (uartp)->txstate = UART_TX_COMPLETE; \
+ if ((uartp)->config->txend1_cb != NULL) { \
+ (uartp)->config->txend1_cb(uartp); \
+ } \
+ if ((uartp)->txstate == UART_TX_COMPLETE) { \
+ (uartp)->txstate = UART_TX_IDLE; \
+ } \
+ _uart_wakeup_tx1_isr(uartp); \
+}
+
+/**
+ * @brief Common ISR code for late TX.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_tx2_isr_code(uartp) { \
+ if ((uartp)->config->txend2_cb != NULL) { \
+ (uartp)->config->txend2_cb(uartp); \
+ } \
+ _uart_wakeup_tx2_isr(uartp); \
+}
+
+/**
+ * @brief Common ISR code for RX complete.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_rx_complete_isr_code(uartp) { \
+ (uartp)->rxstate = UART_RX_COMPLETE; \
+ if ((uartp)->config->rxend_cb != NULL) { \
+ (uartp)->config->rxend_cb(uartp); \
+ } \
+ if ((uartp)->rxstate == UART_RX_COMPLETE) { \
+ (uartp)->rxstate = UART_RX_IDLE; \
+ uart_enter_rx_idle_loop(uartp); \
+ } \
+ _uart_wakeup_rx_complete_isr(uartp); \
+}
+
+/**
+ * @brief Common ISR code for RX error.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_rx_error_isr_code(uartp, errors) { \
+ if ((uartp)->config->rxerr_cb != NULL) { \
+ (uartp)->config->rxerr_cb(uartp, errors); \
+ } \
+ _uart_wakeup_rx_error_isr(uartp); \
+}
+
+
+/**
+ * @brief Common ISR code for RX on idle.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_rx_idle_code(uartp) { \
+ if ((uartp)->config->rxchar_cb != NULL) \
+ (uartp)->config->rxchar_cb(uartp, (uartp)->rxbuf); \
+}
+/** @} */
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@@ -107,6 +318,18 @@ extern "C" {
void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf);
size_t uartStopReceive(UARTDriver *uartp);
size_t uartStopReceiveI(UARTDriver *uartp);
+#if UART_USE_WAIT == TRUE
+ msg_t uartSendTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time);
+ msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time);
+ msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np,
+ void *rxbuf, systime_t time);
+#endif
+#if UART_USE_MUTUAL_EXCLUSION == TRUE
+ void uartAcquireBus(UARTDriver *uartp);
+ void uartReleaseBus(UARTDriver *uartp);
+#endif
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c
index b346dba82..ec422dc6c 100644
--- a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c
+++ b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c
@@ -156,7 +156,7 @@ static uartflags_t translate_errors(uint16_t sr) {
*
* @param[in] uartp pointer to the @p UARTDriver object
*/
-static void set_rx_idle_loop(UARTDriver *uartp) {
+static void uart_enter_rx_idle_loop(UARTDriver *uartp) {
uint32_t mode;
/* RX DMA channel preparation, if the char callback is defined then the
@@ -229,7 +229,7 @@ static void usart_start(UARTDriver *uartp) {
u->CR1 = uartp->config->cr1 | cr1;
/* Starting the receiver idle loop.*/
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
}
/**
@@ -252,23 +252,13 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
if (uartp->rxstate == UART_RX_IDLE) {
/* Receiver in idle state, a callback is generated, if enabled, for each
received character and then the driver stays in the same state.*/
- if (uartp->config->rxchar_cb != NULL)
- uartp->config->rxchar_cb(uartp, uartp->rxbuf);
+ _uart_rx_idle_code(uartp);
}
else {
/* Receiver in active state, a callback is generated, if enabled, after
a completed transfer.*/
dmaStreamDisable(uartp->dmarx);
- uartp->rxstate = UART_RX_COMPLETE;
- if (uartp->config->rxend_cb != NULL)
- uartp->config->rxend_cb(uartp);
-
- /* If the callback didn't explicitly change state then the receiver
- automatically returns to the idle state.*/
- if (uartp->rxstate == UART_RX_COMPLETE) {
- uartp->rxstate = UART_RX_IDLE;
- set_rx_idle_loop(uartp);
- }
+ _uart_rx_complete_isr_code(uartp);
}
}
@@ -292,14 +282,7 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {
dmaStreamDisable(uartp->dmatx);
/* A callback is generated, if enabled, after a completed transfer.*/
- uartp->txstate = UART_TX_COMPLETE;
- if (uartp->config->txend1_cb != NULL)
- uartp->config->txend1_cb(uartp);
-
- /* If the callback didn't explicitly change state then the transmitter
- automatically returns to the idle state.*/
- if (uartp->txstate == UART_TX_COMPLETE)
- uartp->txstate = UART_TX_IDLE;
+ _uart_wakeup_tx1_isr(uartp);
}
/**
@@ -318,8 +301,7 @@ static void serve_usart_irq(UARTDriver *uartp) {
if (sr & (USART_SR_LBD | USART_SR_ORE | USART_SR_NE |
USART_SR_FE | USART_SR_PE)) {
u->SR = ~USART_SR_LBD;
- if (uartp->config->rxerr_cb != NULL)
- uartp->config->rxerr_cb(uartp, translate_errors(sr));
+ _uart_rx_error_isr_code(uartp, translate_errors(sr));
}
if ((sr & USART_SR_TC) && (cr1 & USART_CR1_TCIE)) {
@@ -328,8 +310,7 @@ static void serve_usart_irq(UARTDriver *uartp) {
u->CR1 = cr1 & ~USART_CR1_TCIE;
/* End of transmission, a callback is generated.*/
- if (uartp->config->txend2_cb != NULL)
- uartp->config->txend2_cb(uartp);
+ _uart_wakeup_tx2_isr(uartp);
}
}
@@ -820,7 +801,7 @@ size_t uart_lld_stop_receive(UARTDriver *uartp) {
dmaStreamDisable(uartp->dmarx);
n = dmaStreamGetTransactionSize(uartp->dmarx);
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
return n;
}
diff --git a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h
index 3f3bef590..fee0d1413 100644
--- a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h
+++ b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h
@@ -524,6 +524,26 @@ struct UARTDriver {
* @brief Current configuration data.
*/
const UARTConfig *config;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
diff --git a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c
index 59bb6c229..7594669f0 100644
--- a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c
+++ b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c
@@ -179,7 +179,7 @@ static uartflags_t translate_errors(uint32_t isr) {
*
* @param[in] uartp pointer to the @p UARTDriver object
*/
-static void set_rx_idle_loop(UARTDriver *uartp) {
+static void uart_enter_rx_idle_loop(UARTDriver *uartp) {
uint32_t mode;
/* RX DMA channel preparation, if the char callback is defined then the
@@ -243,7 +243,7 @@ static void usart_start(UARTDriver *uartp) {
u->CR1 = uartp->config->cr1 | cr1;
/* Starting the receiver idle loop.*/
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
}
/**
@@ -266,23 +266,13 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
if (uartp->rxstate == UART_RX_IDLE) {
/* Receiver in idle state, a callback is generated, if enabled, for each
received character and then the driver stays in the same state.*/
- if (uartp->config->rxchar_cb != NULL)
- uartp->config->rxchar_cb(uartp, uartp->rxbuf);
+ _uart_rx_idle_code(uartp);
}
else {
/* Receiver in active state, a callback is generated, if enabled, after
a completed transfer.*/
dmaStreamDisable(uartp->dmarx);
- uartp->rxstate = UART_RX_COMPLETE;
- if (uartp->config->rxend_cb != NULL)
- uartp->config->rxend_cb(uartp);
-
- /* If the callback didn't explicitly change state then the receiver
- automatically returns to the idle state.*/
- if (uartp->rxstate == UART_RX_COMPLETE) {
- uartp->rxstate = UART_RX_IDLE;
- set_rx_idle_loop(uartp);
- }
+ _uart_rx_complete_isr_code(uartp);
}
}
@@ -306,14 +296,7 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {
dmaStreamDisable(uartp->dmatx);
/* A callback is generated, if enabled, after a completed transfer.*/
- uartp->txstate = UART_TX_COMPLETE;
- if (uartp->config->txend1_cb != NULL)
- uartp->config->txend1_cb(uartp);
-
- /* If the callback didn't explicitly change state then the transmitter
- automatically returns to the idle state.*/
- if (uartp->txstate == UART_TX_COMPLETE)
- uartp->txstate = UART_TX_IDLE;
+ _uart_wakeup_tx1_isr(uartp);
}
/**
@@ -332,8 +315,7 @@ static void serve_usart_irq(UARTDriver *uartp) {
if (isr & (USART_ISR_LBDF | USART_ISR_ORE | USART_ISR_NE |
USART_ISR_FE | USART_ISR_PE)) {
- if (uartp->config->rxerr_cb != NULL)
- uartp->config->rxerr_cb(uartp, translate_errors(isr));
+ _uart_rx_error_isr_code(uartp, translate_errors(isr));
}
if ((isr & USART_ISR_TC) && (cr1 & USART_CR1_TCIE)) {
@@ -341,8 +323,7 @@ static void serve_usart_irq(UARTDriver *uartp) {
u->CR1 = cr1 & ~USART_CR1_TCIE;
/* End of transmission, a callback is generated.*/
- if (uartp->config->txend2_cb != NULL)
- uartp->config->txend2_cb(uartp);
+ _uart_wakeup_tx2_isr(uartp);
}
}
@@ -940,7 +921,7 @@ size_t uart_lld_stop_receive(UARTDriver *uartp) {
dmaStreamDisable(uartp->dmarx);
n = dmaStreamGetTransactionSize(uartp->dmarx);
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
return n;
}
diff --git a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h
index b8c227842..395cb3054 100644
--- a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h
+++ b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h
@@ -623,6 +623,26 @@ struct UARTDriver {
* @brief Current configuration data.
*/
const UARTConfig *config;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
diff --git a/os/hal/src/uart.c b/os/hal/src/uart.c
index f5e28fd48..f521412ec 100644
--- a/os/hal/src/uart.c
+++ b/os/hal/src/uart.c
@@ -67,10 +67,19 @@ void uartInit(void) {
*/
void uartObjectInit(UARTDriver *uartp) {
- uartp->state = UART_STOP;
- uartp->txstate = UART_TX_IDLE;
- uartp->rxstate = UART_RX_IDLE;
- uartp->config = NULL;
+ uartp->state = UART_STOP;
+ uartp->txstate = UART_TX_IDLE;
+ uartp->rxstate = UART_RX_IDLE;
+ uartp->config = NULL;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ uartp->early = false;
+ uartp->threadrx = NULL;
+ uartp->threadtx = NULL;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ osalMutexObjectInit(&uartp->mutex);
+#endif /* UART_USE_MUTUAL_EXCLUSION */
+
/* Optional, user-defined initializer.*/
#if defined(UART_DRIVER_EXT_INIT_HOOK)
UART_DRIVER_EXT_INIT_HOOK(uartp);
@@ -233,7 +242,7 @@ size_t uartStopSendI(UARTDriver *uartp) {
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] uartp pointer to the @p UARTDriver object
- * @param[in] n number of data frames to send
+ * @param[in] n number of data frames to receive
* @param[in] rxbuf the pointer to the receive buffer
*
* @api
@@ -258,7 +267,7 @@ void uartStartReceive(UARTDriver *uartp, size_t n, void *rxbuf) {
* @note This function has to be invoked from a lock zone.
*
* @param[in] uartp pointer to the @p UARTDriver object
- * @param[in] n number of data frames to send
+ * @param[in] n number of data frames to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @iclass
@@ -333,6 +342,172 @@ size_t uartStopReceiveI(UARTDriver *uartp) {
return 0;
}
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Performs a transmission on the UART peripheral.
+ * @note The function returns when the specified number of frames have been
+ * sent to the UART or on timeout.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in,out] np number of data frames to transmit, on exit the number
+ * of frames actually transmitted
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @return The operation status.
+ * @retval MSG_OK if the operation completed successfully.
+ * @retval MSG_TIMEOUT if the operation timed out.
+ *
+ * @api
+ */
+msg_t uartSendTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time) {
+ msg_t msg;
+
+ osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(uartp->state == UART_READY, "is active");
+ osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
+
+ /* Transmission start.*/
+ uartp->early = true;
+ uart_lld_start_send(uartp, *np, txbuf);
+ uartp->txstate = UART_TX_ACTIVE;
+
+ /* Waiting for result.*/
+ msg = osalThreadSuspendTimeoutS(&uartp->threadtx, time);
+ if (msg != MSG_OK) {
+ *np = uartStopSendI(uartp);
+ }
+ osalSysUnlock();
+
+ return msg;
+}
+
+/**
+ * @brief Performs a transmission on the UART peripheral.
+ * @note The function returns when the specified number of frames have been
+ * physically transmitted or on timeout.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in,out] np number of data frames to transmit, on exit the number
+ * of frames actually transmitted
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @return The operation status.
+ * @retval MSG_OK if the operation completed successfully.
+ * @retval MSG_TIMEOUT if the operation timed out.
+ *
+ * @api
+ */
+msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time) {
+ msg_t msg;
+
+ osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(uartp->state == UART_READY, "is active");
+ osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
+
+ /* Transmission start.*/
+ uartp->early = false;
+ uart_lld_start_send(uartp, *np, txbuf);
+ uartp->txstate = UART_TX_ACTIVE;
+
+ /* Waiting for result.*/
+ msg = osalThreadSuspendTimeoutS(&uartp->threadtx, time);
+ if (msg != MSG_OK) {
+ *np = uartStopSendI(uartp);
+ }
+ osalSysUnlock();
+
+ return msg;
+}
+
+/**
+ * @brief Performs a receive operation on the UART peripheral.
+ * @note The function returns when the specified number of frames have been
+ * received or on error/timeout.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in,out] np number of data frames to receive, on exit the number
+ * of frames actually received
+ * @param[in] rxbuf the pointer to the receive buffer
+ * @param[in] time operation timeout
+ *
+ * @return The operation status.
+ * @retval MSG_OK if the operation completed successfully.
+ * @retval MSG_TIMEOUT if the operation timed out.
+ * @retval MSG_RESET in case of a receive error.
+ *
+ * @api
+ */
+msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np,
+ void *rxbuf, systime_t time) {
+ msg_t msg;
+
+ osalDbgCheck((uartp != NULL) && (*np > 0U) && (rxbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(uartp->state == UART_READY, "is active");
+ osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active");
+
+ /* Receive start.*/
+ uart_lld_start_receive(uartp, *np, rxbuf);
+ uartp->rxstate = UART_RX_ACTIVE;
+
+ /* Waiting for result.*/
+ msg = osalThreadSuspendTimeoutS(&uartp->threadrx, time);
+ if (msg != MSG_OK) {
+ *np = uartStopReceiveI(uartp);
+ }
+ osalSysUnlock();
+
+ return msg;
+}
+#endif
+
+#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Gains exclusive access to the UART bus.
+ * @details This function tries to gain ownership to the UART bus, if the bus
+ * is already being used then the invoking thread is queued.
+ * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @api
+ */
+void uartAcquireBus(UARTDriver *uartp) {
+
+ osalDbgCheck(uartp != NULL);
+
+ osalMutexLock(&uartp->mutex);
+}
+
+/**
+ * @brief Releases exclusive access to the UART bus.
+ * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @api
+ */
+void uartReleaseBus(UARTDriver *uartp) {
+
+ osalDbgCheck(uartp != NULL);
+
+ osalMutexUnlock(&uartp->mutex);
+}
+#endif
+
#endif /* HAL_USE_UART == TRUE */
/** @} */
diff --git a/os/hal/templates/uart_lld.h b/os/hal/templates/uart_lld.h
index 13d105b16..0451dcb21 100644
--- a/os/hal/templates/uart_lld.h
+++ b/os/hal/templates/uart_lld.h
@@ -143,6 +143,26 @@ struct UARTDriver {
* @brief Current configuration data.
*/
const UARTConfig *config;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
diff --git a/readme.txt b/readme.txt
index 995175aa4..06857c225 100644
--- a/readme.txt
+++ b/readme.txt
@@ -76,6 +76,7 @@
- HAL: Introduced preliminary support for STM32F7xx devices.
- HAL: Introduced preliminary support for STM32L4xx devices.
- HAL: Introduced preliminary support for STM32L0xx devices.
+- HAL: Added synchronous API and mutual exclusion to the UART driver.
- HAL: Added PAL driver for STM32L4xx GPIOv3 peripheral.
- HAL: Added I2S driver for STM32 SPIv2 peripheral.
- HAL: Added demos and board files for ST's Nucleo32 boards (F031, F042, F303).