UART/Timing and trouble/Asking the other side to wait
Lesson 10 of 12 · in 3D and VR

Asking the other side to wait

A UART receiver cannot ask for a byte to be sent again, but it can ask the sender to wait. Hardware flow control does it with two extra wires, software flow control with two ordinary bytes, and many links use neither.

Lonely BinaryUpdated 2026-10-015 min readNo board required

View it in VR

Lesson 10 of the UART course opens in a VR headset, on a table in front of you, and a voice starts three seconds after you arrive. Type this short address into the browser on a headset such as Meta Quest or Apple Vision Pro, and press Enter VR. No headset? Press Start the lesson: the same lesson, full screen.

learn.lonelybinary.com/vr/uart/10

A receiver that cannot keep up loses bytes, and nothing in a UART frame lets it ask for them again. The only cure is to stop the sender before the receive buffer is full. That needs a second channel from the receiver back to the sender, and there are two ways to make one.

Two extra wires

Hardware flow control adds RTS and CTS. Each end's RTS output goes to the other end's CTS input, crossed in the same way as TX and RX. RTS is the receiver saying whether it has room. CTS is the line the sender looks at before it sends. The names come from RS-232, but on a modern link RTS means "I am ready to receive".

Which voltage means stop is not worth memorising: the driver sets it, and the ESP32 and ESP32-S3 manuals word it in opposite ways. What matters is the direction. The receiver drives the line and the sender reads it, and the sender is only held between bytes: it finishes the byte it is sending.

That last point decides when the receiver has to ask. It cannot wait until the buffer is full, because a byte or two are already on their way. The ESP32 asks when its receive FIFO passes a threshold you set, which is below the top for exactly this reason. On the bench the tray holds eight bytes and the receiver asks at five.

Two special bytes

Software flow control needs no extra wire. The receiver sends one byte back down its own TX line to say stop, XOFF, and another to say go, XON. They are the ASCII control codes DC3 and DC1, which are 0x13 and 0x11, and on the ESP32-S3 both can be changed.

The stop is itself a byte. It has to be sent and read before the sender reacts, and meanwhile more bytes arrive, so XON and XOFF need a little more headroom than the wires do.

There is a worse cost. The receiver cannot tell data from control, so a binary stream that happens to contain 0x13 stops the sender, and one that contains 0x11 starts it again. That is why software flow control suits text and not files.

Both ends, or neither

Flow control is a setting at each end, and the two must agree. A sender that obeys CTS, wired to a receiver that never drives it, reads a line that holds whatever level it floats at, so it may never stop or never go. A sender that ignores the wires keeps sending to a receiver whose lamp says wait, and the tray overflows anyway. The bench's last button shows exactly that.

Many links use neither. A three-wire link at a speed the receiver can always keep up with needs no flow control.

What it costs

Flow control does not make the receiver faster. It makes the sender slower, so a burst takes longer. If the receiver is too slow on average, flow control turns loss into waiting.

Common mistakes

  • Wiring RTS to RTS. The wires cross, like TX and RX: each RTS goes to the other end's CTS.
  • Turning flow control on at one end only. Nothing complains. The link either never stops, or stops and never goes.
  • Using XON and XOFF for binary data. Any 0x13 in the data stops the sender. Use the wires, or leave flow control off and slow the sender down.

Edit this page — content/fundamentals/uart/flow-control.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Fundamentals on the forum →