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_FL_RXNOTEMPY_POS 1
|
||||||
#define SIO_PARITY_ERROR 4 /**< @brief Parity error happened. */
|
#define SIO_FL_TXNOTFULL_POS 2
|
||||||
#define SIO_FRAMING_ERROR 8 /**< @brief Framing error happened. */
|
#define SIO_FL_RXIDLE_POS 3
|
||||||
#define SIO_OVERRUN_ERROR 16 /**< @brief Overflow happened. */
|
#define SIO_FL_TXDONE_POS 4
|
||||||
#define SIO_NOISE_ERROR 32 /**< @brief Noise on the line. */
|
#define SIO_FL_ALL_ERRORS_POS 5
|
||||||
#define SIO_BREAK_DETECTED 64 /**< @brief Break detected. */
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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.
|
* @brief Type of structure representing a SIO driver.
|
||||||
|
@ -168,6 +247,10 @@ struct hal_sio_driver {
|
||||||
* @brief Current configuration data.
|
* @brief Current configuration data.
|
||||||
*/
|
*/
|
||||||
const SIOConfig *config;
|
const SIOConfig *config;
|
||||||
|
/**
|
||||||
|
* @brief Enabled conditions flags.
|
||||||
|
*/
|
||||||
|
sioflags_t enabled;
|
||||||
/**
|
/**
|
||||||
* @brief Current configuration data.
|
* @brief Current configuration data.
|
||||||
*/
|
*/
|
||||||
|
@ -177,6 +260,10 @@ struct hal_sio_driver {
|
||||||
* @brief Synchronization point for RX.
|
* @brief Synchronization point for RX.
|
||||||
*/
|
*/
|
||||||
thread_reference_t sync_rx;
|
thread_reference_t sync_rx;
|
||||||
|
/**
|
||||||
|
* @brief Synchronization point for RX idle.
|
||||||
|
*/
|
||||||
|
thread_reference_t sync_rxidle;
|
||||||
/**
|
/**
|
||||||
* @brief Synchronization point for TX.
|
* @brief Synchronization point for TX.
|
||||||
*/
|
*/
|
||||||
|
@ -198,30 +285,10 @@ struct hal_sio_driver {
|
||||||
*/
|
*/
|
||||||
struct hal_sio_operation {
|
struct hal_sio_operation {
|
||||||
/**
|
/**
|
||||||
* @brief Receive non-empty callback.
|
* @brief Events callback.
|
||||||
* @note Can be @p NULL.
|
* @note Can be @p NULL.
|
||||||
*/
|
*/
|
||||||
siocb_t rx_cb;
|
siocb_t 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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -233,27 +300,122 @@ struct hal_sio_operation {
|
||||||
*
|
*
|
||||||
* @param[in] siop pointer to the @p SIODriver object
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The RX FIFO state.
|
* @return The RX FIFO state.
|
||||||
* @retval false if RX FIFO is not empty
|
* @retval false if RX FIFO is not empty.
|
||||||
* @retval true if RX FIFO is empty
|
* @retval true if RX FIFO is empty.
|
||||||
*
|
*
|
||||||
* @xclass
|
* @xclass
|
||||||
*/
|
*/
|
||||||
#define sioIsRXEmptyX(siop) sio_lld_is_rx_empty(siop)
|
#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.
|
* @brief Determines the state of the TX FIFO.
|
||||||
*
|
*
|
||||||
* @param[in] siop pointer to the @p SIODriver object
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The TX FIFO state.
|
* @return The TX FIFO state.
|
||||||
* @retval false if TX FIFO is not full
|
* @retval false if TX FIFO is not full.
|
||||||
* @retval true if TX FIFO is full
|
* @retval true if TX FIFO is full.
|
||||||
*
|
*
|
||||||
* @xclass
|
* @xclass
|
||||||
*/
|
*/
|
||||||
#define sioIsTXFullX(siop) sio_lld_is_tx_full(siop)
|
#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
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The pending event flags.
|
* @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
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
#define __sio_callback_rx(siop) { \
|
#define __sio_callback(siop) do { \
|
||||||
if ((siop)->operation->rx_cb != NULL) { \
|
if ((siop)->operation->cb != NULL) { \
|
||||||
(siop)->operation->rx_cb(siop); \
|
(siop)->operation->cb(siop); \
|
||||||
} \
|
} \
|
||||||
}
|
} while (false)
|
||||||
|
|
||||||
/**
|
|
||||||
* @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); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
|
#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.
|
* @brief Wakes up the RX-waiting thread.
|
||||||
*
|
*
|
||||||
* @param[in] siop pointer to the @p SIODriver object
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @param[in] msg the wake up message
|
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
#define __sio_wakeup_rx(siop, msg) { \
|
#define __sio_wakeup_rx(siop) do { \
|
||||||
osalSysLockFromISR(); \
|
osalSysLockFromISR(); \
|
||||||
osalThreadResumeI(&(siop)->sync_rx, msg); \
|
osalThreadResumeI(&(siop)->sync_rx, MSG_OK); \
|
||||||
osalSysUnlockFromISR(); \
|
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.
|
* @brief Wakes up the TX-waiting thread.
|
||||||
|
@ -424,11 +560,11 @@ struct hal_sio_operation {
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
#define __sio_wakeup_tx(siop, msg) { \
|
#define __sio_wakeup_tx(siop) do { \
|
||||||
osalSysLockFromISR(); \
|
osalSysLockFromISR(); \
|
||||||
osalThreadResumeI(&(siop)->sync_tx, msg); \
|
osalThreadResumeI(&(siop)->sync_tx, MSG_OK); \
|
||||||
osalSysUnlockFromISR(); \
|
osalSysUnlockFromISR(); \
|
||||||
}
|
} while (false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wakes up the TXend-waiting thread.
|
* @brief Wakes up the TXend-waiting thread.
|
||||||
|
@ -438,11 +574,11 @@ struct hal_sio_operation {
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
#define __sio_wakeup_txend(siop, msg) { \
|
#define __sio_wakeup_txend(siop) do { \
|
||||||
osalSysLockFromISR(); \
|
osalSysLockFromISR(); \
|
||||||
osalThreadResumeI(&(siop)->sync_txend, msg); \
|
osalThreadResumeI(&(siop)->sync_txend, MSG_OK); \
|
||||||
osalSysUnlockFromISR(); \
|
osalSysUnlockFromISR(); \
|
||||||
}
|
} while (false)
|
||||||
#else /* !SIO_USE_SYNCHRONIZATION */
|
#else /* !SIO_USE_SYNCHRONIZATION */
|
||||||
#define __sio_wakeup_rx(siop, msg)
|
#define __sio_wakeup_rx(siop, msg)
|
||||||
#define __sio_wakeup_tx(siop, msg)
|
#define __sio_wakeup_tx(siop, msg)
|
||||||
|
@ -450,6 +586,16 @@ struct hal_sio_operation {
|
||||||
#endif /* !SIO_USE_SYNCHRONIZATION */
|
#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. */
|
/* External declarations. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -463,11 +609,16 @@ extern "C" {
|
||||||
void sioStop(SIODriver *siop);
|
void sioStop(SIODriver *siop);
|
||||||
void sioStartOperation(SIODriver *siop, const SIOOperation *operation);
|
void sioStartOperation(SIODriver *siop, const SIOOperation *operation);
|
||||||
void sioStopOperation(SIODriver *siop);
|
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 sioAsyncRead(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||||
size_t sioAsyncWrite(SIODriver *siop, const 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__)
|
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
|
||||||
msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout);
|
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 sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout);
|
||||||
msg_t sioSynchronizeTXEnd(SIODriver *siop, sysinterval_t timeout);
|
msg_t sioSynchronizeTXEnd(SIODriver *siop, sysinterval_t timeout);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -77,40 +77,27 @@ static const SIOConfig default_config = {
|
||||||
|
|
||||||
__STATIC_INLINE void uart_enable_rx_irq(SIODriver *siop) {
|
__STATIC_INLINE void uart_enable_rx_irq(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
if ((siop->enabled & SIO_FL_RXNOTEMPY) != 0U) {
|
||||||
siop->uart->UARTIMSC |= (UART_UARTIMSC_RXIM | UART_UARTIMSC_RTIM);
|
|
||||||
#else
|
|
||||||
if (siop->operation->rx_cb != NULL) {
|
|
||||||
siop->uart->UARTIMSC |= UART_UARTIMSC_RXIM;
|
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;
|
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
|
if ((siop->enabled & SIO_FL_ALL_ERRORS) != 0U) {
|
||||||
siop->uart->UARTIMSC |= UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
|
||||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM;
|
|
||||||
#else
|
|
||||||
if (siop->operation->rx_evt_cb != NULL) {
|
|
||||||
siop->uart->UARTIMSC |= UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
siop->uart->UARTIMSC |= UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM;
|
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE void uart_enable_tx_irq(SIODriver *siop) {
|
__STATIC_INLINE void uart_enable_tx_irq(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
if ((siop->enabled & SIO_FL_TXNOTFULL) != 0U) {
|
||||||
siop->uart->UARTIMSC |= UART_UARTIMSC_TXIM;
|
|
||||||
#else
|
|
||||||
if (siop->operation->tx_cb != NULL) {
|
|
||||||
siop->uart->UARTIMSC |= UART_UARTIMSC_TXIM;
|
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
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The operation status.
|
* @return The operation status.
|
||||||
* @retval false if the driver has been correctly started.
|
|
||||||
* @retval true if an error occurred.
|
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
bool sio_lld_start(SIODriver *siop) {
|
msg_t sio_lld_start(SIODriver *siop) {
|
||||||
|
|
||||||
/* Using the default configuration if the application passed a
|
/* Using the default configuration if the application passed a
|
||||||
NULL pointer.*/
|
NULL pointer.*/
|
||||||
|
@ -219,10 +204,9 @@ bool sio_lld_start(SIODriver *siop) {
|
||||||
/* Configures the peripheral.*/
|
/* Configures the peripheral.*/
|
||||||
uart_init(siop);
|
uart_init(siop);
|
||||||
|
|
||||||
return false;
|
return HAL_RET_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deactivates the SIO peripheral.
|
* @brief Deactivates the SIO peripheral.
|
||||||
*
|
*
|
||||||
|
@ -264,38 +248,9 @@ void sio_lld_stop(SIODriver *siop) {
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void sio_lld_start_operation(SIODriver *siop) {
|
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.*/
|
/* Setting up the operation.*/
|
||||||
siop->uart->UARTICR = siop->uart->UARTRIS;
|
siop->uart->UARTICR = siop->uart->UARTRIS;
|
||||||
siop->uart->UARTIMSC |= imsc;
|
|
||||||
siop->uart->UARTCR = siop->config->UARTCR |
|
siop->uart->UARTCR = siop->config->UARTCR |
|
||||||
UART_UARTCR_RXE | UART_UARTCR_TXE | UART_UARTCR_UARTEN;
|
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
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The pending event flags.
|
* @return The pending event flags.
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop) {
|
||||||
sio_events_mask_t evtmask;
|
|
||||||
uint32_t ris;
|
uint32_t ris;
|
||||||
|
sioevents_t errors = (sioevents_t)0;
|
||||||
|
|
||||||
/* Getting and clearing all relevant ISR flags (and only those).*/
|
/* Getting and clearing all relevant RIS flags (and only those).*/
|
||||||
ris = siop->uart->UARTRIS & (UART_UARTRIS_OERIS | UART_UARTRIS_BERIS |
|
ris = siop->uart->UARTRIS & SIO_LLD_ISR_RX_ERRORS;
|
||||||
UART_UARTRIS_PERIS | UART_UARTRIS_FERIS);
|
|
||||||
siop->uart->UARTICR = ris;
|
siop->uart->UARTICR = ris;
|
||||||
|
|
||||||
/* Status flags cleared, now the related interrupts can be enabled again.*/
|
/* 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.*/
|
/* Translating the status flags in SIO events.*/
|
||||||
evtmask = 0U;
|
errors |= __sio_reloc_field(ris, UART_UARTMIS_OEMIS_Msk, UART_UARTMIS_OEMIS_Pos, SIO_EV_OVERRUN_ERR_POS) |
|
||||||
if ((ris & UART_UARTRIS_BERIS) != 0U) {
|
__sio_reloc_field(ris, UART_UARTMIS_BEMIS_Msk, UART_UARTMIS_BEMIS_Pos, SIO_EV_BREAK_POS) |
|
||||||
evtmask |= SIO_BREAK_DETECTED;
|
__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);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
rd = 0U;
|
||||||
while (true) {
|
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)) {
|
if (sio_lld_is_rx_empty(siop)) {
|
||||||
uart_enable_rx_irq(siop);
|
uart_enable_rx_irq(siop);
|
||||||
break;
|
break;
|
||||||
|
@ -501,7 +511,7 @@ msg_t sio_lld_control(SIODriver *siop, unsigned int operation, void *arg) {
|
||||||
*/
|
*/
|
||||||
void sio_lld_serve_interrupt(SIODriver *siop) {
|
void sio_lld_serve_interrupt(SIODriver *siop) {
|
||||||
UART_TypeDef *u = siop->uart;
|
UART_TypeDef *u = siop->uart;
|
||||||
uint32_t mis, imsc, evtmask;
|
uint32_t mis, imsc;
|
||||||
|
|
||||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||||
|
|
||||||
|
@ -512,65 +522,77 @@ void sio_lld_serve_interrupt(SIODriver *siop) {
|
||||||
/* Read on control registers.*/
|
/* Read on control registers.*/
|
||||||
imsc = u->UARTIMSC;
|
imsc = u->UARTIMSC;
|
||||||
|
|
||||||
/* Enabled errors/events handling.*/
|
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||||
evtmask = mis & (UART_UARTMIS_OEMIS | UART_UARTMIS_BEMIS |
|
disabled instead.*/
|
||||||
UART_UARTMIS_PEMIS | UART_UARTMIS_FEMIS);
|
if (mis != 0U) {
|
||||||
|
|
||||||
|
/* Error events handled as a group, except ORE.*/
|
||||||
|
if ((mis & SIO_LLD_ISR_RX_ERRORS) != 0U) {
|
||||||
|
|
||||||
|
#if SIO_USE_SYNCHRONIZATION
|
||||||
|
/* The idle flag is forcibly cleared when an RX error event is
|
||||||
|
detected.*/
|
||||||
|
imsc &= ~UART_UARTIMSC_RTIM;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (evtmask != 0U) {
|
|
||||||
/* Disabling event sources.*/
|
/* Disabling event sources.*/
|
||||||
u->UARTIMSC = imsc & ~(UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
imsc &= ~(UART_UARTIMSC_OEIM | UART_UARTIMSC_BEIM |
|
||||||
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM);
|
UART_UARTIMSC_PEIM | UART_UARTIMSC_FEIM);
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_callback_rx_evt(siop);
|
__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.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_rx(siop, SIO_MSG_ERRORS);
|
__sio_wakeup_rxidle(siop);
|
||||||
|
|
||||||
/* Values could have been changed by the callback. */
|
|
||||||
imsc = u->UARTIMSC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX FIFO is non-empty.*/
|
/* RX FIFO is non-empty.*/
|
||||||
if (((mis & UART_UARTMIS_RXMIS) != 0U)) {
|
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.*/
|
#if SIO_USE_SYNCHRONIZATION
|
||||||
__sio_callback_rx(siop);
|
/* 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.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_rx(siop, MSG_OK);
|
__sio_wakeup_rx(siop);
|
||||||
|
|
||||||
/* 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.*/
|
/* TX FIFO is non-full.*/
|
||||||
if ((mis & UART_UARTMIS_TXMIS) != 0U) {
|
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.*/
|
/* Called once then the interrupt source is disabled.*/
|
||||||
__sio_callback_tx(siop);
|
imsc &= ~UART_UARTIMSC_TXIM;
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_tx(siop, MSG_OK);
|
__sio_wakeup_tx(siop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Updating IMSC, some sources could have been disabled.*/
|
||||||
|
u->UARTIMSC = imsc;
|
||||||
|
|
||||||
|
/* The callback is invoked.*/
|
||||||
|
__sio_callback(siop);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
osalDbgAssert(false, "spurious interrupt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,14 @@
|
||||||
/* Driver constants. */
|
/* 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. */
|
/* Driver pre-compile time settings. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -95,11 +103,6 @@
|
||||||
/* Driver data structures and types. */
|
/* Driver data structures and types. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Type of a SIO events mask.
|
|
||||||
*/
|
|
||||||
typedef uint32_t sio_events_mask_t;
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver macros. */
|
/* Driver macros. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -136,6 +139,33 @@ typedef uint32_t sio_events_mask_t;
|
||||||
#define sio_lld_is_rx_empty(siop) \
|
#define sio_lld_is_rx_empty(siop) \
|
||||||
(bool)(((siop)->uart->UARTFR & UART_UARTFR_RXFE) != 0U)
|
(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.
|
* @brief Determines the state of the TX FIFO.
|
||||||
*
|
*
|
||||||
|
@ -178,11 +208,13 @@ extern SIODriver SIOD1;
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
void sio_lld_init(void);
|
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_stop(SIODriver *siop);
|
||||||
void sio_lld_start_operation(SIODriver *siop);
|
void sio_lld_start_operation(SIODriver *siop);
|
||||||
void sio_lld_stop_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_read(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||||
size_t sio_lld_write(SIODriver *siop, const 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);
|
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) {
|
__STATIC_INLINE void usart_enable_rx_irq(SIODriver *siop) {
|
||||||
|
uint32_t cr1;
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
cr1 = siop->usart->CR1;
|
||||||
siop->usart->CR1 |= USART_CR1_RXNEIE;
|
if ((siop->enabled & SIO_FL_RXNOTEMPY) != 0U) {
|
||||||
#else
|
cr1 |= USART_CR1_RXNEIE;
|
||||||
if (siop->operation->rx_cb != NULL) {
|
|
||||||
siop->usart->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
|
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;
|
|
||||||
#else
|
|
||||||
if (siop->operation->rx_evt_cb != NULL) {
|
|
||||||
siop->usart->CR1 |= USART_CR1_PEIE;
|
siop->usart->CR1 |= USART_CR1_PEIE;
|
||||||
siop->usart->CR2 |= USART_CR2_LBDIE;
|
siop->usart->CR2 |= USART_CR2_LBDIE;
|
||||||
siop->usart->CR3 |= USART_CR3_EIE;
|
siop->usart->CR3 |= USART_CR3_EIE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE void usart_enable_tx_irq(SIODriver *siop) {
|
__STATIC_INLINE void usart_enable_tx_irq(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
if ((siop->enabled & SIO_FL_TXNOTFULL) != 0U) {
|
||||||
siop->usart->CR1 |= USART_CR1_TXEIE;
|
|
||||||
#else
|
|
||||||
if (siop->operation->tx_cb != NULL) {
|
|
||||||
siop->usart->CR1 |= USART_CR1_TXEIE;
|
siop->usart->CR1 |= USART_CR1_TXEIE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE void usart_enable_tx_end_irq(SIODriver *siop) {
|
__STATIC_INLINE void usart_enable_tx_end_irq(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
if ((siop->enabled & SIO_FL_TXDONE) != 0U) {
|
||||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
|
||||||
#else
|
|
||||||
if (siop->operation->tx_end_cb != NULL) {
|
|
||||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
siop->usart->CR1 |= USART_CR1_TCIE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -367,7 +355,7 @@ msg_t sio_lld_start(SIODriver *siop) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
osalDbgAssert(false, "invalid USART instance");
|
osalDbgAssert(false, "invalid SIO instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver object low level initializations.*/
|
/* Driver object low level initializations.*/
|
||||||
|
@ -454,7 +442,7 @@ void sio_lld_stop(SIODriver *siop) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
osalDbgAssert(false, "invalid USART instance");
|
osalDbgAssert(false, "invalid SIO instance");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,43 +455,10 @@ void sio_lld_stop(SIODriver *siop) {
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void sio_lld_start_operation(SIODriver *siop) {
|
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.*/
|
/* Setting up the operation.*/
|
||||||
siop->usart->ICR = siop->usart->ISR;
|
siop->usart->ICR = siop->usart->ISR;
|
||||||
siop->usart->CR2 |= cr2irq;
|
siop->usart->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||||
siop->usart->CR3 |= cr3irq;
|
|
||||||
siop->usart->CR1 |= cr1irq | 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) {
|
void sio_lld_stop_operation(SIODriver *siop) {
|
||||||
|
|
||||||
/* Stop operation.*/
|
/* Stop operation.*/
|
||||||
siop->usart->CR1 &= USART_CR1_CFG_FORBIDDEN;
|
siop->usart->CR1 &= ~USART_CR1_CFG_FORBIDDEN;
|
||||||
siop->usart->CR2 &= USART_CR2_CFG_FORBIDDEN;
|
siop->usart->CR2 &= ~USART_CR2_CFG_FORBIDDEN;
|
||||||
siop->usart->CR3 &= USART_CR3_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
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The pending event flags.
|
* @return The pending event flags.
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop) {
|
||||||
sio_events_mask_t evtmask;
|
|
||||||
uint32_t isr;
|
uint32_t isr;
|
||||||
|
sioevents_t errors = (sioevents_t)0;
|
||||||
|
|
||||||
/* Getting and clearing all relevant ISR flags (and only those).*/
|
/* Getting all error ISR flags (and only those).
|
||||||
isr = siop->usart->ISR & (USART_ISR_PE | USART_ISR_LBDF | USART_ISR_FE |
|
NOTE: Do not trust the position of other bits in ISR/ICR because
|
||||||
USART_ISR_ORE | USART_ISR_NE);
|
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;
|
siop->usart->ICR = isr;
|
||||||
|
|
||||||
/* Status flags cleared, now the related interrupts can be enabled again.*/
|
/* Status flags cleared, now the RX errors-related interrupts can be
|
||||||
usart_enable_rx_evt_irq(siop);
|
enabled again.*/
|
||||||
|
usart_enable_rx_errors_irq(siop);
|
||||||
|
|
||||||
/* Translating the status flags in SIO events.*/
|
/* Translating the status flags in SIO events.*/
|
||||||
evtmask = 0U;
|
errors |= __sio_reloc_field(isr, USART_ISR_LBDF_Msk, USART_ISR_LBDF_Pos, SIO_EV_BREAK_POS) |
|
||||||
if ((isr & USART_ISR_LBDF) != 0U) {
|
__sio_reloc_field(isr, USART_ISR_PE_Msk, USART_ISR_PE_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||||
evtmask |= SIO_BREAK_DETECTED;
|
__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) |
|
||||||
if ((isr & USART_ISR_ORE) != 0U) {
|
__sio_reloc_field(isr, USART_ISR_ORE_Msk, USART_ISR_ORE_Pos, SIO_EV_OVERRUN_ERR_POS);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
rd = 0U;
|
||||||
while (true) {
|
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)) {
|
if (sio_lld_is_rx_empty(siop)) {
|
||||||
usart_enable_rx_irq(siop);
|
usart_enable_rx_irq(siop);
|
||||||
break;
|
break;
|
||||||
|
@ -711,108 +733,109 @@ msg_t sio_lld_control(SIODriver *siop, unsigned int operation, void *arg) {
|
||||||
*/
|
*/
|
||||||
void sio_lld_serve_interrupt(SIODriver *siop) {
|
void sio_lld_serve_interrupt(SIODriver *siop) {
|
||||||
USART_TypeDef *u = siop->usart;
|
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");
|
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.*/
|
/* Read on control registers.*/
|
||||||
cr1 = u->CR1;
|
cr1 = u->CR1;
|
||||||
cr2 = u->CR2;
|
cr2 = u->CR2;
|
||||||
cr3 = u->CR3;
|
cr3 = u->CR3;
|
||||||
|
|
||||||
/* Enabled errors/events handling.*/
|
/* Calculating the mask of the interrupts to be processed, BTW, thanks ST
|
||||||
irqmask = ((cr1 & USART_CR1_PEIE) != 0U ? USART_ISR_PE : 0U) |
|
for placing interrupt enable bits randomly in 3 distinct registers
|
||||||
((cr1 & USART_CR1_RXNEIE) != 0U ? USART_ISR_ORE : 0U) |
|
instead of a dedicated IER (ISR, ICR, see the pattern?).*/
|
||||||
((cr2 & USART_CR2_LBDIE) != 0U ? USART_ISR_LBDF : 0U) |
|
isrmask = __sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_NE_Pos) |
|
||||||
((cr3 & USART_CR3_EIE) != 0U ? USART_ISR_FE |
|
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_FE_Pos) |
|
||||||
USART_ISR_ORE |
|
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_ORE_Pos) |
|
||||||
USART_ISR_NE : 0U);
|
__sio_reloc_field(cr2, USART_CR2_LBDIE_Msk, USART_CR2_LBDIE_Pos, USART_ISR_LBDF_Pos) |
|
||||||
evtmask = isr & irqmask;
|
__sio_reloc_field(cr1, USART_CR1_PEIE_Msk, USART_CR1_PEIE_Pos, USART_ISR_PE_Pos) |
|
||||||
if (evtmask != 0U) {
|
__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
|
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||||
application.*/
|
disabled instead.*/
|
||||||
u->CR1 = cr1 & ~USART_CR1_PEIE;
|
isr = u->ISR & isrmask;
|
||||||
u->CR2 = cr2 & ~USART_CR2_LBDIE;
|
if (isr != 0U) {
|
||||||
u->CR3 = cr3 & ~USART_CR3_EIE;
|
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
/* Error events handled as a group, except ORE.*/
|
||||||
__sio_callback_rx_evt(siop);
|
if ((isr & (USART_ISR_LBDF | USART_ISR_NE | USART_ISR_FE |
|
||||||
|
USART_ISR_PE | USART_ISR_ORE)) != 0U) {
|
||||||
|
|
||||||
|
#if SIO_USE_SYNCHRONIZATION
|
||||||
|
/* The idle flag is forcibly cleared when an RX error event is
|
||||||
|
detected.*/
|
||||||
|
u->ICR = USART_ISR_IDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Interrupt sources disabled.*/
|
||||||
|
cr3 &= ~USART_CR3_EIE;
|
||||||
|
cr2 &= ~USART_CR2_LBDIE;
|
||||||
|
cr1 &= ~USART_CR1_PEIE;
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_rx(siop, SIO_MSG_ERRORS);
|
__sio_wakeup_events(siop);
|
||||||
|
}
|
||||||
|
|
||||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
/* Idle RX event.*/
|
||||||
cr1 = u->CR1;
|
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.*/
|
/* RX FIFO is non-empty.*/
|
||||||
if (((cr1 & USART_CR1_RXNEIE) != 0U) &&
|
if ((isr & USART_ISR_RXNE) != 0U) {
|
||||||
(isr & USART_ISR_RXNE) != 0U) {
|
|
||||||
|
|
||||||
/* Called once then the interrupt source is disabled.*/
|
#if SIO_USE_SYNCHRONIZATION
|
||||||
u->CR1 = cr1 & ~USART_CR1_RXNEIE;
|
/* The idle flag is forcibly cleared when an RX data event is
|
||||||
|
detected.*/
|
||||||
|
u->ICR = USART_ISR_IDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
/* Interrupt source disabled.*/
|
||||||
__sio_callback_rx(siop);
|
cr1 &= ~USART_CR1_RXNEIE;
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_rx(siop, MSG_OK);
|
__sio_wakeup_rx(siop);
|
||||||
|
|
||||||
/* Values could have been changed by the callback, CR2-CR3 no more needed.*/
|
|
||||||
cr1 = u->CR1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TX FIFO is non-full.*/
|
/* TX FIFO is non-full.*/
|
||||||
if (((cr1 & USART_CR1_TXEIE) != 0U) &&
|
if ((isr & USART_ISR_TXE) != 0U) {
|
||||||
(isr & USART_ISR_TXE) != 0U) {
|
|
||||||
|
|
||||||
/* Called once then the interrupt is disabled.*/
|
/* Interrupt source disabled.*/
|
||||||
u->CR1 = cr1 & ~USART_CR1_TXEIE;
|
cr1 &= ~USART_CR1_TXEIE;
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
|
||||||
__sio_callback_tx(siop);
|
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_tx(siop, MSG_OK);
|
__sio_wakeup_tx(siop);
|
||||||
|
|
||||||
/* 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.*/
|
/* Physical transmission end.*/
|
||||||
if (((cr1 & USART_CR1_TCIE) != 0U) &&
|
if ((isr & USART_ISR_TC) != 0U) {
|
||||||
(isr & USART_ISR_TC) != 0U) {
|
|
||||||
|
|
||||||
/* Called once then the interrupt is disabled.*/
|
/* Interrupt source disabled.*/
|
||||||
u->CR1 = cr1 & ~USART_CR1_TCIE;
|
cr1 &= ~USART_CR1_TCIE;
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
|
||||||
__sio_callback_tx_end(siop);
|
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_txend(siop, MSG_OK);
|
__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);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
osalDbgAssert(false, "spurious interrupt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,13 @@
|
||||||
/* Driver constants. */
|
/* 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. */
|
/* Driver pre-compile time settings. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -252,11 +259,6 @@
|
||||||
/* Driver macros. */
|
/* 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.
|
* @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) \
|
#define sio_lld_is_rx_empty(siop) \
|
||||||
(bool)(((siop)->usart->ISR & USART_ISR_RXNE) == 0U)
|
(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.
|
* @brief Determines the state of the TX FIFO.
|
||||||
*
|
*
|
||||||
|
@ -368,7 +398,9 @@ extern "C" {
|
||||||
void sio_lld_stop(SIODriver *siop);
|
void sio_lld_stop(SIODriver *siop);
|
||||||
void sio_lld_start_operation(SIODriver *siop);
|
void sio_lld_start_operation(SIODriver *siop);
|
||||||
void sio_lld_stop_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_read(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||||
size_t sio_lld_write(SIODriver *siop, const 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);
|
msg_t sio_lld_get(SIODriver *siop);
|
||||||
|
|
|
@ -147,7 +147,7 @@ static const SIOConfig default_config = {
|
||||||
.presc = USART_PRESC1,
|
.presc = USART_PRESC1,
|
||||||
.cr1 = USART_CR1_DATA8 | USART_CR1_OVER16,
|
.cr1 = USART_CR1_DATA8 | USART_CR1_OVER16,
|
||||||
.cr2 = USART_CR2_STOP1_BITS,
|
.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) {
|
__STATIC_INLINE void usart_enable_rx_irq(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
if ((siop->enabled & SIO_FL_RXNOTEMPY) != 0U) {
|
||||||
siop->usart->CR3 |= USART_CR3_RXFTIE;
|
|
||||||
#else
|
|
||||||
if (siop->operation->rx_cb != NULL) {
|
|
||||||
siop->usart->CR3 |= USART_CR3_RXFTIE;
|
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
|
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;
|
|
||||||
#else
|
|
||||||
if (siop->operation->rx_evt_cb != NULL) {
|
|
||||||
siop->usart->CR1 |= USART_CR1_PEIE;
|
siop->usart->CR1 |= USART_CR1_PEIE;
|
||||||
siop->usart->CR2 |= USART_CR2_LBDIE;
|
siop->usart->CR2 |= USART_CR2_LBDIE;
|
||||||
siop->usart->CR3 |= USART_CR3_EIE;
|
siop->usart->CR3 |= USART_CR3_EIE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE void usart_enable_tx_irq(SIODriver *siop) {
|
__STATIC_INLINE void usart_enable_tx_irq(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
if ((siop->enabled & SIO_FL_TXNOTFULL) != 0U) {
|
||||||
siop->usart->CR3 |= USART_CR3_TXFTIE;
|
|
||||||
#else
|
|
||||||
if (siop->operation->tx_cb != NULL) {
|
|
||||||
siop->usart->CR3 |= USART_CR3_TXFTIE;
|
siop->usart->CR3 |= USART_CR3_TXFTIE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE void usart_enable_tx_end_irq(SIODriver *siop) {
|
__STATIC_INLINE void usart_enable_tx_end_irq(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
if ((siop->enabled & SIO_FL_TXDONE) != 0U) {
|
||||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
|
||||||
#else
|
|
||||||
if (siop->operation->tx_end_cb != NULL) {
|
|
||||||
siop->usart->CR1 |= USART_CR1_TCIE;
|
siop->usart->CR1 |= USART_CR1_TCIE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -412,7 +397,7 @@ msg_t sio_lld_start(SIODriver *siop) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
osalDbgAssert(false, "invalid USART instance");
|
osalDbgAssert(false, "invalid SIO instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver object low level initializations.*/
|
/* Driver object low level initializations.*/
|
||||||
|
@ -511,7 +496,7 @@ void sio_lld_stop(SIODriver *siop) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
osalDbgAssert(false, "invalid USART instance");
|
osalDbgAssert(false, "invalid SIO instance");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,42 +509,10 @@ void sio_lld_stop(SIODriver *siop) {
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void sio_lld_start_operation(SIODriver *siop) {
|
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.*/
|
/* Setting up the operation.*/
|
||||||
siop->usart->ICR = siop->usart->ISR;
|
siop->usart->ICR = siop->usart->ISR;
|
||||||
siop->usart->CR2 |= cr2irq;
|
siop->usart->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||||
siop->usart->CR3 |= cr3irq;
|
|
||||||
siop->usart->CR1 |= cr1irq | 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) {
|
void sio_lld_stop_operation(SIODriver *siop) {
|
||||||
|
|
||||||
/* Stop operation.*/
|
/* Stop operation.*/
|
||||||
siop->usart->CR1 &= USART_CR1_CFG_FORBIDDEN;
|
siop->usart->CR1 &= ~USART_CR1_CFG_FORBIDDEN;
|
||||||
siop->usart->CR2 &= USART_CR2_CFG_FORBIDDEN;
|
siop->usart->CR2 &= ~USART_CR2_CFG_FORBIDDEN;
|
||||||
siop->usart->CR3 &= USART_CR3_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
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The pending event flags.
|
* @return The pending event flags.
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
sio_events_mask_t sio_lld_get_and_clear_events(SIODriver *siop) {
|
sioevents_t sio_lld_get_and_clear_errors(SIODriver *siop) {
|
||||||
sio_events_mask_t evtmask;
|
|
||||||
uint32_t isr;
|
uint32_t isr;
|
||||||
|
sioevents_t errors = (sioevents_t)0;
|
||||||
|
|
||||||
/* Getting and clearing all relevant ISR flags (and only those).*/
|
/* Getting all error ISR flags (and only those).
|
||||||
isr = siop->usart->ISR & (USART_ISR_PE | USART_ISR_LBDF | USART_ISR_FE |
|
NOTE: Do not trust the position of other bits in ISR/ICR because
|
||||||
USART_ISR_ORE | USART_ISR_NE);
|
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;
|
siop->usart->ICR = isr;
|
||||||
|
|
||||||
/* Status flags cleared, now the related interrupts can be enabled again.*/
|
/* Status flags cleared, now the RX errors-related interrupts can be
|
||||||
usart_enable_rx_evt_irq(siop);
|
enabled again.*/
|
||||||
|
usart_enable_rx_errors_irq(siop);
|
||||||
|
|
||||||
/* Translating the status flags in SIO events.*/
|
/* Translating the status flags in SIO events.*/
|
||||||
evtmask = 0U;
|
errors |= __sio_reloc_field(isr, USART_ISR_LBDF_Msk, USART_ISR_LBDF_Pos, SIO_EV_BREAK_POS) |
|
||||||
if ((isr & USART_ISR_LBDF) != 0U) {
|
__sio_reloc_field(isr, USART_ISR_PE_Msk, USART_ISR_PE_Pos, SIO_EV_PARITY_ERR_POS) |
|
||||||
evtmask |= SIO_BREAK_DETECTED;
|
__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) |
|
||||||
if ((isr & USART_ISR_ORE) != 0U) {
|
__sio_reloc_field(isr, USART_ISR_ORE_Msk, USART_ISR_ORE_Pos, SIO_EV_OVERRUN_ERR_POS);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
rd = 0U;
|
||||||
while (true) {
|
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)) {
|
if (sio_lld_is_rx_empty(siop)) {
|
||||||
usart_enable_rx_irq(siop);
|
usart_enable_rx_irq(siop);
|
||||||
break;
|
break;
|
||||||
|
@ -767,110 +785,109 @@ msg_t sio_lld_control(SIODriver *siop, unsigned int operation, void *arg) {
|
||||||
*/
|
*/
|
||||||
void sio_lld_serve_interrupt(SIODriver *siop) {
|
void sio_lld_serve_interrupt(SIODriver *siop) {
|
||||||
USART_TypeDef *u = siop->usart;
|
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");
|
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.*/
|
/* Read on control registers.*/
|
||||||
cr1 = u->CR1;
|
cr1 = u->CR1;
|
||||||
cr2 = u->CR2;
|
cr2 = u->CR2;
|
||||||
cr3 = u->CR3;
|
cr3 = u->CR3;
|
||||||
|
|
||||||
/* Enabled errors/events handling.*/
|
/* Calculating the mask of the interrupts to be processed, BTW, thanks ST
|
||||||
irqmask = ((cr1 & USART_CR1_PEIE) != 0U ? USART_ISR_PE : 0U) |
|
for placing interrupt enable bits randomly in 3 distinct registers
|
||||||
((cr1 & USART_CR1_RXNEIE) != 0U ? USART_ISR_ORE : 0U) |
|
instead of a dedicated IER (ISR, ICR, see the pattern?).*/
|
||||||
((cr2 & USART_CR2_LBDIE) != 0U ? USART_ISR_LBDF : 0U) |
|
isrmask = __sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_NE_Pos) |
|
||||||
((cr3 & USART_CR3_EIE) != 0U ? USART_ISR_FE |
|
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_FE_Pos) |
|
||||||
USART_ISR_ORE |
|
__sio_reloc_field(cr3, USART_CR3_EIE_Msk, USART_CR3_EIE_Pos, USART_ISR_ORE_Pos) |
|
||||||
USART_ISR_NE : 0U);
|
__sio_reloc_field(cr1, USART_CR1_PEIE_Msk, USART_CR1_PEIE_Pos, USART_ISR_PE_Pos) |
|
||||||
evtmask = isr & irqmask;
|
__sio_reloc_field(cr2, USART_CR2_LBDIE_Msk, USART_CR2_LBDIE_Pos, USART_ISR_LBDF_Pos) |
|
||||||
if (evtmask != 0U) {
|
__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
|
/* Note, ISR flags are just read but not cleared, ISR sources are
|
||||||
application.*/
|
disabled instead.*/
|
||||||
u->CR1 = cr1 & ~USART_CR1_PEIE;
|
isr = u->ISR & isrmask;
|
||||||
u->CR2 = cr2 & ~USART_CR2_LBDIE;
|
if (isr != 0U) {
|
||||||
u->CR3 = cr3 & ~USART_CR3_EIE;
|
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
/* Error events handled as a group, except ORE.*/
|
||||||
__sio_callback_rx_evt(siop);
|
if ((isr & (USART_ISR_LBDF | USART_ISR_NE | USART_ISR_FE |
|
||||||
|
USART_ISR_PE | USART_ISR_ORE)) != 0U) {
|
||||||
|
|
||||||
|
#if SIO_USE_SYNCHRONIZATION
|
||||||
|
/* The idle flag is forcibly cleared when an RX error event is
|
||||||
|
detected.*/
|
||||||
|
u->ICR = USART_ISR_IDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Interrupt sources disabled.*/
|
||||||
|
cr3 &= ~USART_CR3_EIE;
|
||||||
|
cr2 &= ~USART_CR2_LBDIE;
|
||||||
|
cr1 &= ~USART_CR1_PEIE;
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_rx(siop, SIO_MSG_ERRORS);
|
__sio_wakeup_events(siop);
|
||||||
|
}
|
||||||
|
|
||||||
/* Values could have been changed by the callback, CR2 no more needed.*/
|
/* Idle RX event.*/
|
||||||
cr1 = u->CR1;
|
if ((isr & USART_ISR_IDLE) != 0U) {
|
||||||
cr3 = u->CR3;
|
|
||||||
|
/* Interrupt source disabled.*/
|
||||||
|
cr1 &= ~USART_CR1_IDLEIE;
|
||||||
|
|
||||||
|
/* Waiting thread woken, if any.*/
|
||||||
|
__sio_wakeup_rxidle(siop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX FIFO is non-empty.*/
|
/* RX FIFO is non-empty.*/
|
||||||
if (((cr3 & USART_CR3_RXFTIE) != 0U) &&
|
if ((isr & USART_ISR_RXFT) != 0U) {
|
||||||
(isr & USART_ISR_RXFT) != 0U) {
|
|
||||||
|
|
||||||
/* Called once then the interrupt source is disabled.*/
|
#if SIO_USE_SYNCHRONIZATION
|
||||||
u->CR3 = cr3 & ~USART_CR3_RXFTIE;
|
/* The idle flag is forcibly cleared when an RX data event is
|
||||||
|
detected.*/
|
||||||
|
u->ICR = USART_ISR_IDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
/* Interrupt source disabled.*/
|
||||||
__sio_callback_rx(siop);
|
cr3 &= ~USART_CR3_RXFTIE;
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_rx(siop, MSG_OK);
|
__sio_wakeup_rx(siop);
|
||||||
|
|
||||||
/* Values could have been changed by the callback, CR2 no more needed.*/
|
|
||||||
cr1 = u->CR1;
|
|
||||||
cr3 = u->CR3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TX FIFO is non-full.*/
|
/* TX FIFO is non-full.*/
|
||||||
if (((cr3 & USART_CR3_TXFTIE) != 0U) &&
|
if ((isr & USART_ISR_TXFT) != 0U) {
|
||||||
(isr & USART_ISR_TXFT) != 0U) {
|
|
||||||
|
|
||||||
/* Called once then the interrupt is disabled.*/
|
/* Interrupt source disabled.*/
|
||||||
u->CR3 = cr3 & ~USART_CR3_TXFTIE;
|
cr3 &= ~USART_CR3_TXFTIE;
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
|
||||||
__sio_callback_tx(siop);
|
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_tx(siop, MSG_OK);
|
__sio_wakeup_tx(siop);
|
||||||
|
|
||||||
/* 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.*/
|
/* Physical transmission end.*/
|
||||||
if (((cr1 & USART_CR1_TCIE) != 0U) &&
|
if ((isr & USART_ISR_TC) != 0U) {
|
||||||
(isr & USART_ISR_TC) != 0U) {
|
|
||||||
|
|
||||||
/* Called once then the interrupt is disabled.*/
|
/* Interrupt source disabled.*/
|
||||||
u->CR1 = cr1 & ~USART_CR1_TCIE;
|
cr1 &= ~USART_CR1_TCIE;
|
||||||
|
|
||||||
/* The callback is invoked if defined.*/
|
|
||||||
__sio_callback_tx_end(siop);
|
|
||||||
|
|
||||||
/* Waiting thread woken, if any.*/
|
/* Waiting thread woken, if any.*/
|
||||||
__sio_wakeup_txend(siop, MSG_OK);
|
__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);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
osalDbgAssert(false, "spurious interrupt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,13 @@
|
||||||
/* Driver constants. */
|
/* 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. */
|
/* Driver pre-compile time settings. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -299,11 +306,6 @@
|
||||||
/* Driver macros. */
|
/* 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.
|
* @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) \
|
#define sio_lld_is_rx_empty(siop) \
|
||||||
(bool)(((siop)->usart->ISR & USART_ISR_RXNE_RXFNE) == 0U)
|
(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.
|
* @brief Determines the state of the TX FIFO.
|
||||||
*
|
*
|
||||||
|
@ -423,7 +453,9 @@ extern "C" {
|
||||||
void sio_lld_stop(SIODriver *siop);
|
void sio_lld_stop(SIODriver *siop);
|
||||||
void sio_lld_start_operation(SIODriver *siop);
|
void sio_lld_start_operation(SIODriver *siop);
|
||||||
void sio_lld_stop_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_read(SIODriver *siop, uint8_t *buffer, size_t n);
|
||||||
size_t sio_lld_write(SIODriver *siop, const 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);
|
msg_t sio_lld_get(SIODriver *siop);
|
||||||
|
|
|
@ -39,11 +39,7 @@
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
static const SIOOperation default_operation = {
|
static const SIOOperation default_operation = {
|
||||||
.rx_cb = NULL,
|
.cb = NULL
|
||||||
.rx_idle_cb = NULL,
|
|
||||||
.tx_cb = NULL,
|
|
||||||
.tx_end_cb = NULL,
|
|
||||||
.rx_evt_cb = NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -62,7 +58,7 @@ static size_t sync_write(void *ip, const uint8_t *bp, size_t n,
|
||||||
msg_t msg;
|
msg_t msg;
|
||||||
|
|
||||||
msg = sioSynchronizeTX(siop, timeout);
|
msg = sioSynchronizeTX(siop, timeout);
|
||||||
if (msg < MSG_OK) {
|
if (msg != MSG_OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +80,7 @@ static size_t sync_read(void *ip, uint8_t *bp, size_t n,
|
||||||
msg_t msg;
|
msg_t msg;
|
||||||
|
|
||||||
msg = sioSynchronizeRX(siop, timeout);
|
msg = sioSynchronizeRX(siop, timeout);
|
||||||
if (msg < MSG_OK) {
|
if (msg != MSG_OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,9 +222,14 @@ void sioObjectInit(SIODriver *siop) {
|
||||||
|
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
#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
|
#endif
|
||||||
siop->state = SIO_STOP;
|
siop->state = SIO_STOP;
|
||||||
siop->config = NULL;
|
siop->config = NULL;
|
||||||
|
siop->enabled = (sioflags_t)0;
|
||||||
|
|
||||||
/* Optional, user-defined initializer.*/
|
/* Optional, user-defined initializer.*/
|
||||||
#if defined(SIO_DRIVER_EXT_INIT_HOOK)
|
#if defined(SIO_DRIVER_EXT_INIT_HOOK)
|
||||||
|
@ -324,6 +325,13 @@ void sioStartOperation(SIODriver *siop, const SIOOperation *operation) {
|
||||||
if (siop->state == SIO_READY) {
|
if (siop->state == SIO_READY) {
|
||||||
sio_lld_start_operation(siop);
|
sio_lld_start_operation(siop);
|
||||||
siop->state = SIO_ACTIVE;
|
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();
|
osalSysUnlock();
|
||||||
|
@ -349,6 +357,7 @@ void sioStopOperation(SIODriver *siop) {
|
||||||
#if SIO_USE_SYNCHRONIZATION == TRUE
|
#if SIO_USE_SYNCHRONIZATION == TRUE
|
||||||
/* Informing waiting threads, if any.*/
|
/* Informing waiting threads, if any.*/
|
||||||
osalThreadResumeI(&siop->sync_rx, MSG_RESET);
|
osalThreadResumeI(&siop->sync_rx, MSG_RESET);
|
||||||
|
osalThreadResumeI(&siop->sync_rxidle, MSG_RESET);
|
||||||
osalThreadResumeI(&siop->sync_tx, MSG_RESET);
|
osalThreadResumeI(&siop->sync_tx, MSG_RESET);
|
||||||
osalThreadResumeI(&siop->sync_txend, MSG_RESET);
|
osalThreadResumeI(&siop->sync_txend, MSG_RESET);
|
||||||
#endif
|
#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
|
* @param[in] siop pointer to the @p SIODriver object
|
||||||
* @return The pending event flags.
|
* @return The pending event flags.
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
sio_events_mask_t sioGetAndClearEvents(SIODriver *siop) {
|
sioevents_t sioGetAndClearEvents(SIODriver *siop) {
|
||||||
sio_events_mask_t evtmask;
|
sioevents_t events;
|
||||||
|
|
||||||
osalDbgCheck(siop != NULL);
|
osalDbgCheck(siop != NULL);
|
||||||
|
|
||||||
osalSysLock();
|
osalSysLock();
|
||||||
|
|
||||||
evtmask = sioGetAndClearEventsI(siop);
|
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||||
|
|
||||||
|
events = sioGetAndClearEventsI(siop);
|
||||||
|
|
||||||
osalSysUnlock();
|
osalSysUnlock();
|
||||||
|
|
||||||
return evtmask;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -404,6 +502,8 @@ size_t sioAsyncRead(SIODriver *siop, uint8_t *buffer, size_t n) {
|
||||||
|
|
||||||
osalSysLock();
|
osalSysLock();
|
||||||
|
|
||||||
|
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||||
|
|
||||||
n = sioAsyncReadI(siop, buffer, n);
|
n = sioAsyncReadI(siop, buffer, n);
|
||||||
|
|
||||||
osalSysUnlock();
|
osalSysUnlock();
|
||||||
|
@ -431,6 +531,8 @@ size_t sioAsyncWrite(SIODriver *siop, const uint8_t *buffer, size_t n) {
|
||||||
|
|
||||||
osalSysLock();
|
osalSysLock();
|
||||||
|
|
||||||
|
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||||
|
|
||||||
n = sioAsyncWriteI(siop, buffer, n);
|
n = sioAsyncWriteI(siop, buffer, n);
|
||||||
|
|
||||||
osalSysUnlock();
|
osalSysUnlock();
|
||||||
|
@ -450,14 +552,13 @@ size_t sioAsyncWrite(SIODriver *siop, const uint8_t *buffer, size_t n) {
|
||||||
* @return The synchronization result.
|
* @return The synchronization result.
|
||||||
* @retval MSG_OK if there is data in the RX FIFO.
|
* @retval MSG_OK if there is data in the RX FIFO.
|
||||||
* @retval MSG_TIMEOUT if synchronization timed out.
|
* @retval MSG_TIMEOUT if synchronization timed out.
|
||||||
* @retval MSG_RESET operation has been stopped while waiting.
|
* @retval MSG_RESET it the operation has been stopped while waiting.
|
||||||
* @retval SIO_MSG_IDLE if RX line went idle.
|
|
||||||
* @retval SIO_MSG_ERRORS if RX errors occurred during wait.
|
* @retval SIO_MSG_ERRORS if RX errors occurred during wait.
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout) {
|
msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout) {
|
||||||
msg_t msg = MSG_OK;
|
msg_t msg;
|
||||||
|
|
||||||
osalDbgCheck(siop != NULL);
|
osalDbgCheck(siop != NULL);
|
||||||
|
|
||||||
|
@ -465,13 +566,65 @@ msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout) {
|
||||||
|
|
||||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
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
|
/*lint -save -e506 -e681 [2.1] Silencing this error because it is
|
||||||
tested with a template implementation of sio_lld_is_rx_empty() which
|
tested with a template implementation of sio_lld_is_rx_empty() which
|
||||||
is constant.*/
|
is constant.*/
|
||||||
while (sio_lld_is_rx_empty(siop)) {
|
while (sioIsRXEmptyX(siop)) {
|
||||||
/*lint -restore*/
|
/*lint -restore*/
|
||||||
msg = osalThreadSuspendTimeoutS(&siop->sync_rx, timeout);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,7 +650,7 @@ msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout) {
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
msg_t sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout) {
|
msg_t sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout) {
|
||||||
msg_t msg = MSG_OK;
|
msg_t msg;
|
||||||
|
|
||||||
osalDbgCheck(siop != NULL);
|
osalDbgCheck(siop != NULL);
|
||||||
|
|
||||||
|
@ -505,13 +658,14 @@ msg_t sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout) {
|
||||||
|
|
||||||
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state");
|
||||||
|
|
||||||
|
msg = MSG_OK;
|
||||||
/*lint -save -e506 -e681 [2.1] Silencing this error because it is
|
/*lint -save -e506 -e681 [2.1] Silencing this error because it is
|
||||||
tested with a template implementation of sio_lld_is_tx_full() which
|
tested with a template implementation of sio_lld_is_tx_full() which
|
||||||
is constant.*/
|
is constant.*/
|
||||||
while (sio_lld_is_tx_full(siop)) {
|
while (sioIsTXFullX(siop)) {
|
||||||
/*lint -restore*/
|
/*lint -restore*/
|
||||||
msg = osalThreadSuspendTimeoutS(&siop->sync_tx, timeout);
|
msg = osalThreadSuspendTimeoutS(&siop->sync_tx, timeout);
|
||||||
if (msg < MSG_OK) {
|
if (msg != MSG_OK) {
|
||||||
break;
|
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
|
/*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()
|
it is tested with a template implementation of sio_lld_is_tx_ongoing()
|
||||||
which is constant.*/
|
which is constant.*/
|
||||||
if (sio_lld_is_tx_ongoing(siop)) {
|
if (sioIsTXOngoingX(siop)) {
|
||||||
/*lint -restore*/
|
/*lint -restore*/
|
||||||
msg = osalThreadSuspendTimeoutS(&siop->sync_txend, timeout);
|
msg = osalThreadSuspendTimeoutS(&siop->sync_txend, timeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,8 +74,7 @@
|
||||||
*****************************************************************************
|
*****************************************************************************
|
||||||
|
|
||||||
*** Next ***
|
*** Next ***
|
||||||
- NEW: Made sioStopOperation() and sioStartOperation() call possible in
|
- NEW: Reworked HAL SIO driver.
|
||||||
both SIO_READY and SIO_ACTIVE states.
|
|
||||||
- NEW: Non-proprietary LLVM build support.
|
- NEW: Non-proprietary LLVM build support.
|
||||||
- NEW: Added palReadGroupLatch() to PAL driver.
|
- NEW: Added palReadGroupLatch() to PAL driver.
|
||||||
- NEW: Added a Posix-favored shell named "msh" (Mini Shell). The shell is able
|
- NEW: Added a Posix-favored shell named "msh" (Mini Shell). The shell is able
|
||||||
|
|
Loading…
Reference in New Issue