Improved UART driver.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8479 35acf78f-673a-0410-8e92-d51de3d6d3f4master
parent
4fb6d9644e
commit
f098e079d0
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
Loading…
Reference in New Issue