Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ static const SerialConfig default_config =
USART_CR2_STOP1_BITS,
0,
NULL,
NULL
NULL,
false
};

/*===========================================================================*/
Expand Down Expand Up @@ -132,8 +133,8 @@ static void usart_init(SerialDriver *sdp, const SerialConfig *config) {
u->CR2 = config->cr2 | USART_CR2_LBDIE;
u->CR3 = config->cr3 | USART_CR3_EIE;
u->CR1 = config->cr1 | USART_CR1_UE | USART_CR1_PEIE |
USART_CR1_RXNEIE | USART_CR1_TE |
USART_CR1_RE;
(config->external_rx_buffer ? 0U : USART_CR1_RXNEIE) |
USART_CR1_TE | USART_CR1_RE;
u->SR = 0;
(void)u->SR; /* SR reset step 1.*/
(void)u->DR; /* SR reset step 2.*/
Expand Down Expand Up @@ -752,6 +753,16 @@ void sd_lld_serve_interrupt(SerialDriver *sdp) {
/* Error condition detection.*/
if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE))
set_error(sdp, sr);
if (sdp->config->external_rx_buffer) {
/* Receive path is external: DR is read only to clear an error flag,
never to take data. A pending byte with no error is left for the
external path.*/
if ((sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) == 0U)
break;
(void)u->DR;
sr = u->SR;
continue;
}
b = (uint8_t)u->DR & sdp->rxmask;
if (sr & USART_SR_RXNE)
sdIncomingDataI(sdp, b);
Expand Down
8 changes: 8 additions & 0 deletions os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,14 @@ typedef struct hal_serial_config {
* @pointer to ctx
*/
void* ctx;
/**
* @brief Receive data is moved by an external path.
* @details When true the driver does not enable RXNEIE and its interrupt
* handler reads the data register only to clear an error flag,
* never to take data, so bytes cannot be diverted into the
* (unused) input queue.
*/
bool external_rx_buffer;
} SerialConfig;

/**
Expand Down
22 changes: 14 additions & 8 deletions os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ static const SerialConfig default_config =
USART_CR2_STOP1_BITS,
0,
NULL,
NULL
NULL,
false
};

#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
Expand Down Expand Up @@ -269,8 +270,8 @@ static void usart_init(SerialDriver *sdp,
u->CR2 = config->cr2 | USART_CR2_LBDIE;
u->CR3 = config->cr3 | USART_CR3_EIE;
u->CR1 = config->cr1 | USART_CR1_UE | USART_CR1_PEIE |
USART_CR1_RXNEIE | USART_CR1_TE |
USART_CR1_RE;
(config->external_rx_buffer ? 0U : USART_CR1_RXNEIE) |
USART_CR1_TE | USART_CR1_RE;
u->ICR = 0xFFFFFFFFU;

/* Deciding mask to be applied on the data register on receive, this is
Expand Down Expand Up @@ -870,12 +871,17 @@ void sd_lld_serve_interrupt(SerialDriver *sdp) {
an extra interrupt to serve.
2) FIFO mode is enabled on devices that support it, we need to empty
the FIFO.*/
while (isr & USART_ISR_RXNE) {
osalSysLockFromISR();
sdIncomingDataI(sdp, (uint8_t)u->RDR & sdp->rxmask);
osalSysUnlockFromISR();
/* Skipped entirely when the receive path is external: an IDLE or TX
interrupt that finds a byte the external path has not taken yet must not
divert it into the input queue.*/
if (!sdp->config->external_rx_buffer) {
while (isr & USART_ISR_RXNE) {
osalSysLockFromISR();
sdIncomingDataI(sdp, (uint8_t)u->RDR & sdp->rxmask);
osalSysUnlockFromISR();

isr = u->ISR;
isr = u->ISR;
}
}

/* Caching CR1.*/
Expand Down
7 changes: 7 additions & 0 deletions os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,13 @@ typedef struct hal_serial_config {
* @pointer to ctx
*/
void* ctx;
/**
* @brief Receive data is moved by an external path.
* @details When true the driver does not enable RXNEIE and its interrupt
* handler never reads the data register to take data, so bytes
* cannot be diverted into the (unused) input queue.
*/
bool external_rx_buffer;

} SerialConfig;

Expand Down
24 changes: 15 additions & 9 deletions os/hal/ports/STM32/LLD/USARTv3/hal_serial_lld.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ static const SerialConfig default_config =
USART_CR2_STOP1_BITS,
0,
NULL,
NULL
NULL,
false
};

#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
Expand Down Expand Up @@ -295,8 +296,8 @@ static void usart_init(SerialDriver *sdp,
u->CR2 = config->cr2 | USART_CR2_LBDIE;
u->CR3 = config->cr3 | USART_CR3_EIE;
u->CR1 = config->cr1 | USART_CR1_UE | USART_CR1_PEIE |
USART_CR1_RXNEIE | USART_CR1_TE |
USART_CR1_RE;
(config->external_rx_buffer ? 0U : USART_CR1_RXNEIE) |
USART_CR1_TE | USART_CR1_RE;
u->ICR = 0xFFFFFFFFU;

/* Deciding mask to be applied on the data register on receive, this is
Expand Down Expand Up @@ -997,13 +998,18 @@ void sd_lld_serve_interrupt(SerialDriver *sdp) {
1) Another byte arrived after removing the previous one, this would cause
an extra interrupt to serve.
2) FIFO mode is enabled on devices that support it, we need to empty
the FIFO.*/
while (isr & USART_ISR_RXNE) {
osalSysLockFromISR();
sdIncomingDataI(sdp, (uint8_t)u->RDR & sdp->rxmask);
osalSysUnlockFromISR();
the FIFO.
Skipped entirely when the receive path is external: an IDLE or TX
interrupt that finds a byte the external path has not taken yet must not
divert it into the input queue.*/
if (!sdp->config->external_rx_buffer) {
while (isr & USART_ISR_RXNE) {
osalSysLockFromISR();
sdIncomingDataI(sdp, (uint8_t)u->RDR & sdp->rxmask);
osalSysUnlockFromISR();

isr = u->ISR;
isr = u->ISR;
}
}

/* Caching CR1.*/
Expand Down
7 changes: 7 additions & 0 deletions os/hal/ports/STM32/LLD/USARTv3/hal_serial_lld.h
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,13 @@ typedef struct hal_serial_config {
* @pointer to ctx
*/
void* ctx;
/**
* @brief Receive data is moved by an external path.
* @details When true the driver does not enable RXNEIE and its interrupt
* handler never reads the data register to take data, so bytes
* cannot be diverted into the (unused) input queue.
*/
bool external_rx_buffer;
} SerialConfig;

/**
Expand Down