From c8beefbf850eb191c152be6ecd3a2c53a8f9ea17 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Mar 2016 14:40:47 +0100 Subject: [PATCH] wait for transmitter to be done before receiving At higher speeds, it seems we are turning off the transmitter before we are enabling the receiver. Unfortunately the TXEN bit in the uart mode register is read-only, so we don't really know if the transmitter is enabled or not. It seems we can simply keep transmitter + reciver running at the same time, and use the TXEMPTY bit as reliable means to determine if we're busy transmtting. --- firmware/src_simtrace/mode_cardemu.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/firmware/src_simtrace/mode_cardemu.c b/firmware/src_simtrace/mode_cardemu.c index c0127017..098e0d67 100644 --- a/firmware/src_simtrace/mode_cardemu.c +++ b/firmware/src_simtrace/mode_cardemu.c @@ -84,6 +84,19 @@ static Usart *get_usart_by_chan(uint8_t uart_chan) * Call-Backs from card_emu.c ***********************************************************************/ +static void wait_tx_idle(Usart *usart) +{ + int i = 1; + + /* wait until last char has been fully transmitted */ + while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) { + if (!(i%1000000)) { + TRACE_ERROR("s: %x \r\n", usart->US_CSR); + } + i++; + } +} + /* call-back from card_emu.c to enable/disable transmit and/or receive */ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx) { @@ -91,14 +104,19 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx) switch (rxtx) { case ENABLE_TX: USART_DisableIt(usart, ~US_IER_TXRDY); - USART_SetReceiverEnabled(usart, 0); + /* as irritating as it is, we actually want to keep the + * receiver enabled during transmit */ + USART_SetReceiverEnabled(usart, 1); usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; USART_EnableIt(usart, US_IER_TXRDY); USART_SetTransmitterEnabled(usart, 1); break; case ENABLE_RX: USART_DisableIt(usart, ~US_IER_RXRDY); - USART_SetTransmitterEnabled(usart, 0); + /* as irritating as it is, we actually want to keep the + * transmitter enabled during receive */ + USART_SetTransmitterEnabled(usart, 1); + wait_tx_idle(usart); usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; USART_EnableIt(usart, US_IER_RXRDY); USART_SetReceiverEnabled(usart, 1);