UART FIFO issue

Ceiliedgh
Hi,

I'm writing a small bootloader (as a way to familiarize myself with
embedded development).

Given the following code:

void uart_test()
{
    const char * sometext = "Some very long buffer that is longer than 64
characters and will not fit in UART FIFO queue !\r\n";
    uint32_t text_len = strlen(sometext);

    // Set up port (8 data bits, 1 stop bit, no parity)
    uint32_t line_ctrl = uart_port::DATA_8_BITS | (uart_port::STOP_1_BIT <<
2);
    write_register32(uart_port::REG_BASE + uart_port::REG_LINE_CTRL,
line_ctrl);

    // Polled TX & RX
    uint32_t chan_ctrl = (uart_port::TXRX_MODE_POLL << 2) |
uart_port::TXRX_MODE_POLL;
    write_register32(uart_port::REG_BASE + uart_port::REG_CHANNEL_CTRL,
chan_ctrl);

    // PCLK = 50.625 Mhz, 57600 Baud --> within 1.69% error tolerance
    write_register32(uart_port::REG_BASE + uart_port::REG_DIVISOR, 54);

    // Enable & reset FIFO
    uint32_t fifo_ctrl = uart_port::FIFO_ENABLE | uart_port::FIFO_RX_RESET
| uart_port::FIFO_TX_RESET;
    write_register32(uart_port::REG_BASE + uart_port::REG_FIFO_CTRL,
fifo_ctrl);

    /**
     * Wait until the FIFO buffers are initialized (RX and TX flags will be
reset to 0)
     */
    uint32_t fifo_reg;
    do
    {
        fifo_reg = read_register32(uart_port::REG_BASE +
uart_port::REG_FIFO_CTRL);
    } while (fifo_reg & (uart_port::FIFO_RX_RESET |
uart_port::FIFO_TX_RESET));

    // Send the same line of text forever
    for (;;)
    {
        uint32_t sent = 0;
        // Send while there's some data left
        while (sent != text_len)
        {
            uint32_t fifo_status = read_register32(uart_port::REG_BASE +
uart_port::REG_FIFO_STATUS);
            // Determine amount of free bytes in FIFO buffer
            uint32_t tx_free = 64 - ((fifo_reg >> 8) & 0x3F);

            // Only send if the fifo is not full
            if (tx_free)
            {
                // Determine the amount of bytes to write the fifo
                // min(fifo_free_bytes, buf_remaining_bytes)
                uint32_t txbytes = std::min(tx_free, (text_len - sent));
                
                for (uint32_t i = 0; i < txbytes; i++)
                    write_register8(uart_port::REG_BASE +
uart_port::REG_TX, (uint8_t)sometext[sent++]);
            }
        }
    }
}

My problem is that when this code is run, garbage appears on the port. (To
be more precise, the characters that are written to the FIFO do appear, but
in totally random order.)

If I add the following line of code to the beginning of the while loop,
everything appears correctly:
while (!(read_register32(uart_port::REG_BASE + uart_port::REG_TXRX_STATUS)
& uart_port::TXRX_TRANSMITTER_EMPTY));

It seems that if you write to the TX FIFO when the transmit buffer is not
empty, it will corrupt the FIFO buffer.
(My understanding is that the transmit buffer (not the FIFO one) is a one
byte buffer that shifts data out bit-by-bit. The busy loop will only halt
when the FIFO TX buffer is empty and the transmit buffer sent its last bit
as well.)

My question would be, is it normal that the FIFO TX buffer cannot be
written to when there's data in the transmit buffer?
I didn't find anything in the S3C2440 manual that says if this is allowed
behavior or not.

Hope i made sense :(

Thanks in advance!