Electronic – ATMEGA UART transmition with flow control

atmegaavrflow controlmicrocontrolleruart

Background

I'm using an ATmega328P to send data to another device at a high baud rate (230400). The device I'm sending data to supports flow control and raises the RTS signal when it needs to hold the transmission.
The problem is that the device is expecting me to stop the transmission immediately after RTS is asserted.

The ATmega328P has a transmission buffer (UDR) and a shift register from which data is sent to the TX line. Since the ATmega328P does not support flow control in hardware, I'm implementing it in software. Before sending (before writing to UDR) I'm checking RTS and waiting until it goes low, but apparently this is not enough because data in the transmit buffer and shift register is still being sent and a full byte could still be sent after RTS is asserted when the ATmega328P flushes its buffers.

Apparently, disabling the transmitter when RTS is asserted (setting the TXEN to zero) does not help since it will not become effective until ongoing and pending transmissions are completed, according to the documentation section 19.6.5.

A workaround could be to wait until Transmit Complete (TXC) before sending each byte, but this would impact the data rate since I'm not sending the byte stream back-to-back even when RTS is not asserted (I'm starting to send a new byte only after the previous one was completely sent).

My question is:

With the ATmega328P, is there a way to support RTS flow control in the transmitter while still enjoying the pipelining provided by the transmit buffer and shift register?

Best Answer

Sounds like you have two basic problems, a badly designed external device and that you are trying to make inappropriate hardware do a job it is not intended for.

First, does this other device really require absolutely no more bytes after RTS is asserted? That would be very unusual. It is very common for transmitters to empty a small buffer before obeying RTS, so unless the other engineer didn't know what he was doing the device should be able to tolerate a few more bytes. Maybe it can't handle the "full featured" case of 16 more bytes, but not allowing 2-4 more bytes is just bad design.

Second, given that you need to stop transmitting faster than the size of the output buffer, you picked the wrong hardware. I am not familiar with that line of micros, but surely this is in the datasheet. I see three options:

  1. Get a micro that does have a RTS input and that stops on the next byte boundary when it is asserted. Most UARTs in micros don't have this extra feature, but there are certainly some that do. I know some PIC 33F can do this because I've chosen them in part for this feature. Look around the Atmel product line. They may have a few micros with this feature too.

  2. Use a external UART that does hardware flow control on the byte level.

  3. Use the existing UART with more software intervention. You won't be able to use the internal buffer, and will have to wait until one character is sent, check RTS, then write the next character to the UART. This will be facilitated if the UART can interrupt when empty, not just when there is room in the output buffer.

None of these tradeoffs may be what you want, but that's the cost of bad architecture. Fix it next rev, or respin now if it's really important. The world doesn't always have a magic answer just because your boss wants it now or because you painted yourself into a corner.