tabemann / zeptoforth

A not-so-small Forth for Cortex-M

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RP Pico : flush-uart returns when characters are still being transmitted!

robzed opened this issue · comments

flush-uart appears to flush all the characters out of the system, but it only deals with the ZeptoForth buffer and doesn't flush the hardware FIFO. This means that it returns when up to 32 characters are being transmitted - the UART isn't fully flushed.

\ Flush the transmit buffer for a UART
: flush-uart ( uart -- )
dup validate-uart
0= if
do-flush-console
else
[: uart1-tx-empty? ;] wait
then
;

This function should wait for the FIFO, and ideally check the transmit shift register is empty.

Instead of modifying flush-uart, maybe uart1-tx-empty should be modified from:
\ Get whether the tx buffer is empty
: uart1-tx-empty? ( -- f )
uart1-tx-read-index c@ uart1-tx-write-index c@ =
;

and maybe become (this is NOT tested!):

\ Get whether the tx buffer is empty
: uart1-tx-empty? ( -- f )
    uart1-tx-read-index c@ uart1-tx-write-index c@ = UART1_UARTFR_TXFE@ 0<> and
;

From the RP2040 datasheet (page 430) UART: UARTFR Register Offset: 0x018
7 TXFE Transmit FIFO empty. The meaning of this bit depends on the state of the FEN bit in the Line Control Register, UARTLCR_H. If the FIFO is disabled, this bit is set when the transmit holding register is empty. If the FIFO is enabled, the TXFE bit is set when the transmit FIFO is empty. This bit does not indicate if there is data in the transmit shift register.

4 bit constant UART_FIFO \ Set the UART FIFO to be enabled

Since we enable the hardware FIFO, I also wonder about the transmit holding register and the transmit shift register.

Section 4.2.2.4. Transmit FIFO The transmit FIFO is an 8-bit wide, 32 location deep, FIFO memory buffer. CPU data written across the APB interface is stored in the FIFO until read out by the transmit logic. You can disable the transmit FIFO to act like a one-byte holding register.

Section 4.2.3.2.5. Disabling the FIFOs Additionally, you can disable the FIFOs. In this case, the transmit and receive sides of the UART have 1-byte holding registers (the bottom entry of the FIFOs). The overrun bit is set when a word has been received, and the previous one was not yet read. In this implementation, the FIFOs are not physically disabled, but the flags are manipulated to give the illusion of a 1-byte register. When the FIFOs are disabled, a write to the data register bypasses the holding register unless the transmit shift register is already in use.

Sounds like with FIFO there is no separate transmit holding register – just the FIFO acts as 32 long or 1 long.

I don’t see an easy method to check if transmission shift register is empty. This is a problem for half-duplex systems, like RS485 or Radio interfaces. This should be explicitly mentioned in the documents.

The workarounds are:

  • Transmit an extra character where permissible (RF systems often have postamble characters)
  • Wait for (1/baud rate) * number of bits (=data+start+stop).

Thanks for bringing this up - I had never looked at this closely since I have never really had a need to flush the UART TX FIFO's themselves. I will incorporate your change to check UART1_UARTFR_TXFE@, but in flush-uart (and the corresponding code for UART0), as the word you proposed to change is specific to the zeptoforth UART ring buffer and probably should not be changed by itself. I will also make changes to the other platforms in the same fashion. Note, however, about the TX shift register that will be up to the user to put in a delay for, for the reason you give.

I have made a change to flush-console, when the console is a UART, and uart::flush-uart, such that they guarantee for all supported platforms that the UART's transmit FIFO is empty before returning. However, they do not guarantee that any UART transmit shift register is empty, so if this matters to you I would recommend delaying for the time necessary to transmit 10 bits at the given baud rate. You can find a new release containing these changes at https://github.com/tabemann/zeptoforth/releases/tag/v0.61.2.