Reworked HAL SIO driver.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@15713 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
parent
7f09ea6b8d
commit
57f853674c
|
@ -32,23 +32,97 @@
|
|||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name SIO status flags
|
||||
* @name Events enable flags offsets
|
||||
* @{
|
||||
*/
|
||||
#define SIO_NO_ERROR 0 /**< @brief No pending conditions. */
|
||||
#define SIO_PARITY_ERROR 4 /**< @brief Parity error happened. */
|
||||
#define SIO_FRAMING_ERROR 8 /**< @brief Framing error happened. */
|
||||
#define SIO_OVERRUN_ERROR 16 /**< @brief Overflow happened. */
|
||||
#define SIO_NOISE_ERROR 32 /**< @brief Noise on the line. */
|
||||
#define SIO_BREAK_DETECTED 64 /**< @brief Break detected. */
|
||||
#define SIO_FL_RXNOTEMPY_POS 1
|
||||
#define SIO_FL_TXNOTFULL_POS 2
|
||||
#define SIO_FL_RXIDLE_POS 3
|
||||
#define SIO_FL_TXDONE_POS 4
|
||||
#define SIO_FL_ALL_ERRORS_POS 5
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SIO additional messages
|
||||
* @name Events enable flags
|
||||
* @{
|
||||
*/
|
||||
#define SIO_MSG_IDLE 1
|
||||
#define SIO_MSG_ERRORS 2
|
||||
/**
|
||||
* @brief No events enabled.
|
||||
*/
|
||||
#define SIO_FL_NONE 0U
|
||||
/**
|
||||
* @brief RX buffer not empty event.
|
||||
*/
|
||||
#define SIO_FL_RXNOTEMPY (1U << SIO_FL_RXNOTEMPY_POS)
|
||||
/**
|
||||
* @brief TX buffer not full event.
|
||||
*/
|
||||
#define SIO_FL_TXNOTFULL (1U << SIO_FL_TXNOTFULL_POS)
|
||||
/**
|
||||
* @brief All data-related events.
|
||||
*/
|
||||
#define SIO_FL_ALL_DATA (SIO_FL_RXNOTEMPY | \
|
||||
SIO_FL_TXNOTFULL)
|
||||
/**
|
||||
* @brief RX line idling event.
|
||||
*/
|
||||
#define SIO_FL_RXIDLE (1U << SIO_FL_RXIDLE_POS)
|
||||
/**
|
||||
* @brief TX complete event.
|
||||
*/
|
||||
#define SIO_FL_TXDONE (1U << SIO_FL_TXDONE_POS)
|
||||
/**
|
||||
* @brief All protocol-related events.
|
||||
*/
|
||||
#define SIO_FL_ALL_PROTOCOL (SIO_FL_RXIDLE | \
|
||||
SIO_FL_TXDONE)
|
||||
/**
|
||||
* @brief All RX error events.
|
||||
*/
|
||||
#define SIO_FL_ALL_ERRORS (1U << SIO_FL_ALL_ERRORS_POS)
|
||||
/**
|
||||
* @brief All events.
|
||||
*/
|
||||
#define SIO_FL_ALL (SIO_FL_ALL_DATA | \
|
||||
SIO_FL_ALL_PROTOCOL | \
|
||||
SIO_FL_ALL_ERRORS)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Event flags offsets
|
||||
* @{
|
||||
*/
|
||||
#define SIO_EV_RXNOTEMPY_POS 2 /* CHN_INPUT_AVAILABLE */
|
||||
#define SIO_EV_TXNOTFULL_POS 3 /* CHN_OUTPUT_EMPTY */
|
||||
#define SIO_EV_TXDONE_POS 4 /* CHN_TRANSMISSION_END */
|
||||
#define SIO_EV_PARITY_ERR_POS 5 /* SD_PARITY_ERROR */
|
||||
#define SIO_EV_FRAMING_ERR_POS 6 /* SD_FRAMING_ERROR */
|
||||
#define SIO_EV_OVERRUN_ERR_POS 7 /* SD_OVERRUN_ERROR */
|
||||
#define SIO_EV_NOISE_ERR_POS 8 /* SD_NOISE_ERROR */
|
||||
#define SIO_EV_BREAK_POS 9
|
||||
#define SIO_EV_RXIDLE_POS 11
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Event flags (compatible with channel and serial events)
|
||||
* @{
|
||||
*/
|
||||
#define SIO_EV_RXNOTEMPY (1U << SIO_EV_RXNOTEMPY_POS)
|
||||
#define SIO_EV_TXNOTFULL (1U << SIO_EV_TXNOTFULL_POS)
|
||||
#define SIO_EV_TXDONE (1U << SIO_EV_TXDONE_POS)
|
||||
#define SIO_EV_PARITY_ERR (1U << SIO_EV_PARITY_ERR_POS)
|
||||
#define SIO_EV_FRAMING_ERR (1U << SIO_EV_FRAMING_ERR_POS)
|
||||
#define SIO_EV_OVERRUN_ERR (1U << SIO_EV_OVERRUN_ERR_POS)
|
||||
#define SIO_EV_NOISE_ERR (1U << SIO_EV_NOISE_ERR_POS)
|
||||
#define SIO_EV_BREAK (1U << SIO_EV_BREAK_POS)
|
||||
#define SIO_EV_RXIDLE (1U << SIO_EV_RXIDLE_POS)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Additional messages
|
||||
* @{
|
||||
*/
|
||||
#define SIO_MSG_ERRORS 1
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -85,9 +159,14 @@
|
|||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief SIO driver condition flags type.
|
||||
* @brief Type of events enable flags.
|
||||
*/
|
||||
typedef uint_fast8_t sioflags_t;
|
||||
typedef uint_least8_t sioflags_t;
|
||||
|
||||
/**
|
||||
* @brief Type of event flags.
|
||||
*/
|
||||
typedef eventflags_t sioevents_t;
|
||||
|
||||
/**
|
||||
* @brief Type of structure representing a SIO driver.
|
||||
|
@ -168,15 +247,23 @@ struct hal_sio_driver {
|
|||
* @brief Current configuration data.
|
||||
*/
|
||||
const SIOConfig *config;
|
||||
/**
|
||||
* @brief Enabled conditions flags.
|
||||
*/
|
||||
sioflags_t enabled;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const SIOOperation *operation;
|
||||
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Synchronization point for RX.
|
||||
* @brief Synchronization point for RX.
|
||||
*/
|
||||
thread_reference_t sync_rx;
|
||||
/**
|
||||
* @brief Synchronization point for RX idle.
|
||||
*/
|
||||
thread_reference_t sync_rx;
|
||||
thread_reference_t sync_rxidle;
|
||||
/**
|
||||
* @brief Synchronization point for TX.
|
||||
*/
|
||||
|
@ -198,30 +285,10 @@ struct hal_sio_driver {
|
|||
*/
|
||||
struct hal_sio_operation {
|
||||
/**
|
||||
* @brief Receive non-empty callback.
|
||||
* @brief Events callback.
|
||||
* @note Can be @p NULL.
|
||||
*/
|
||||
siocb_t rx_cb;
|
||||
/**
|
||||
* @brief Receive idle callback.
|
||||
* @note Can be @p NULL.
|
||||
*/
|
||||
siocb_t rx_idle_cb;
|
||||
/**
|
||||
* @brief Transmission buffer non-full callback.
|
||||
* @note Can be @p NULL.
|
||||
*/
|
||||
siocb_t tx_cb;
|
||||
/**
|
||||
* @brief Physical end of transmission callback.
|
||||
* @note Can be @p NULL.
|
||||
*/
|
||||
siocb_t tx_end_cb;
|
||||
/**
|
||||
* @brief Receive event callback.
|
||||
* @note Can be @p NULL.
|
||||
*/
|
||||
siocb_t rx_evt_cb;
|
||||
siocb_t cb;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -233,27 +300,122 @@ struct hal_sio_operation {
|
|||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX FIFO state.
|
||||
* @retval false if RX FIFO is not empty
|
||||
* @retval true if RX FIFO is empty
|
||||
* @retval false if RX FIFO is not empty.
|
||||
* @retval true if RX FIFO is empty.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define sioIsRXEmptyX(siop) sio_lld_is_rx_empty(siop)
|
||||
|
||||
/**
|
||||
* @brief Determines the activity state of the receiver.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX activity state.
|
||||
* @retval false if RX is in active state.
|
||||
* @retval true if RX is in idle state.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define sioIsRXIdleX(siop) sio_lld_is_rx_idle(siop)
|
||||
|
||||
/**
|
||||
* @brief Determines if RX has pending errors to be read and cleared.
|
||||
* @note Only errors are handled, data and idle events are not considered.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX error events.
|
||||
* @retval false if RX has no pending events.
|
||||
* @retval true if RX has pending events.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define sioHasRXErrorsX(siop) sio_lld_has_rx_errors(siop)
|
||||
|
||||
/**
|
||||
* @brief Determines the state of the TX FIFO.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The TX FIFO state.
|
||||
* @retval false if TX FIFO is not full
|
||||
* @retval true if TX FIFO is full
|
||||
* @retval false if TX FIFO is not full.
|
||||
* @retval true if TX FIFO is full.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define sioIsTXFullX(siop) sio_lld_is_tx_full(siop)
|
||||
|
||||
/**
|
||||
* @brief Return the pending SIO events flags.
|
||||
* @brief Determines the transmission state.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The TX FIFO state.
|
||||
* @retval false if transmission is over.
|
||||
* @retval true if transmission is ongoing.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define sioIsTXOngoingX(siop) sio_lld_is_tx_ongoing(siop)
|
||||
|
||||
/**
|
||||
* @brief Writes the condition flags mask.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @param[in] flags flags mask to be written
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define sioWriteEnableFlagsI(siop, flags) do { \
|
||||
(siop)->enabled = (flags); \
|
||||
sio_lld_update_enable_flags(siop); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Enables flags to the condition flags mask.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @param[in] flags flags mask to be enabled
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define sioSetEnableFlagsI(siop, flags) do { \
|
||||
(siop)->enabled |= (flags); \
|
||||
sio_lld_update_enable_flags(siop); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Disables flags from the condition flags mask.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @param[in] flags flags mask to be disabled
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define sioClearEnableFlagsI(siop, flags) do { \
|
||||
(siop)->enabled &= ~(flags); \
|
||||
sio_lld_update_enable_flags(siop); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Return the enabled condition flags mask.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define sioGetEnableFlagsX(siop) (siop)->eflags
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO error event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending error event flags.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define sioGetAndClearErrorsI(siop) sio_lld_get_and_clear_errors(siop)
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
|
@ -337,84 +499,58 @@ struct hal_sio_operation {
|
|||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief RX callback.
|
||||
* @brief SIO callback.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_callback_rx(siop) { \
|
||||
if ((siop)->operation->rx_cb != NULL) { \
|
||||
(siop)->operation->rx_cb(siop); \
|
||||
#define __sio_callback(siop) do { \
|
||||
if ((siop)->operation->cb != NULL) { \
|
||||
(siop)->operation->cb(siop); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RX idle callback.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_callback_rx_idle(siop) { \
|
||||
if ((siop)->operation->rx_idle_cb != NULL) { \
|
||||
(siop)->operation->rx_idle_cb(siop); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TX callback.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_callback_tx(siop) { \
|
||||
if ((siop)->operation->tx_cb != NULL) { \
|
||||
(siop)->operation->tx_cb(siop); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TX end callback.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_callback_tx_end(siop) { \
|
||||
if ((siop)->operation->tx_end_cb != NULL) { \
|
||||
(siop)->operation->tx_end_cb(siop); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RX event callback.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_callback_rx_evt(siop) { \
|
||||
if ((siop)->operation->rx_evt_cb != NULL) { \
|
||||
(siop)->operation->rx_evt_cb(siop); \
|
||||
} \
|
||||
}
|
||||
} while (false)
|
||||
|
||||
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Wakes up because RX errors.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_wakeup_events(siop) do { \
|
||||
osalSysLockFromISR(); \
|
||||
osalThreadResumeI(&(siop)->sync_rx, SIO_MSG_ERRORS); \
|
||||
osalThreadResumeI(&(siop)->sync_rxidle, SIO_MSG_ERRORS); \
|
||||
osalSysUnlockFromISR(); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Wakes up the RX-waiting thread.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @param[in] msg the wake up message
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_wakeup_rx(siop, msg) { \
|
||||
#define __sio_wakeup_rx(siop) do { \
|
||||
osalSysLockFromISR(); \
|
||||
osalThreadResumeI(&(siop)->sync_rx, msg); \
|
||||
osalThreadResumeI(&(siop)->sync_rx, MSG_OK); \
|
||||
osalSysUnlockFromISR(); \
|
||||
}
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Wakes up the RX-idle-waiting thread.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_wakeup_rxidle(siop) do { \
|
||||
osalSysLockFromISR(); \
|
||||
osalThreadResumeI(&(siop)->sync_rxidle, MSG_OK); \
|
||||
osalSysUnlockFromISR(); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Wakes up the TX-waiting thread.
|
||||
|
@ -424,11 +560,11 @@ struct hal_sio_operation {
|
|||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_wakeup_tx(siop, msg) { \
|
||||
#define __sio_wakeup_tx(siop) do { \
|
||||
osalSysLockFromISR(); \
|
||||
osalThreadResumeI(&(siop)->sync_tx, msg); \
|
||||
osalThreadResumeI(&(siop)->sync_tx, MSG_OK); \
|
||||
osalSysUnlockFromISR(); \
|
||||
}
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Wakes up the TXend-waiting thread.
|
||||
|
@ -438,11 +574,11 @@ struct hal_sio_operation {
|
|||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define __sio_wakeup_txend(siop, msg) { \
|
||||
#define __sio_wakeup_txend(siop) do { \
|
||||
osalSysLockFromISR(); \
|
||||
osalThreadResumeI(&(siop)->sync_txend, msg); \
|
||||
osalThreadResumeI(&(siop)->sync_txend, MSG_OK); \
|
||||
osalSysUnlockFromISR(); \
|
||||
}
|
||||
} while (false)
|
||||
#else /* !SIO_USE_SYNCHRONIZATION */
|
||||
#define __sio_wakeup_rx(siop, msg)
|
||||
#define __sio_wakeup_tx(siop, msg)
|
||||
|
@ -450,6 +586,16 @@ struct hal_sio_operation {
|
|||
#endif /* !SIO_USE_SYNCHRONIZATION */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Relocates a bit field.
|
||||
*
|
||||
* @param[in] v value
|
||||
* @param[in] m mask of the bit field
|
||||
* @param[in] s source bit offset
|
||||
* @param[in] d destination bit offset
|
||||
*/
|
||||
#define __sio_reloc_field(v, m, s, d) ((((v) & m) >> (s)) << (d))
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
@ -463,11 +609,16 @@ extern "C" {
|
|||
void sioStop(SIODriver *siop);
|
||||
void sioStartOperation(SIODriver *siop, const SIOOperation *operation);
|
||||
void sioStopOperation(SIODriver *siop);
|
||||
sio_events_mask_t sioGetAndClearEvents(SIODriver *siop);
|
||||
void sioWriteEnableFlags(SIODriver *siop, sioflags_t flags);
|
||||
void sioSetEnableFlags(SIODriver *siop, sioflags_t flags);
|
||||
void sioClearEnableFlags(SIODriver *siop, sioflags_t flags);
|
||||
sioevents_t sioGetAndClearErrors(SIODriver *siop) ;
|
||||
sioevents_t sioGetAndClearEvents(SIODriver *siop);
|
||||
size_t sioAsyncRead(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||
size_t sioAsyncWrite(SIODriver *siop, const uint8_t *buffer, size_t n);
|
||||
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
|
||||
msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout);
|
||||
msg_t sioSynchronizeRXIdle(SIODriver *siop, sysinterval_t timeout);
|
||||
msg_t sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout);
|
||||
msg_t sioSynchronizeTXEnd(SIODriver *siop, sysinterval_t timeout);
|
||||
#endif
|
||||
|
|
|
@ -77,40 +77,27 @@ static const SIOConfig default_config = {
|
|||
|
||||
__STATIC_INLINE void uart_enable_rx_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->uart->UARTIMSC |= (UART_UARTIMSC_RXIM | UART_UARTIMSC_RTIM);
|
||||
#else
|
||||
if (siop->operation->rx_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_RXNOTEMPY) != 0U) {
|
||||
siop->uart->UARTIMSC |= UART_UARTIMSC_RXIM;
|
||||
}
|
||||
if (siop->operation->rx_idle_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_RXIDLE) != 0U) {
|
||||
siop->uart->UARTIMSC |= UART_UARTIMSC_RTIM;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void uart_enable_rx_evt_irq(SIODriver *siop) {
|
||||
__STATIC_INLINE void uart_enable_rx_errors_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->uart->UARTIMSC |= UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM;
|
||||
#else
|
||||
if (siop->operation->rx_evt_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_ALL_ERRORS) != 0U) {
|
||||
siop->uart->UARTIMSC |= UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void uart_enable_tx_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->uart->UARTIMSC |= UART_UARTIMSC_TXIM;
|
||||
#else
|
||||
if (siop->operation->tx_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_TXNOTFULL) != 0U) {
|
||||
siop->uart->UARTIMSC |= UART_UARTIMSC_TXIM;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,12 +161,10 @@ void sio_lld_init(void) {
|
|||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The operation status.
|
||||
* @retval false if the driver has been correctly started.
|
||||
* @retval true if an error occurred.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
bool sio_lld_start(SIODriver *siop) {
|
||||
msg_t sio_lld_start(SIODriver *siop) {
|
||||
|
||||
/* Using the default configuration if the application passed a
|
||||
NULL pointer.*/
|
||||
|
@ -219,10 +204,9 @@ bool sio_lld_start(SIODriver *siop) {
|
|||
/* Configures the peripheral.*/
|
||||
uart_init(siop);
|
||||
|
||||
return false;
|
||||
return HAL_RET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deactivates the SIO peripheral.
|
||||
*
|
||||
|
@ -264,38 +248,9 @@ void sio_lld_stop(SIODriver *siop) {
|
|||
* @api
|
||||
*/
|
||||
void sio_lld_start_operation(SIODriver *siop) {
|
||||
uint32_t imsc;
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
/* With synchronization all interrupts are required.*/
|
||||
imsc = UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM |
|
||||
UART_UARTIMSC_RXIM | UART_UARTIMSC_RTIM |
|
||||
UART_UARTIMSC_TXIM;
|
||||
#else
|
||||
/* When using just callbacks we can select only those really required.*/
|
||||
imsc = 0U;
|
||||
if (siop->operation->rx_cb != NULL) {
|
||||
imsc |= UART_UARTIMSC_RXIM;
|
||||
}
|
||||
if (siop->operation->rx_idle_cb != NULL) {
|
||||
imsc |= UART_UARTIMSC_RTIM;
|
||||
}
|
||||
if (siop->operation->tx_cb != NULL) {
|
||||
imsc |= UART_UARTIMSC_TXIM;
|
||||
}
|
||||
if (siop->operation->tx_end_cb != NULL) {
|
||||
osalDbgAssert(false, "unsupported callback");
|
||||
}
|
||||
if (siop->operation->rx_evt_cb != NULL) {
|
||||
imsc |= UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setting up the operation.*/
|
||||
siop->uart->UARTICR = siop->uart->UARTRIS;
|
||||
siop->uart->UARTIMSC |= imsc;
|
||||
siop->uart->UARTCR = siop->config->UARTCR |
|
||||
UART_UARTCR_RXE | UART_UARTCR_TXE | UART_UARTCR_UARTEN;
|
||||
}
|
||||
|
@ -315,41 +270,95 @@ void sio_lld_stop_operation(SIODriver *siop) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Return the pending SIO events flags.
|
||||
* @brief Enable flags change notification.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*/
|
||||
void sio_lld_update_enable_flags(SIODriver *siop) {
|
||||
uint32_t imsc;
|
||||
|
||||
osalDbgAssert((siop->enabled & SIO_FL_TXDONE) == 0U, "unsupported event");
|
||||
|
||||
if ((siop->enabled & SIO_FL_ALL_ERRORS) == 0U) {
|
||||
imsc = 0U;
|
||||
}
|
||||
else {
|
||||
imsc = UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM;
|
||||
}
|
||||
|
||||
imsc |= __sio_reloc_field(siop->enabled, SIO_FL_RXNOTEMPY, SIO_FL_RXNOTEMPY_POS, UART_UARTIMSC_RXIM_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_TXNOTFULL, SIO_FL_TXNOTFULL_POS, UART_UARTIMSC_TXIM_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_RXIDLE, SIO_FL_RXIDLE_POS, UART_UARTIMSC_RTIM_Pos);
|
||||
|
||||
/* Setting up the operation.*/
|
||||
siop->uart->UARTIMSC |= imsc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO error event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
||||
sio_events_mask_t evtmask;
|
||||
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop) {
|
||||
uint32_t ris;
|
||||
sioevents_t errors = (sioevents_t)0;
|
||||
|
||||
/* Getting and clearing all relevant ISR flags (and only those).*/
|
||||
ris = siop->uart->UARTRIS & (UART_UARTRIS_OERIS | UART_UARTRIS_BERIS |
|
||||
UART_UARTRIS_PERIS | UART_UARTRIS_FERIS);
|
||||
/* Getting and clearing all relevant RIS flags (and only those).*/
|
||||
ris = siop->uart->UARTRIS & SIO_LLD_ISR_RX_ERRORS;
|
||||
siop->uart->UARTICR = ris;
|
||||
|
||||
/* Status flags cleared, now the related interrupts can be enabled again.*/
|
||||
uart_enable_rx_evt_irq(siop);
|
||||
uart_enable_rx_errors_irq(siop);
|
||||
|
||||
/* Translating the status flags in SIO events.*/
|
||||
evtmask = 0U;
|
||||
if ((ris & UART_UARTRIS_BERIS) != 0U) {
|
||||
evtmask |= SIO_BREAK_DETECTED;
|
||||
}
|
||||
if ((ris & UART_UARTRIS_OERIS) != 0U) {
|
||||
evtmask |= SIO_OVERRUN_ERROR;
|
||||
}
|
||||
if ((ris & UART_UARTRIS_FERIS) != 0U) {
|
||||
evtmask |= SIO_FRAMING_ERROR;
|
||||
}
|
||||
if ((ris & UART_UARTRIS_PERIS) != 0U) {
|
||||
evtmask |= SIO_PARITY_ERROR;
|
||||
}
|
||||
errors |= __sio_reloc_field(ris, UART_UARTMIS_OEMIS_Msk, UART_UARTMIS_OEMIS_Pos, SIO_EV_OVERRUN_ERR_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_BEMIS_Msk, UART_UARTMIS_BEMIS_Pos, SIO_EV_BREAK_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_PEMIS_Msk, UART_UARTMIS_PEMIS_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_FEMIS_Msk, UART_UARTMIS_FEMIS_Pos, SIO_EV_FRAMING_ERR_POS);
|
||||
|
||||
return evtmask;
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
sioevents_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
||||
uint32_t ris;
|
||||
sioevents_t events = (sioevents_t)0;
|
||||
|
||||
/* Getting all RIS flags.*/
|
||||
ris = siop->uart->UARTRIS & (SIO_LLD_ISR_RX_ERRORS |
|
||||
UART_UARTMIS_RTMIS |
|
||||
UART_UARTMIS_RXMIS |
|
||||
UART_UARTMIS_TXMIS);
|
||||
|
||||
/* Clearing captured events.*/
|
||||
siop->uart->UARTICR = ris;
|
||||
|
||||
/* Status flags cleared, now the RX-related interrupts can be
|
||||
enabled again.*/
|
||||
uart_enable_rx_irq(siop);
|
||||
uart_enable_rx_errors_irq(siop);
|
||||
|
||||
/* Translating the status flags in SIO events.*/
|
||||
events |= __sio_reloc_field(ris, UART_UARTMIS_RXMIS_Msk, UART_UARTMIS_RXMIS_Pos, SIO_EV_RXNOTEMPY_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_TXMIS_Msk, UART_UARTMIS_TXMIS_Pos, SIO_EV_TXNOTFULL_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_RTMIS_Msk, UART_UARTMIS_RTMIS_Pos, SIO_EV_RXIDLE_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_OEMIS_Msk, UART_UARTMIS_OEMIS_Pos, SIO_EV_OVERRUN_ERR_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_BEMIS_Msk, UART_UARTMIS_BEMIS_Pos, SIO_EV_BREAK_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_PEMIS_Msk, UART_UARTMIS_PEMIS_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||
__sio_reloc_field(ris, UART_UARTMIS_FEMIS_Msk, UART_UARTMIS_FEMIS_Pos, SIO_EV_FRAMING_ERR_POS);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -369,7 +378,8 @@ size_t sio_lld_read(SIODriver *siop, uint8_t *buffer, size_t n) {
|
|||
rd = 0U;
|
||||
while (true) {
|
||||
|
||||
/* If the RX FIFO has been emptied then the interrupt is enabled again.*/
|
||||
/* If the RX FIFO has been emptied then the RX FIFO and IDLE interrupts
|
||||
are enabled again.*/
|
||||
if (sio_lld_is_rx_empty(siop)) {
|
||||
uart_enable_rx_irq(siop);
|
||||
break;
|
||||
|
@ -501,7 +511,7 @@ msg_t sio_lld_control(SIODriver *siop, unsigned int operation, void *arg) {
|
|||
*/
|
||||
void sio_lld_serve_interrupt(SIODriver *siop) {
|
||||
UART_TypeDef *u = siop->uart;
|
||||
uint32_t mis, imsc, evtmask;
|
||||
uint32_t mis, imsc;
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
|
@ -512,65 +522,77 @@ void sio_lld_serve_interrupt(SIODriver *siop) {
|
|||
/* Read on control registers.*/
|
||||
imsc = u->UARTIMSC;
|
||||
|
||||
/* Enabled errors/events handling.*/
|
||||
evtmask = mis & (UART_UARTMIS_OEMIS | UART_UARTMIS_BEMIS |
|
||||
UART_UARTMIS_PEMIS | UART_UARTMIS_FEMIS);
|
||||
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||
disabled instead.*/
|
||||
if (mis != 0U) {
|
||||
|
||||
if (evtmask != 0U) {
|
||||
/* Disabling event sources.*/
|
||||
u->UARTIMSC = imsc & ~(UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM);
|
||||
/* Error events handled as a group, except ORE.*/
|
||||
if ((mis & SIO_LLD_ISR_RX_ERRORS) != 0U) {
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx_evt(siop);
|
||||
#if SIO_USE_SYNCHRONIZATION
|
||||
/* The idle flag is forcibly cleared when an RX error event is
|
||||
detected.*/
|
||||
imsc &= ~UART_UARTIMSC_RTIM;
|
||||
#endif
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, SIO_MSG_ERRORS);
|
||||
/* Disabling event sources.*/
|
||||
imsc &= ~(UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_events(siop);
|
||||
}
|
||||
|
||||
/* Idle RX event.*/
|
||||
if ((mis & UART_UARTMIS_RTMIS) != 0U) {
|
||||
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
imsc &= ~UART_UARTIMSC_RTIM;
|
||||
|
||||
/* Workaround for RX FIFO threshold problem.*/
|
||||
if(!sio_lld_is_rx_empty(siop)) {
|
||||
__sio_wakeup_rx(siop);
|
||||
}
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rxidle(siop);
|
||||
}
|
||||
|
||||
/* RX FIFO is non-empty.*/
|
||||
if ((mis & UART_UARTMIS_RXMIS) != 0U) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION
|
||||
/* The idle flag is forcibly cleared when an RX data event is
|
||||
detected.*/
|
||||
imsc &= ~UART_UARTIMSC_RTIM;
|
||||
#endif
|
||||
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
imsc &= ~UART_UARTIMSC_RXIM;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop);
|
||||
}
|
||||
|
||||
/* TX FIFO is non-full.*/
|
||||
if ((mis & UART_UARTMIS_TXMIS) != 0U) {
|
||||
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
imsc &= ~UART_UARTIMSC_TXIM;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_tx(siop);
|
||||
}
|
||||
|
||||
/* Updating IMSC, some sources could have been disabled.*/
|
||||
u->UARTIMSC = imsc;
|
||||
|
||||
/* The callback is invoked.*/
|
||||
__sio_callback(siop);
|
||||
|
||||
/* Values could have been changed by the callback. */
|
||||
imsc = u->UARTIMSC;
|
||||
}
|
||||
|
||||
/* RX FIFO is non-empty.*/
|
||||
if (((mis & UART_UARTMIS_RXMIS) != 0U)) {
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
u->UARTIMSC = imsc & ~UART_UARTIMSC_RXIM;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, MSG_OK);
|
||||
|
||||
/* Values could have been changed by the callback. */
|
||||
imsc = u->UARTIMSC;
|
||||
}
|
||||
|
||||
/* RX idle condition.*/
|
||||
if ((mis & UART_UARTMIS_RTMIS) != 0U) {
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
u->UARTIMSC = imsc & ~UART_UARTIMSC_RTIM;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx_idle(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, SIO_MSG_IDLE);
|
||||
|
||||
/* Values could have been changed by the callback. */
|
||||
imsc = u->UARTIMSC;
|
||||
}
|
||||
|
||||
/* TX FIFO is non-full.*/
|
||||
if ((mis & UART_UARTMIS_TXMIS) != 0U) {
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
u->UARTIMSC = imsc & ~UART_UARTIMSC_TXIM;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_tx(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_tx(siop, MSG_OK);
|
||||
else {
|
||||
osalDbgAssert(false, "spurious interrupt");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,14 @@
|
|||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Mask of RX-related errors in the MIS/RIS registers.
|
||||
*/
|
||||
#define SIO_LLD_ISR_RX_ERRORS (UART_UARTMIS_OEMIS | \
|
||||
UART_UARTMIS_BEMIS | \
|
||||
UART_UARTMIS_PEMIS | \
|
||||
UART_UARTMIS_FEMIS)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
@ -95,11 +103,6 @@
|
|||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of a SIO events mask.
|
||||
*/
|
||||
typedef uint32_t sio_events_mask_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
@ -136,6 +139,33 @@ typedef uint32_t sio_events_mask_t;
|
|||
#define sio_lld_is_rx_empty(siop) \
|
||||
(bool)(((siop)->uart->UARTFR & UART_UARTFR_RXFE) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines the activity state of the receiver.
|
||||
*(bool)(((siop)->uart->UARTFR & UART_UARTFR_RXFE) != 0U)
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX activity state.
|
||||
* @retval false if RX is in active state.
|
||||
* @retval true if RX is in idle state.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define sio_lld_is_rx_idle(siop) true
|
||||
|
||||
/**
|
||||
* @brief Determines if RX has pending error events to be read and cleared.
|
||||
* @note Only error and protocol errors are handled, data events are not
|
||||
* considered.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX error events.
|
||||
* @retval false if RX has no pending events
|
||||
* @retval true if RX has pending events
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define sio_lld_has_rx_errors(siop) \
|
||||
(bool)(((siop)->uart->UARTMIS & SIO_LLD_ISR_RX_ERRORS) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines the state of the TX FIFO.
|
||||
*
|
||||
|
@ -178,11 +208,13 @@ extern SIODriver SIOD1;
|
|||
extern "C" {
|
||||
#endif
|
||||
void sio_lld_init(void);
|
||||
bool sio_lld_start(SIODriver *siop);
|
||||
msg_t sio_lld_start(SIODriver *siop);
|
||||
void sio_lld_stop(SIODriver *siop);
|
||||
void sio_lld_start_operation(SIODriver *siop);
|
||||
void sio_lld_stop_operation(SIODriver *siop);
|
||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop);
|
||||
void sio_lld_update_enable_flags(SIODriver *siop);
|
||||
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop);
|
||||
sioevents_t sio_lld_get_and_clear_events(SIODriver *siop);
|
||||
size_t sio_lld_read(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||
size_t sio_lld_write(SIODriver *siop, const uint8_t *buffer, size_t n);
|
||||
msg_t sio_lld_get(SIODriver *siop);
|
||||
|
|
|
@ -133,51 +133,39 @@ static const SIOConfig default_config = {
|
|||
/*===========================================================================*/
|
||||
|
||||
__STATIC_INLINE void usart_enable_rx_irq(SIODriver *siop) {
|
||||
uint32_t cr1;
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR1 |= USART_CR1_RXNEIE;
|
||||
#else
|
||||
if (siop->operation->rx_cb != NULL) {
|
||||
siop->usart->CR1 |= USART_CR1_RXNEIE;
|
||||
cr1 = siop->usart->CR1;
|
||||
if ((siop->enabled & SIO_FL_RXNOTEMPY) != 0U) {
|
||||
cr1 |= USART_CR1_RXNEIE;
|
||||
}
|
||||
#endif
|
||||
if ((siop->enabled & SIO_FL_RXIDLE) != 0U) {
|
||||
cr1 |= USART_CR1_IDLEIE;
|
||||
}
|
||||
siop->usart->CR1 = cr1;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void usart_enable_rx_evt_irq(SIODriver *siop) {
|
||||
__STATIC_INLINE void usart_enable_rx_errors_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR1 |= USART_CR1_PEIE;
|
||||
siop->usart->CR2 |= USART_CR2_LBDIE;
|
||||
siop->usart->CR3 |= USART_CR3_EIE;
|
||||
#else
|
||||
if (siop->operation->rx_evt_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_ALL_ERRORS) != 0U) {
|
||||
siop->usart->CR1 |= USART_CR1_PEIE;
|
||||
siop->usart->CR2 |= USART_CR2_LBDIE;
|
||||
siop->usart->CR3 |= USART_CR3_EIE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void usart_enable_tx_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR1 |= USART_CR1_TXEIE;
|
||||
#else
|
||||
if (siop->operation->tx_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_TXNOTFULL) != 0U) {
|
||||
siop->usart->CR1 |= USART_CR1_TXEIE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void usart_enable_tx_end_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
||||
#else
|
||||
if (siop->operation->tx_end_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_TXDONE) != 0U) {
|
||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -246,48 +234,48 @@ void sio_lld_init(void) {
|
|||
/* Driver instances initialization.*/
|
||||
#if STM32_SIO_USE_USART1 == TRUE
|
||||
sioObjectInit(&SIOD1);
|
||||
SIOD1.usart = USART1;
|
||||
SIOD1.clock = STM32_USART1CLK;
|
||||
SIOD1.usart = USART1;
|
||||
SIOD1.clock = STM32_USART1CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_USART2 == TRUE
|
||||
sioObjectInit(&SIOD2);
|
||||
SIOD2.usart = USART2;
|
||||
SIOD2.clock = STM32_USART2CLK;
|
||||
SIOD2.usart = USART2;
|
||||
SIOD2.clock = STM32_USART2CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_USART3 == TRUE
|
||||
sioObjectInit(&SIOD3);
|
||||
SIOD3.usart = USART3;
|
||||
SIOD3.clock = STM32_USART3CLK;
|
||||
SIOD3.usart = USART3;
|
||||
SIOD3.clock = STM32_USART3CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART4 == TRUE
|
||||
sioObjectInit(&SIOD4);
|
||||
SIOD4.usart = UART4;
|
||||
SIOD4.clock = STM32_UART4CLK;
|
||||
SIOD4.usart = UART4;
|
||||
SIOD4.clock = STM32_UART4CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART5 == TRUE
|
||||
sioObjectInit(&SIOD5);
|
||||
SIOD5.usart = UART5;
|
||||
SIOD5.clock = STM32_UART5CLK;
|
||||
SIOD5.usart = UART5;
|
||||
SIOD5.clock = STM32_UART5CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_USART6 == TRUE
|
||||
sioObjectInit(&SIOD6);
|
||||
SIOD6.usart = USART6;
|
||||
SIOD6.clock = STM32_USART6CLK;
|
||||
SIOD6.usart = USART6;
|
||||
SIOD6.clock = STM32_USART6CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART7 == TRUE
|
||||
sioObjectInit(&SIOD7);
|
||||
SIOD7.usart = UART7;
|
||||
SIOD7.clock = STM32_UART7CLK;
|
||||
SIOD7.usart = UART7;
|
||||
SIOD7.clock = STM32_UART7CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART8 == TRUE
|
||||
sioObjectInit(&SIOD8);
|
||||
SIOD8.usart = UART8;
|
||||
SIOD8.clock = STM32_UART8CLK;
|
||||
SIOD8.usart = UART8;
|
||||
SIOD8.clock = STM32_UART8CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_LPUART1 == TRUE
|
||||
sioObjectInit(&LPSIOD1);
|
||||
LPSIOD1.usart = LPUART1;
|
||||
LPSIOD1.clock = STM32_LPUART1CLK;
|
||||
LPSIOD1.usart = LPUART1;
|
||||
LPSIOD1.clock = STM32_LPUART1CLK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -367,7 +355,7 @@ msg_t sio_lld_start(SIODriver *siop) {
|
|||
}
|
||||
#endif
|
||||
else {
|
||||
osalDbgAssert(false, "invalid USART instance");
|
||||
osalDbgAssert(false, "invalid SIO instance");
|
||||
}
|
||||
|
||||
/* Driver object low level initializations.*/
|
||||
|
@ -454,7 +442,7 @@ void sio_lld_stop(SIODriver *siop) {
|
|||
}
|
||||
#endif
|
||||
else {
|
||||
osalDbgAssert(false, "invalid USART instance");
|
||||
osalDbgAssert(false, "invalid SIO instance");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -467,43 +455,10 @@ void sio_lld_stop(SIODriver *siop) {
|
|||
* @api
|
||||
*/
|
||||
void sio_lld_start_operation(SIODriver *siop) {
|
||||
uint32_t cr1irq, cr2irq, cr3irq;
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
/* With synchronization all interrupts are required.*/
|
||||
cr1irq = USART_CR1_RXNEIE | USART_CR1_TXEIE | USART_CR1_PEIE |
|
||||
USART_CR1_TCIE | USART_CR1_IDLEIE;
|
||||
cr2irq = USART_CR2_LBDIE;
|
||||
cr3irq = USART_CR3_EIE;
|
||||
#else
|
||||
/* When using just callbacks we can select only those really required.*/
|
||||
cr1irq = 0U;
|
||||
cr2irq = 0U;
|
||||
cr3irq = 0U;
|
||||
if (siop->operation->rx_cb != NULL) {
|
||||
cr1irq |= USART_CR1_RXNEIE;
|
||||
}
|
||||
if (siop->operation->rx_idle_cb != NULL) {
|
||||
cr1irq |= USART_CR1_IDLEIE;
|
||||
}
|
||||
if (siop->operation->tx_cb != NULL) {
|
||||
cr1irq |= USART_CR1_TXEIE;
|
||||
}
|
||||
if (siop->operation->tx_end_cb != NULL) {
|
||||
cr1irq |= USART_CR1_TCIE;
|
||||
}
|
||||
if (siop->operation->rx_evt_cb != NULL) {
|
||||
cr1irq |= USART_CR1_PEIE;
|
||||
cr2irq |= USART_CR2_LBDIE;
|
||||
cr3irq |= USART_CR3_EIE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setting up the operation.*/
|
||||
siop->usart->ICR = siop->usart->ISR;
|
||||
siop->usart->CR2 |= cr2irq;
|
||||
siop->usart->CR3 |= cr3irq;
|
||||
siop->usart->CR1 |= cr1irq | USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||
siop->usart->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -516,50 +471,116 @@ void sio_lld_start_operation(SIODriver *siop) {
|
|||
void sio_lld_stop_operation(SIODriver *siop) {
|
||||
|
||||
/* Stop operation.*/
|
||||
siop->usart->CR1 &= USART_CR1_CFG_FORBIDDEN;
|
||||
siop->usart->CR2 &= USART_CR2_CFG_FORBIDDEN;
|
||||
siop->usart->CR3 &= USART_CR3_CFG_FORBIDDEN;
|
||||
siop->usart->CR1 &= ~USART_CR1_CFG_FORBIDDEN;
|
||||
siop->usart->CR2 &= ~USART_CR2_CFG_FORBIDDEN;
|
||||
siop->usart->CR3 &= ~USART_CR3_CFG_FORBIDDEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the pending SIO events flags.
|
||||
* @brief Enable flags change notification.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*/
|
||||
void sio_lld_update_enable_flags(SIODriver *siop) {
|
||||
uint32_t cr1irq, cr2irq, cr3irq;
|
||||
|
||||
cr1irq = siop->usart->CR1 & ~(USART_CR1_TXEIE | USART_CR1_RXNEIE |
|
||||
USART_CR1_IDLEIE | USART_CR1_TCIE |
|
||||
USART_CR1_PEIE);
|
||||
cr2irq = siop->usart->CR2 & ~(USART_CR2_LBDIE);
|
||||
cr3irq = siop->usart->CR3 & ~(USART_CR3_EIE);
|
||||
|
||||
cr1irq |= __sio_reloc_field(siop->enabled, SIO_FL_RXNOTEMPY, SIO_FL_RXNOTEMPY_POS, USART_CR1_RXNEIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_TXNOTFULL, SIO_FL_TXNOTFULL_POS, USART_CR1_TXEIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_RXIDLE, SIO_FL_RXIDLE_POS, USART_CR1_IDLEIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_TXDONE, SIO_FL_TXDONE_POS, USART_CR1_TCIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_ALL_ERRORS, SIO_FL_ALL_ERRORS_POS, USART_CR1_PEIE_Pos);
|
||||
cr2irq |= __sio_reloc_field(siop->enabled, SIO_FL_ALL_ERRORS, SIO_FL_ALL_ERRORS_POS, USART_CR2_LBDIE_Pos);
|
||||
cr3irq |= __sio_reloc_field(siop->enabled, SIO_FL_ALL_ERRORS, SIO_FL_ALL_ERRORS_POS, USART_CR3_EIE_Pos);
|
||||
|
||||
/* Setting up the operation.*/
|
||||
siop->usart->CR1 = cr1irq;
|
||||
siop->usart->CR2 = cr2irq;
|
||||
siop->usart->CR3 = cr3irq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO error event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
||||
sio_events_mask_t evtmask;
|
||||
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop) {
|
||||
uint32_t isr;
|
||||
sioevents_t errors = (sioevents_t)0;
|
||||
|
||||
/* Getting and clearing all relevant ISR flags (and only those).*/
|
||||
isr = siop->usart->ISR & (USART_ISR_PE | USART_ISR_LBDF | USART_ISR_FE |
|
||||
USART_ISR_ORE | USART_ISR_NE);
|
||||
/* Getting all error ISR flags (and only those).
|
||||
NOTE: Do not trust the position of other bits in ISR/ICR because
|
||||
some scientist decided to use different positions for some
|
||||
of them.*/
|
||||
isr = siop->usart->ISR & SIO_LLD_ISR_RX_ERRORS;
|
||||
|
||||
/* Clearing captured events.*/
|
||||
siop->usart->ICR = isr;
|
||||
|
||||
/* Status flags cleared, now the related interrupts can be enabled again.*/
|
||||
usart_enable_rx_evt_irq(siop);
|
||||
/* Status flags cleared, now the RX errors-related interrupts can be
|
||||
enabled again.*/
|
||||
usart_enable_rx_errors_irq(siop);
|
||||
|
||||
/* Translating the status flags in SIO events.*/
|
||||
evtmask = 0U;
|
||||
if ((isr & USART_ISR_LBDF) != 0U) {
|
||||
evtmask |= SIO_BREAK_DETECTED;
|
||||
}
|
||||
if ((isr & USART_ISR_ORE) != 0U) {
|
||||
evtmask |= SIO_OVERRUN_ERROR;
|
||||
}
|
||||
if ((isr & USART_ISR_NE) != 0U) {
|
||||
evtmask |= SIO_NOISE_ERROR;
|
||||
}
|
||||
if ((isr & USART_ISR_FE) != 0U) {
|
||||
evtmask |= SIO_FRAMING_ERROR;
|
||||
}
|
||||
if ((isr & USART_ISR_PE) != 0U) {
|
||||
evtmask |= SIO_PARITY_ERROR;
|
||||
}
|
||||
errors |= __sio_reloc_field(isr, USART_ISR_LBDF_Msk, USART_ISR_LBDF_Pos, SIO_EV_BREAK_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_PE_Msk, USART_ISR_PE_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_FE_Msk, USART_ISR_FE_Pos, SIO_EV_FRAMING_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_NE_Msk, USART_ISR_NE_Pos, SIO_EV_NOISE_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_ORE_Msk, USART_ISR_ORE_Pos, SIO_EV_OVERRUN_ERR_POS);
|
||||
|
||||
return evtmask;
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
sioevents_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
||||
uint32_t isr;
|
||||
sioevents_t events = (sioevents_t)0;
|
||||
|
||||
/* Getting all ISR flags.
|
||||
NOTE: Do not trust the position of other bits in ISR/ICR because
|
||||
some scientist decided to use different positions for some
|
||||
of them.*/
|
||||
isr = siop->usart->ISR & (SIO_LLD_ISR_RX_ERRORS |
|
||||
USART_ISR_RXNE |
|
||||
USART_ISR_IDLE |
|
||||
USART_ISR_TXE |
|
||||
USART_ISR_TC);
|
||||
|
||||
/* Clearing captured events.*/
|
||||
siop->usart->ICR = isr;
|
||||
|
||||
/* Status flags cleared, now the RX-related interrupts can be
|
||||
enabled again.*/
|
||||
usart_enable_rx_irq(siop);
|
||||
usart_enable_rx_errors_irq(siop);
|
||||
|
||||
/* Translating the status flags in SIO events.*/
|
||||
events |= __sio_reloc_field(isr, USART_ISR_RXNE_Msk, USART_ISR_RXNE_Pos, SIO_EV_RXNOTEMPY_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_TXE_Msk, USART_ISR_TXE_Pos, SIO_EV_TXNOTFULL_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_IDLE_Msk, USART_ISR_IDLE_Pos, SIO_EV_RXIDLE_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_TC_Msk, USART_ISR_TC_Pos, SIO_EV_TXDONE_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_LBDF_Msk, USART_ISR_LBDF_Pos, SIO_EV_BREAK_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_PE_Msk, USART_ISR_PE_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_FE_Msk, USART_ISR_FE_Pos, SIO_EV_FRAMING_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_NE_Msk, USART_ISR_NE_Pos, SIO_EV_NOISE_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_ORE_Msk, USART_ISR_ORE_Pos, SIO_EV_OVERRUN_ERR_POS);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -579,7 +600,8 @@ size_t sio_lld_read(SIODriver *siop, uint8_t *buffer, size_t n) {
|
|||
rd = 0U;
|
||||
while (true) {
|
||||
|
||||
/* If the RX FIFO has been emptied then the interrupt is enabled again.*/
|
||||
/* If the RX FIFO has been emptied then the RX FIFO and IDLE interrupts
|
||||
are enabled again.*/
|
||||
if (sio_lld_is_rx_empty(siop)) {
|
||||
usart_enable_rx_irq(siop);
|
||||
break;
|
||||
|
@ -711,108 +733,109 @@ msg_t sio_lld_control(SIODriver *siop, unsigned int operation, void *arg) {
|
|||
*/
|
||||
void sio_lld_serve_interrupt(SIODriver *siop) {
|
||||
USART_TypeDef *u = siop->usart;
|
||||
uint32_t isr, cr1, cr2, cr3, evtmask, irqmask;
|
||||
uint32_t isr, isrmask;
|
||||
uint32_t cr1, cr2, cr3;
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||
disabled instead.*/
|
||||
isr = u->ISR;
|
||||
|
||||
/* Read on control registers.*/
|
||||
cr1 = u->CR1;
|
||||
cr2 = u->CR2;
|
||||
cr3 = u->CR3;
|
||||
|
||||
/* Enabled errors/events handling.*/
|
||||
irqmask = ((cr1 & USART_CR1_PEIE) != 0U ? USART_ISR_PE : 0U) |
|
||||
((cr1 & USART_CR1_RXNEIE) != 0U ? USART_ISR_ORE : 0U) |
|
||||
((cr2 & USART_CR2_LBDIE) != 0U ? USART_ISR_LBDF : 0U) |
|
||||
((cr3 & USART_CR3_EIE) != 0U ? USART_ISR_FE |
|
||||
USART_ISR_ORE |
|
||||
USART_ISR_NE : 0U);
|
||||
evtmask = isr & irqmask;
|
||||
if (evtmask != 0U) {
|
||||
/* Calculating the mask of the interrupts to be processed, BTW, thanks ST
|
||||
for placing interrupt enable bits randomly in 3 distinct registers
|
||||
instead of a dedicated IER (ISR, ICR, see the pattern?).*/
|
||||
isrmask = __sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_NE_Pos) |
|
||||
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_FE_Pos) |
|
||||
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_ORE_Pos) |
|
||||
__sio_reloc_field(cr2, USART_CR2_LBDIE_Msk, USART_CR2_LBDIE_Pos, USART_ISR_LBDF_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_PEIE_Msk, USART_CR1_PEIE_Pos, USART_ISR_PE_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_IDLEIE_Msk, USART_CR1_IDLEIE_Pos, USART_ISR_IDLE_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_RXNEIE_Msk, USART_CR1_RXNEIE_Pos, USART_ISR_RXNE_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_TXEIE_Msk, USART_CR1_TXEIE_Pos, USART_ISR_TXE_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_TCIE_Msk, USART_CR1_TCIE_Pos, USART_ISR_TC_Pos);
|
||||
|
||||
/* Disabling event sources until errors are recognized by the
|
||||
application.*/
|
||||
u->CR1 = cr1 & ~USART_CR1_PEIE;
|
||||
u->CR2 = cr2 & ~USART_CR2_LBDIE;
|
||||
u->CR3 = cr3 & ~USART_CR3_EIE;
|
||||
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||
disabled instead.*/
|
||||
isr = u->ISR & isrmask;
|
||||
if (isr != 0U) {
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx_evt(siop);
|
||||
/* Error events handled as a group, except ORE.*/
|
||||
if ((isr & (USART_ISR_LBDF | USART_ISR_NE | USART_ISR_FE |
|
||||
USART_ISR_PE | USART_ISR_ORE)) != 0U) {
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, SIO_MSG_ERRORS);
|
||||
#if SIO_USE_SYNCHRONIZATION
|
||||
/* The idle flag is forcibly cleared when an RX error event is
|
||||
detected.*/
|
||||
u->ICR = USART_ISR_IDLE;
|
||||
#endif
|
||||
|
||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
/* Interrupt sources disabled.*/
|
||||
cr3 &= ~USART_CR3_EIE;
|
||||
cr2 &= ~USART_CR2_LBDIE;
|
||||
cr1 &= ~USART_CR1_PEIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_events(siop);
|
||||
}
|
||||
|
||||
/* Idle RX event.*/
|
||||
if ((isr & USART_ISR_IDLE) != 0U) {
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr1 &= ~USART_CR1_IDLEIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rxidle(siop);
|
||||
}
|
||||
|
||||
/* RX FIFO is non-empty.*/
|
||||
if ((isr & USART_ISR_RXNE) != 0U) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION
|
||||
/* The idle flag is forcibly cleared when an RX data event is
|
||||
detected.*/
|
||||
u->ICR = USART_ISR_IDLE;
|
||||
#endif
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr1 &= ~USART_CR1_RXNEIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop);
|
||||
}
|
||||
|
||||
/* TX FIFO is non-full.*/
|
||||
if ((isr & USART_ISR_TXE) != 0U) {
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr1 &= ~USART_CR1_TXEIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_tx(siop);
|
||||
}
|
||||
|
||||
/* Physical transmission end.*/
|
||||
if ((isr & USART_ISR_TC) != 0U) {
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr1 &= ~USART_CR1_TCIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_txend(siop);
|
||||
}
|
||||
|
||||
/* Updating control registers, some sources could have been disabled.*/
|
||||
u->CR1 = cr1;
|
||||
u->CR2 = cr2;
|
||||
u->CR3 = cr3;
|
||||
|
||||
/* The callback is invoked.*/
|
||||
__sio_callback(siop);
|
||||
}
|
||||
|
||||
/* RX FIFO is non-empty.*/
|
||||
if (((cr1 & USART_CR1_RXNEIE) != 0U) &&
|
||||
(isr & USART_ISR_RXNE) != 0U) {
|
||||
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
u->CR1 = cr1 & ~USART_CR1_RXNEIE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, MSG_OK);
|
||||
|
||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
}
|
||||
|
||||
/* TX FIFO is non-full.*/
|
||||
if (((cr1 & USART_CR1_TXEIE) != 0U) &&
|
||||
(isr & USART_ISR_TXE) != 0U) {
|
||||
|
||||
/* Called once then the interrupt is disabled.*/
|
||||
u->CR1 = cr1 & ~USART_CR1_TXEIE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_tx(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_tx(siop, MSG_OK);
|
||||
|
||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
}
|
||||
|
||||
/* RX idle condition.*/
|
||||
if (((cr1 & USART_CR1_IDLEIE) != 0U) &&
|
||||
(isr & USART_ISR_IDLE) != 0U) {
|
||||
|
||||
/* The idle flag requires clearing, it stays enabled.*/
|
||||
u->ICR = USART_ISR_IDLE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx_idle(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, SIO_MSG_IDLE);
|
||||
|
||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
}
|
||||
|
||||
/* Physical transmission end.*/
|
||||
if (((cr1 & USART_CR1_TCIE) != 0U) &&
|
||||
(isr & USART_ISR_TC) != 0U) {
|
||||
|
||||
/* Called once then the interrupt is disabled.*/
|
||||
u->CR1 = cr1 & ~USART_CR1_TCIE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_tx_end(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_txend(siop, MSG_OK);
|
||||
else {
|
||||
osalDbgAssert(false, "spurious interrupt");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,13 @@
|
|||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Mask of RX-related errors in the ISR register.
|
||||
*/
|
||||
#define SIO_LLD_ISR_RX_ERRORS (USART_ISR_NE | USART_ISR_FE | \
|
||||
USART_ISR_PE | USART_ISR_ORE | \
|
||||
USART_ISR_LBDF)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
@ -252,11 +259,6 @@
|
|||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of a SIO events mask.
|
||||
*/
|
||||
typedef uint32_t sio_events_mask_t;
|
||||
|
||||
/**
|
||||
* @brief Low level fields of the SIO driver structure.
|
||||
*/
|
||||
|
@ -294,6 +296,34 @@ typedef uint32_t sio_events_mask_t;
|
|||
#define sio_lld_is_rx_empty(siop) \
|
||||
(bool)(((siop)->usart->ISR & USART_ISR_RXNE) == 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines the activity state of the receiver.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX activity state.
|
||||
* @retval false if RX is in active state.
|
||||
* @retval true if RX is in idle state.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define sio_lld_is_rx_idle(siop) \
|
||||
(bool)(((siop)->usart->ISR & USART_ISR_IDLE) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines if RX has pending error events to be read and cleared.
|
||||
* @note Only error and protocol errors are handled, data events are not
|
||||
* considered.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX error events.
|
||||
* @retval false if RX has no pending events
|
||||
* @retval true if RX has pending events
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define sio_lld_has_rx_errors(siop) \
|
||||
(bool)(((siop)->usart->ISR & SIO_LLD_ISR_RX_ERRORS) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines the state of the TX FIFO.
|
||||
*
|
||||
|
@ -368,7 +398,9 @@ extern "C" {
|
|||
void sio_lld_stop(SIODriver *siop);
|
||||
void sio_lld_start_operation(SIODriver *siop);
|
||||
void sio_lld_stop_operation(SIODriver *siop);
|
||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop);
|
||||
void sio_lld_update_enable_flags(SIODriver *siop);
|
||||
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop);
|
||||
sioevents_t sio_lld_get_and_clear_events(SIODriver *siop);
|
||||
size_t sio_lld_read(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||
size_t sio_lld_write(SIODriver *siop, const uint8_t *buffer, size_t n);
|
||||
msg_t sio_lld_get(SIODriver *siop);
|
||||
|
|
|
@ -147,7 +147,7 @@ static const SIOConfig default_config = {
|
|||
.presc = USART_PRESC1,
|
||||
.cr1 = USART_CR1_DATA8 | USART_CR1_OVER16,
|
||||
.cr2 = USART_CR2_STOP1_BITS,
|
||||
.cr3 = USART_CR3_TXFTCFG_1H | USART_CR3_RXFTCFG_1H
|
||||
.cr3 = USART_CR3_TXFTCFG_1H | USART_CR3_RXFTCFG_NONEMPTY
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -156,50 +156,35 @@ static const SIOConfig default_config = {
|
|||
|
||||
__STATIC_INLINE void usart_enable_rx_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR3 |= USART_CR3_RXFTIE;
|
||||
#else
|
||||
if (siop->operation->rx_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_RXNOTEMPY) != 0U) {
|
||||
siop->usart->CR3 |= USART_CR3_RXFTIE;
|
||||
}
|
||||
#endif
|
||||
if ((siop->enabled & SIO_FL_RXIDLE) != 0U) {
|
||||
siop->usart->CR1 |= USART_CR1_IDLEIE;
|
||||
}
|
||||
}
|
||||
|
||||
__STATIC_INLINE void usart_enable_rx_evt_irq(SIODriver *siop) {
|
||||
__STATIC_INLINE void usart_enable_rx_errors_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR1 |= USART_CR1_PEIE;
|
||||
siop->usart->CR2 |= USART_CR2_LBDIE;
|
||||
siop->usart->CR3 |= USART_CR3_EIE;
|
||||
#else
|
||||
if (siop->operation->rx_evt_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_ALL_ERRORS) != 0U) {
|
||||
siop->usart->CR1 |= USART_CR1_PEIE;
|
||||
siop->usart->CR2 |= USART_CR2_LBDIE;
|
||||
siop->usart->CR3 |= USART_CR3_EIE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void usart_enable_tx_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR3 |= USART_CR3_TXFTIE;
|
||||
#else
|
||||
if (siop->operation->tx_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_TXNOTFULL) != 0U) {
|
||||
siop->usart->CR3 |= USART_CR3_TXFTIE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void usart_enable_tx_end_irq(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
||||
#else
|
||||
if (siop->operation->tx_end_cb != NULL) {
|
||||
if ((siop->enabled & SIO_FL_TXDONE) != 0U) {
|
||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,58 +254,58 @@ void sio_lld_init(void) {
|
|||
/* Driver instances initialization.*/
|
||||
#if STM32_SIO_USE_USART1 == TRUE
|
||||
sioObjectInit(&SIOD1);
|
||||
SIOD1.usart = USART1;
|
||||
SIOD1.clock = STM32_USART1CLK;
|
||||
SIOD1.usart = USART1;
|
||||
SIOD1.clock = STM32_USART1CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_USART2 == TRUE
|
||||
sioObjectInit(&SIOD2);
|
||||
SIOD2.usart = USART2;
|
||||
SIOD2.clock = STM32_USART2CLK;
|
||||
SIOD2.usart = USART2;
|
||||
SIOD2.clock = STM32_USART2CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_USART3 == TRUE
|
||||
sioObjectInit(&SIOD3);
|
||||
SIOD3.usart = USART3;
|
||||
SIOD3.clock = STM32_USART3CLK;
|
||||
SIOD3.usart = USART3;
|
||||
SIOD3.clock = STM32_USART3CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART4 == TRUE
|
||||
sioObjectInit(&SIOD4);
|
||||
SIOD4.usart = UART4;
|
||||
SIOD4.clock = STM32_UART4CLK;
|
||||
SIOD4.usart = UART4;
|
||||
SIOD4.clock = STM32_UART4CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART5 == TRUE
|
||||
sioObjectInit(&SIOD5);
|
||||
SIOD5.usart = UART5;
|
||||
SIOD5.clock = STM32_UART5CLK;
|
||||
SIOD5.usart = UART5;
|
||||
SIOD5.clock = STM32_UART5CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_USART6 == TRUE
|
||||
sioObjectInit(&SIOD6);
|
||||
SIOD6.usart = USART6;
|
||||
SIOD6.clock = STM32_USART6CLK;
|
||||
SIOD6.usart = USART6;
|
||||
SIOD6.clock = STM32_USART6CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART7 == TRUE
|
||||
sioObjectInit(&SIOD7);
|
||||
SIOD7.usart = UART7;
|
||||
SIOD7.clock = STM32_UART7CLK;
|
||||
SIOD7.usart = UART7;
|
||||
SIOD7.clock = STM32_UART7CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART8 == TRUE
|
||||
sioObjectInit(&SIOD8);
|
||||
SIOD8.usart = UART8;
|
||||
SIOD8.clock = STM32_UART8CLK;
|
||||
SIOD8.usart = UART8;
|
||||
SIOD8.clock = STM32_UART8CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_UART9 == TRUE
|
||||
sioObjectInit(&SIOD9);
|
||||
SIOD9.usart = UART9;
|
||||
SIOD9.clock = STM32_UART9CLK;
|
||||
SIOD9.usart = UART9;
|
||||
SIOD9.clock = STM32_UART9CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_USART10 == TRUE
|
||||
sioObjectInit(&SIOD10);
|
||||
SIOD10.usart = USART10;
|
||||
SIOD10.clock = STM32_USART10CLK;
|
||||
SIOD10.usart = USART10;
|
||||
SIOD10.clock = STM32_USART10CLK;
|
||||
#endif
|
||||
#if STM32_SIO_USE_LPUART1 == TRUE
|
||||
sioObjectInit(&LPSIOD1);
|
||||
LPSIOD1.usart = LPUART1;
|
||||
LPSIOD1.clock = STM32_LPUART1CLK;
|
||||
LPSIOD1.usart = LPUART1;
|
||||
LPSIOD1.clock = STM32_LPUART1CLK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -412,7 +397,7 @@ msg_t sio_lld_start(SIODriver *siop) {
|
|||
}
|
||||
#endif
|
||||
else {
|
||||
osalDbgAssert(false, "invalid USART instance");
|
||||
osalDbgAssert(false, "invalid SIO instance");
|
||||
}
|
||||
|
||||
/* Driver object low level initializations.*/
|
||||
|
@ -511,7 +496,7 @@ void sio_lld_stop(SIODriver *siop) {
|
|||
}
|
||||
#endif
|
||||
else {
|
||||
osalDbgAssert(false, "invalid USART instance");
|
||||
osalDbgAssert(false, "invalid SIO instance");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -524,42 +509,10 @@ void sio_lld_stop(SIODriver *siop) {
|
|||
* @api
|
||||
*/
|
||||
void sio_lld_start_operation(SIODriver *siop) {
|
||||
uint32_t cr1irq, cr2irq, cr3irq;
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
/* With synchronization all interrupts are required.*/
|
||||
cr1irq = USART_CR1_PEIE | USART_CR1_TCIE | USART_CR1_IDLEIE;
|
||||
cr2irq = USART_CR2_LBDIE;
|
||||
cr3irq = USART_CR3_RXFTIE | USART_CR3_TXFTIE | USART_CR3_EIE;
|
||||
#else
|
||||
/* When using just callbacks we can select only those really required.*/
|
||||
cr1irq = 0U;
|
||||
cr2irq = 0U;
|
||||
cr3irq = 0U;
|
||||
if (siop->operation->rx_cb != NULL) {
|
||||
cr3irq |= USART_CR3_RXFTIE;
|
||||
}
|
||||
if (siop->operation->rx_idle_cb != NULL) {
|
||||
cr1irq |= USART_CR1_IDLEIE;
|
||||
}
|
||||
if (siop->operation->tx_cb != NULL) {
|
||||
cr3irq |= USART_CR3_TXFTIE;
|
||||
}
|
||||
if (siop->operation->tx_end_cb != NULL) {
|
||||
cr1irq |= USART_CR1_TCIE;
|
||||
}
|
||||
if (siop->operation->rx_evt_cb != NULL) {
|
||||
cr1irq |= USART_CR1_PEIE;
|
||||
cr2irq |= USART_CR2_LBDIE;
|
||||
cr3irq |= USART_CR3_EIE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setting up the operation.*/
|
||||
siop->usart->ICR = siop->usart->ISR;
|
||||
siop->usart->CR2 |= cr2irq;
|
||||
siop->usart->CR3 |= cr3irq;
|
||||
siop->usart->CR1 |= cr1irq | USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||
siop->usart->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -572,50 +525,114 @@ void sio_lld_start_operation(SIODriver *siop) {
|
|||
void sio_lld_stop_operation(SIODriver *siop) {
|
||||
|
||||
/* Stop operation.*/
|
||||
siop->usart->CR1 &= USART_CR1_CFG_FORBIDDEN;
|
||||
siop->usart->CR2 &= USART_CR2_CFG_FORBIDDEN;
|
||||
siop->usart->CR3 &= USART_CR3_CFG_FORBIDDEN;
|
||||
siop->usart->CR1 &= ~USART_CR1_CFG_FORBIDDEN;
|
||||
siop->usart->CR2 &= ~USART_CR2_CFG_FORBIDDEN;
|
||||
siop->usart->CR3 &= ~USART_CR3_CFG_FORBIDDEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the pending SIO events flags.
|
||||
* @brief Enable flags change notification.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
*/
|
||||
void sio_lld_update_enable_flags(SIODriver *siop) {
|
||||
uint32_t cr1irq, cr2irq, cr3irq;
|
||||
|
||||
cr1irq = siop->usart->CR1 & ~(USART_CR1_IDLEIE | USART_CR1_TCIE | USART_CR1_PEIE);
|
||||
cr2irq = siop->usart->CR2 & ~(USART_CR2_LBDIE);
|
||||
cr3irq = siop->usart->CR3 & ~(USART_CR3_RXFTIE | USART_CR3_TXFTIE | USART_CR3_EIE);
|
||||
|
||||
cr1irq |= __sio_reloc_field(siop->enabled, SIO_FL_RXIDLE, SIO_FL_RXIDLE_POS, USART_CR1_IDLEIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_TXDONE, SIO_FL_TXDONE_POS, USART_CR1_TCIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_ALL_ERRORS, SIO_FL_ALL_ERRORS_POS, USART_CR1_PEIE_Pos);
|
||||
cr2irq |= __sio_reloc_field(siop->enabled, SIO_FL_ALL_ERRORS, SIO_FL_ALL_ERRORS_POS, USART_CR2_LBDIE_Pos);
|
||||
cr3irq |= __sio_reloc_field(siop->enabled, SIO_FL_RXNOTEMPY, SIO_FL_RXNOTEMPY_POS, USART_CR3_RXFTIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_TXNOTFULL, SIO_FL_TXNOTFULL_POS, USART_CR3_TXFTIE_Pos) |
|
||||
__sio_reloc_field(siop->enabled, SIO_FL_ALL_ERRORS, SIO_FL_ALL_ERRORS_POS, USART_CR3_EIE_Pos);
|
||||
|
||||
/* Setting up the operation.*/
|
||||
siop->usart->CR1 = cr1irq;
|
||||
siop->usart->CR2 = cr2irq;
|
||||
siop->usart->CR3 = cr3irq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO error event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
||||
sio_events_mask_t evtmask;
|
||||
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop) {
|
||||
uint32_t isr;
|
||||
sioevents_t errors = (sioevents_t)0;
|
||||
|
||||
/* Getting and clearing all relevant ISR flags (and only those).*/
|
||||
isr = siop->usart->ISR & (USART_ISR_PE | USART_ISR_LBDF | USART_ISR_FE |
|
||||
USART_ISR_ORE | USART_ISR_NE);
|
||||
/* Getting all error ISR flags (and only those).
|
||||
NOTE: Do not trust the position of other bits in ISR/ICR because
|
||||
some scientist decided to use different positions for some
|
||||
of them.*/
|
||||
isr = siop->usart->ISR & SIO_LLD_ISR_RX_ERRORS;
|
||||
|
||||
/* Clearing captured events.*/
|
||||
siop->usart->ICR = isr;
|
||||
|
||||
/* Status flags cleared, now the related interrupts can be enabled again.*/
|
||||
usart_enable_rx_evt_irq(siop);
|
||||
/* Status flags cleared, now the RX errors-related interrupts can be
|
||||
enabled again.*/
|
||||
usart_enable_rx_errors_irq(siop);
|
||||
|
||||
/* Translating the status flags in SIO events.*/
|
||||
evtmask = 0U;
|
||||
if ((isr & USART_ISR_LBDF) != 0U) {
|
||||
evtmask |= SIO_BREAK_DETECTED;
|
||||
}
|
||||
if ((isr & USART_ISR_ORE) != 0U) {
|
||||
evtmask |= SIO_OVERRUN_ERROR;
|
||||
}
|
||||
if ((isr & USART_ISR_NE) != 0U) {
|
||||
evtmask |= SIO_NOISE_ERROR;
|
||||
}
|
||||
if ((isr & USART_ISR_FE) != 0U) {
|
||||
evtmask |= SIO_FRAMING_ERROR;
|
||||
}
|
||||
if ((isr & USART_ISR_PE) != 0U) {
|
||||
evtmask |= SIO_PARITY_ERROR;
|
||||
}
|
||||
errors |= __sio_reloc_field(isr, USART_ISR_LBDF_Msk, USART_ISR_LBDF_Pos, SIO_EV_BREAK_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_PE_Msk, USART_ISR_PE_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_FE_Msk, USART_ISR_FE_Pos, SIO_EV_FRAMING_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_NE_Msk, USART_ISR_NE_Pos, SIO_EV_NOISE_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_ORE_Msk, USART_ISR_ORE_Pos, SIO_EV_OVERRUN_ERR_POS);
|
||||
|
||||
return evtmask;
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
sioevents_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
||||
uint32_t isr;
|
||||
sioevents_t events = (sioevents_t)0;
|
||||
|
||||
/* Getting all ISR flags.
|
||||
NOTE: Do not trust the position of other bits in ISR/ICR because
|
||||
some scientist decided to use different positions for some
|
||||
of them.*/
|
||||
isr = siop->usart->ISR & (SIO_LLD_ISR_RX_ERRORS |
|
||||
USART_ISR_RXNE_RXFNE |
|
||||
USART_ISR_IDLE |
|
||||
USART_ISR_TXE_TXFNF |
|
||||
USART_ISR_TC);
|
||||
|
||||
/* Clearing captured events.*/
|
||||
siop->usart->ICR = isr;
|
||||
|
||||
/* Status flags cleared, now the RX-related interrupts can be
|
||||
enabled again.*/
|
||||
usart_enable_rx_irq(siop);
|
||||
usart_enable_rx_errors_irq(siop);
|
||||
|
||||
/* Translating the status flags in SIO events.*/
|
||||
events |= __sio_reloc_field(isr, USART_ISR_RXNE_RXFNE_Msk, USART_ISR_RXNE_RXFNE_Pos, SIO_EV_RXNOTEMPY_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_TXE_TXFNF_Msk, USART_ISR_TXE_TXFNF_Pos, SIO_EV_TXNOTFULL_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_IDLE_Msk, USART_ISR_IDLE_Pos, SIO_EV_RXIDLE_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_TC_Msk, USART_ISR_TC_Pos, SIO_EV_TXDONE_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_LBDF_Msk, USART_ISR_LBDF_Pos, SIO_EV_BREAK_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_PE_Msk, USART_ISR_PE_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_FE_Msk, USART_ISR_FE_Pos, SIO_EV_FRAMING_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_NE_Msk, USART_ISR_NE_Pos, SIO_EV_NOISE_ERR_POS) |
|
||||
__sio_reloc_field(isr, USART_ISR_ORE_Msk, USART_ISR_ORE_Pos, SIO_EV_OVERRUN_ERR_POS);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -635,7 +652,8 @@ size_t sio_lld_read(SIODriver *siop, uint8_t *buffer, size_t n) {
|
|||
rd = 0U;
|
||||
while (true) {
|
||||
|
||||
/* If the RX FIFO has been emptied then the interrupt is enabled again.*/
|
||||
/* If the RX FIFO has been emptied then the RX FIFO and IDLE interrupts
|
||||
are enabled again.*/
|
||||
if (sio_lld_is_rx_empty(siop)) {
|
||||
usart_enable_rx_irq(siop);
|
||||
break;
|
||||
|
@ -767,110 +785,109 @@ msg_t sio_lld_control(SIODriver *siop, unsigned int operation, void *arg) {
|
|||
*/
|
||||
void sio_lld_serve_interrupt(SIODriver *siop) {
|
||||
USART_TypeDef *u = siop->usart;
|
||||
uint32_t isr, cr1, cr2, cr3, evtmask, irqmask;
|
||||
uint32_t isr, isrmask;
|
||||
uint32_t cr1, cr2, cr3;
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||
disabled instead.*/
|
||||
isr = u->ISR;
|
||||
|
||||
/* Read on control registers.*/
|
||||
cr1 = u->CR1;
|
||||
cr2 = u->CR2;
|
||||
cr3 = u->CR3;
|
||||
|
||||
/* Enabled errors/events handling.*/
|
||||
irqmask = ((cr1 & USART_CR1_PEIE) != 0U ? USART_ISR_PE : 0U) |
|
||||
((cr1 & USART_CR1_RXNEIE) != 0U ? USART_ISR_ORE : 0U) |
|
||||
((cr2 & USART_CR2_LBDIE) != 0U ? USART_ISR_LBDF : 0U) |
|
||||
((cr3 & USART_CR3_EIE) != 0U ? USART_ISR_FE |
|
||||
USART_ISR_ORE |
|
||||
USART_ISR_NE : 0U);
|
||||
evtmask = isr & irqmask;
|
||||
if (evtmask != 0U) {
|
||||
/* Calculating the mask of the interrupts to be processed, BTW, thanks ST
|
||||
for placing interrupt enable bits randomly in 3 distinct registers
|
||||
instead of a dedicated IER (ISR, ICR, see the pattern?).*/
|
||||
isrmask = __sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_NE_Pos) |
|
||||
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_FE_Pos) |
|
||||
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_ORE_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_PEIE_Msk, USART_CR1_PEIE_Pos, USART_ISR_PE_Pos) |
|
||||
__sio_reloc_field(cr2, USART_CR2_LBDIE_Msk, USART_CR2_LBDIE_Pos, USART_ISR_LBDF_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_IDLEIE_Msk, USART_CR1_IDLEIE_Pos, USART_ISR_IDLE_Pos) |
|
||||
__sio_reloc_field(cr3, USART_CR3_RXFTIE_Msk, USART_CR3_RXFTIE_Pos, USART_ISR_RXFT_Pos) |
|
||||
__sio_reloc_field(cr3, USART_CR3_TXFTIE_Msk, USART_CR3_TXFTIE_Pos, USART_ISR_TXFT_Pos) |
|
||||
__sio_reloc_field(cr1, USART_CR1_TCIE_Msk, USART_CR1_TCIE_Pos, USART_ISR_TC_Pos);
|
||||
|
||||
/* Disabling event sources until errors are recognized by the
|
||||
application.*/
|
||||
u->CR1 = cr1 & ~USART_CR1_PEIE;
|
||||
u->CR2 = cr2 & ~USART_CR2_LBDIE;
|
||||
u->CR3 = cr3 & ~USART_CR3_EIE;
|
||||
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||
disabled instead.*/
|
||||
isr = u->ISR & isrmask;
|
||||
if (isr != 0U) {
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx_evt(siop);
|
||||
/* Error events handled as a group, except ORE.*/
|
||||
if ((isr & (USART_ISR_LBDF | USART_ISR_NE | USART_ISR_FE |
|
||||
USART_ISR_PE | USART_ISR_ORE)) != 0U) {
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, SIO_MSG_ERRORS);
|
||||
#if SIO_USE_SYNCHRONIZATION
|
||||
/* The idle flag is forcibly cleared when an RX error event is
|
||||
detected.*/
|
||||
u->ICR = USART_ISR_IDLE;
|
||||
#endif
|
||||
|
||||
/* Values could have been changed by the callback, CR2 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
cr3 = u->CR3;
|
||||
/* Interrupt sources disabled.*/
|
||||
cr3 &= ~USART_CR3_EIE;
|
||||
cr2 &= ~USART_CR2_LBDIE;
|
||||
cr1 &= ~USART_CR1_PEIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_events(siop);
|
||||
}
|
||||
|
||||
/* Idle RX event.*/
|
||||
if ((isr & USART_ISR_IDLE) != 0U) {
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr1 &= ~USART_CR1_IDLEIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rxidle(siop);
|
||||
}
|
||||
|
||||
/* RX FIFO is non-empty.*/
|
||||
if ((isr & USART_ISR_RXFT) != 0U) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION
|
||||
/* The idle flag is forcibly cleared when an RX data event is
|
||||
detected.*/
|
||||
u->ICR = USART_ISR_IDLE;
|
||||
#endif
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr3 &= ~USART_CR3_RXFTIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop);
|
||||
}
|
||||
|
||||
/* TX FIFO is non-full.*/
|
||||
if ((isr & USART_ISR_TXFT) != 0U) {
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr3 &= ~USART_CR3_TXFTIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_tx(siop);
|
||||
}
|
||||
|
||||
/* Physical transmission end.*/
|
||||
if ((isr & USART_ISR_TC) != 0U) {
|
||||
|
||||
/* Interrupt source disabled.*/
|
||||
cr1 &= ~USART_CR1_TCIE;
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_txend(siop);
|
||||
}
|
||||
|
||||
/* Updating control registers, some sources could have been disabled.*/
|
||||
u->CR1 = cr1;
|
||||
u->CR2 = cr2;
|
||||
u->CR3 = cr3;
|
||||
|
||||
/* The callback is invoked.*/
|
||||
__sio_callback(siop);
|
||||
}
|
||||
|
||||
/* RX FIFO is non-empty.*/
|
||||
if (((cr3 & USART_CR3_RXFTIE) != 0U) &&
|
||||
(isr & USART_ISR_RXFT) != 0U) {
|
||||
|
||||
/* Called once then the interrupt source is disabled.*/
|
||||
u->CR3 = cr3 & ~USART_CR3_RXFTIE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, MSG_OK);
|
||||
|
||||
/* Values could have been changed by the callback, CR2 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
cr3 = u->CR3;
|
||||
}
|
||||
|
||||
/* TX FIFO is non-full.*/
|
||||
if (((cr3 & USART_CR3_TXFTIE) != 0U) &&
|
||||
(isr & USART_ISR_TXFT) != 0U) {
|
||||
|
||||
/* Called once then the interrupt is disabled.*/
|
||||
u->CR3 = cr3 & ~USART_CR3_TXFTIE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_tx(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_tx(siop, MSG_OK);
|
||||
|
||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
}
|
||||
|
||||
/* RX idle condition.*/
|
||||
if (((cr1 & USART_CR1_IDLEIE) != 0U) &&
|
||||
(isr & USART_ISR_IDLE) != 0U) {
|
||||
|
||||
/* The idle flag requires clearing, it stays enabled.*/
|
||||
u->ICR = USART_ISR_IDLE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_rx_idle(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_rx(siop, SIO_MSG_IDLE);
|
||||
|
||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
||||
cr1 = u->CR1;
|
||||
}
|
||||
|
||||
/* Physical transmission end.*/
|
||||
if (((cr1 & USART_CR1_TCIE) != 0U) &&
|
||||
(isr & USART_ISR_TC) != 0U) {
|
||||
|
||||
/* Called once then the interrupt is disabled.*/
|
||||
u->CR1 = cr1 & ~USART_CR1_TCIE;
|
||||
|
||||
/* The callback is invoked if defined.*/
|
||||
__sio_callback_tx_end(siop);
|
||||
|
||||
/* Waiting thread woken, if any.*/
|
||||
__sio_wakeup_txend(siop, MSG_OK);
|
||||
else {
|
||||
osalDbgAssert(false, "spurious interrupt");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,13 @@
|
|||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Mask of RX-related errors in the ISR register.
|
||||
*/
|
||||
#define SIO_LLD_ISR_RX_ERRORS (USART_ISR_NE | USART_ISR_FE | \
|
||||
USART_ISR_PE | USART_ISR_ORE | \
|
||||
USART_ISR_LBDF)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
@ -299,11 +306,6 @@
|
|||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of a SIO events mask.
|
||||
*/
|
||||
typedef uint32_t sio_events_mask_t;
|
||||
|
||||
/**
|
||||
* @brief Low level fields of the SIO driver structure.
|
||||
*/
|
||||
|
@ -341,6 +343,34 @@ typedef uint32_t sio_events_mask_t;
|
|||
#define sio_lld_is_rx_empty(siop) \
|
||||
(bool)(((siop)->usart->ISR & USART_ISR_RXNE_RXFNE) == 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines the activity state of the receiver.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX activity state.
|
||||
* @retval false if RX is in active state.
|
||||
* @retval true if RX is in idle state.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define sio_lld_is_rx_idle(siop) \
|
||||
(bool)(((siop)->usart->ISR & USART_ISR_IDLE) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines if RX has pending error events to be read and cleared.
|
||||
* @note Only error and protocol errors are handled, data events are not
|
||||
* considered.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The RX error events.
|
||||
* @retval false if RX has no pending events
|
||||
* @retval true if RX has pending events
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define sio_lld_has_rx_errors(siop) \
|
||||
(bool)(((siop)->usart->ISR & SIO_LLD_ISR_RX_ERRORS) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Determines the state of the TX FIFO.
|
||||
*
|
||||
|
@ -423,7 +453,9 @@ extern "C" {
|
|||
void sio_lld_stop(SIODriver *siop);
|
||||
void sio_lld_start_operation(SIODriver *siop);
|
||||
void sio_lld_stop_operation(SIODriver *siop);
|
||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop);
|
||||
void sio_lld_update_enable_flags(SIODriver *siop);
|
||||
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop);
|
||||
sioevents_t sio_lld_get_and_clear_events(SIODriver *siop);
|
||||
size_t sio_lld_read(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||
size_t sio_lld_write(SIODriver *siop, const uint8_t *buffer, size_t n);
|
||||
msg_t sio_lld_get(SIODriver *siop);
|
||||
|
|
|
@ -39,11 +39,7 @@
|
|||
/*===========================================================================*/
|
||||
|
||||
static const SIOOperation default_operation = {
|
||||
.rx_cb = NULL,
|
||||
.rx_idle_cb = NULL,
|
||||
.tx_cb = NULL,
|
||||
.tx_end_cb = NULL,
|
||||
.rx_evt_cb = NULL
|
||||
.cb = NULL
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -62,7 +58,7 @@ static size_t sync_write(void *ip, const uint8_t *bp, size_t n,
|
|||
msg_t msg;
|
||||
|
||||
msg = sioSynchronizeTX(siop, timeout);
|
||||
if (msg < MSG_OK) {
|
||||
if (msg != MSG_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -84,7 +80,7 @@ static size_t sync_read(void *ip, uint8_t *bp, size_t n,
|
|||
msg_t msg;
|
||||
|
||||
msg = sioSynchronizeRX(siop, timeout);
|
||||
if (msg < MSG_OK) {
|
||||
if (msg != MSG_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -225,10 +221,15 @@ void sioInit(void) {
|
|||
void sioObjectInit(SIODriver *siop) {
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
siop->vmt = &vmt;
|
||||
siop->vmt = &vmt;
|
||||
siop->sync_rx = NULL;
|
||||
siop->sync_rxidle = NULL;
|
||||
siop->sync_tx = NULL;
|
||||
siop->sync_txend = NULL;
|
||||
#endif
|
||||
siop->state = SIO_STOP;
|
||||
siop->config = NULL;
|
||||
siop->state = SIO_STOP;
|
||||
siop->config = NULL;
|
||||
siop->enabled = (sioflags_t)0;
|
||||
|
||||
/* Optional, user-defined initializer.*/
|
||||
#if defined(SIO_DRIVER_EXT_INIT_HOOK)
|
||||
|
@ -324,6 +325,13 @@ void sioStartOperation(SIODriver *siop, const SIOOperation *operation) {
|
|||
if (siop->state == SIO_READY) {
|
||||
sio_lld_start_operation(siop);
|
||||
siop->state = SIO_ACTIVE;
|
||||
|
||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
/* If synchronization is enabled then some events are enforced by
|
||||
default.*/
|
||||
sioWriteEnableFlagsI(siop,
|
||||
SIO_FL_ALL_DATA | SIO_FL_ALL_ERRORS | SIO_FL_ALL_PROTOCOL);
|
||||
#endif
|
||||
}
|
||||
|
||||
osalSysUnlock();
|
||||
|
@ -349,6 +357,7 @@ void sioStopOperation(SIODriver *siop) {
|
|||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||
/* Informing waiting threads, if any.*/
|
||||
osalThreadResumeI(&siop->sync_rx, MSG_RESET);
|
||||
osalThreadResumeI(&siop->sync_rxidle, MSG_RESET);
|
||||
osalThreadResumeI(&siop->sync_tx, MSG_RESET);
|
||||
osalThreadResumeI(&siop->sync_txend, MSG_RESET);
|
||||
#endif
|
||||
|
@ -363,25 +372,114 @@ void sioStopOperation(SIODriver *siop) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Return the pending SIO events flags.
|
||||
* @brief Writes the condition flags mask.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @param[in] flags flags mask to be written
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void sioWriteEnableFlags(SIODriver *siop, sioflags_t flags) {
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
sioWriteEnableFlagsI(siop, flags);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables flags to the condition flags mask.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @param[in] flags flags mask to be enabled
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void sioSetEnableFlags(SIODriver *siop, sioflags_t flags) {
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
sioSetEnableFlagsI(siop, flags);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables flags from the condition flags mask.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @param[in] flags flags mask to be disabled
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void sioClearEnableFlags(SIODriver *siop, sioflags_t flags) {
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
sioClearEnableFlagsI(siop, flags);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO error event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending error event flags.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
sioevents_t sioGetAndClearErrors(SIODriver *siop) {
|
||||
sioevents_t errors;
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
errors = sioGetAndClearErrorsI(siop);
|
||||
|
||||
osalSysUnlock();
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get and clears SIO event flags.
|
||||
*
|
||||
* @param[in] siop pointer to the @p SIODriver object
|
||||
* @return The pending event flags.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
sio_events_mask_t sioGetAndClearEvents(SIODriver *siop) {
|
||||
sio_events_mask_t evtmask;
|
||||
sioevents_t sioGetAndClearEvents(SIODriver *siop) {
|
||||
sioevents_t events;
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
evtmask = sioGetAndClearEventsI(siop);
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
events = sioGetAndClearEventsI(siop);
|
||||
|
||||
osalSysUnlock();
|
||||
|
||||
return evtmask;
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -404,6 +502,8 @@ size_t sioAsyncRead(SIODriver *siop, uint8_t *buffer, size_t n) {
|
|||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
n = sioAsyncReadI(siop, buffer, n);
|
||||
|
||||
osalSysUnlock();
|
||||
|
@ -431,6 +531,8 @@ size_t sioAsyncWrite(SIODriver *siop, const uint8_t *buffer, size_t n) {
|
|||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
n = sioAsyncWriteI(siop, buffer, n);
|
||||
|
||||
osalSysUnlock();
|
||||
|
@ -450,14 +552,13 @@ size_t sioAsyncWrite(SIODriver *siop, const uint8_t *buffer, size_t n) {
|
|||
* @return The synchronization result.
|
||||
* @retval MSG_OK if there is data in the RX FIFO.
|
||||
* @retval MSG_TIMEOUT if synchronization timed out.
|
||||
* @retval MSG_RESET operation has been stopped while waiting.
|
||||
* @retval SIO_MSG_IDLE if RX line went idle.
|
||||
* @retval MSG_RESET it the operation has been stopped while waiting.
|
||||
* @retval SIO_MSG_ERRORS if RX errors occurred during wait.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout) {
|
||||
msg_t msg = MSG_OK;
|
||||
msg_t msg;
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
|
@ -465,13 +566,65 @@ msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout) {
|
|||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
/* Checking for errors before going to sleep.*/
|
||||
if (((siop->enabled & SIO_FL_ALL_ERRORS) != 0U) && sioHasRXErrorsX(siop)) {
|
||||
osalSysUnlock();
|
||||
return SIO_MSG_ERRORS;
|
||||
}
|
||||
|
||||
msg = MSG_OK;
|
||||
/*lint -save -e506 -e681 [2.1] Silencing this error because it is
|
||||
tested with a template implementation of sio_lld_is_rx_empty() which
|
||||
is constant.*/
|
||||
while (sio_lld_is_rx_empty(siop)) {
|
||||
while (sioIsRXEmptyX(siop)) {
|
||||
/*lint -restore*/
|
||||
msg = osalThreadSuspendTimeoutS(&siop->sync_rx, timeout);
|
||||
if (msg < MSG_OK) {
|
||||
if (msg != MSG_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
osalSysUnlock();
|
||||
|
||||
return msg;
|
||||
}
|
||||
/**
|
||||
* @brief Synchronizes with RX going idle.
|
||||
* @note This function can only be called by a single thread at time.
|
||||
*
|
||||
* @param[in] siop pointer to an @p SIODriver structure
|
||||
* @param[in] timeout synchronization timeout
|
||||
* @return The synchronization result.
|
||||
* @retval MSG_OK if RW went idle.
|
||||
* @retval MSG_TIMEOUT if synchronization timed out.
|
||||
* @retval MSG_RESET it the operation has been stopped while waiting.
|
||||
* @retval SIO_MSG_ERRORS if RX errors occurred during wait.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t sioSynchronizeRXIdle(SIODriver *siop, sysinterval_t timeout) {
|
||||
msg_t msg;
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
/* Checking for errors before going to sleep.*/
|
||||
if (((siop->enabled & SIO_FL_ALL_ERRORS) != 0U) && sioHasRXErrorsX(siop)) {
|
||||
osalSysUnlock();
|
||||
return SIO_MSG_ERRORS;
|
||||
}
|
||||
|
||||
msg = MSG_OK;
|
||||
/*lint -save -e506 -e681 [2.1] Silencing this error because it is
|
||||
tested with a template implementation of sio_lld_is_rx_empty() which
|
||||
is constant.*/
|
||||
while (!sioIsRXIdleX(siop)) {
|
||||
/*lint -restore*/
|
||||
msg = osalThreadSuspendTimeoutS(&siop->sync_rxidle, timeout);
|
||||
if (msg != MSG_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -497,7 +650,7 @@ msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout) {
|
|||
* @api
|
||||
*/
|
||||
msg_t sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout) {
|
||||
msg_t msg = MSG_OK;
|
||||
msg_t msg;
|
||||
|
||||
osalDbgCheck(siop != NULL);
|
||||
|
||||
|
@ -505,13 +658,14 @@ msg_t sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout) {
|
|||
|
||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||
|
||||
msg = MSG_OK;
|
||||
/*lint -save -e506 -e681 [2.1] Silencing this error because it is
|
||||
tested with a template implementation of sio_lld_is_tx_full() which
|
||||
is constant.*/
|
||||
while (sio_lld_is_tx_full(siop)) {
|
||||
while (sioIsTXFullX(siop)) {
|
||||
/*lint -restore*/
|
||||
msg = osalThreadSuspendTimeoutS(&siop->sync_tx, timeout);
|
||||
if (msg < MSG_OK) {
|
||||
if (msg != MSG_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -545,7 +699,7 @@ msg_t sioSynchronizeTXEnd(SIODriver *siop, sysinterval_t timeout) {
|
|||
/*lint -save -e506 -e774 [2.1, 14.3] Silencing this error because
|
||||
it is tested with a template implementation of sio_lld_is_tx_ongoing()
|
||||
which is constant.*/
|
||||
if (sio_lld_is_tx_ongoing(siop)) {
|
||||
if (sioIsTXOngoingX(siop)) {
|
||||
/*lint -restore*/
|
||||
msg = osalThreadSuspendTimeoutS(&siop->sync_txend, timeout);
|
||||
}
|
||||
|
|
|
@ -74,8 +74,7 @@
|
|||
*****************************************************************************
|
||||
|
||||
*** Next ***
|
||||
- NEW: Made sioStopOperation() and sioStartOperation() call possible in
|
||||
both SIO_READY and SIO_ACTIVE states.
|
||||
- NEW: Reworked HAL SIO driver.
|
||||
- NEW: Non-proprietary LLVM build support.
|
||||
- NEW: Added palReadGroupLatch() to PAL driver.
|
||||
- NEW: Added a Posix-favored shell named "msh" (Mini Shell). The shell is able
|
||||
|
|
Loading…
Reference in New Issue