In a serial RS-232/UART transmission from a µC to a PC, I am having problems with data loss (FIFO overruns) after wake-up of the PC.
"PC" is the receiver, a ThinkPad T400 laptop running "Ubuntu 20.04.5 LTS".
"µC" is the sender, a bare-metal micro-controller (AVR ATmega168) connected via MAX232* to the PC.
The communication works fine after booting or re-starting the PC, but when I am closing the lid of the laptop, wait a minute or so, and then waking it up, there is data loss that looks like FIFO overruns for messages that are sent after wake-up.
In order to monitor the serial line I am using picocom terminal program:
> picocom --baud 115200 --parity none --databits 8 --stopbits 1 /dev/ttyS0
The output of picocom is as follows:
picocom v3.1
port is : /dev/ttyS0
flowcontrol : none
baudrate is : 115200
parity is : none
databits are : 8
stopbits are : 1
escape is : C-a
local echo is : no
noinit is : no
noreset is : no
hangup is : no
nolock is : no
send_cmd is : sz -vv
receive_cmd is : rz -vv -E
imap is :
omap is :
emap is : crcrlf,delbs,
logfile is : none
initstring : none
exit_after is : not set
exit is : no
Type [C-a] [C-h] to see available commands
Terminal ready
8|123456789|123456789|
9|123456789|123456789|
10|123456789|123456789|
11|123456789|123456789|
12|123456789|123456789|
13|123456789|123456789|
76|123456789|1
77|123456789|1
78|123456789|1
79|123456789|1|
80|123456789|1
81|123456789|1
82|123456789|1
83|123456789|1
84|123456789|1
85|123456789|1
...
The µC is sending one message each second, the respective part of the C program is:
printf ("\n%d|123456789|123456789|", ++count);
The PC was inactive for count in 14...75. Messages up to count = 13 are complete. PC woke up at count = 76, and after wake-up messages are truncated to 16 bytes.
> sudo cat /proc/tty/driver/serial
serinfo:1.0 driver revision:
0: uart:16550A port:000003F8 irq:4 tx:0 rx:1389 oe:15
The oe counts the overrun errors. After wake-up, the messages are truncated after 16 bytes (newline takes 2 bytes).
Question: How can I work around this error? Is there a way to "restart" the serial port or the kernel module that is responsible for servicing the IRQs without restarting the PC?
What I have tried so far and what did not work:
- Use different terminal programs like
minicomorpyserial-minitermfrom PySerial. - Setting low latency flag as of
setserial /dev/ttyS0 low_latency. - Using smaller baud-rate like 9600.
- Closing and re-opening
picocom. - Running
stty -F /dev/ttyS0 sane.
Also there is a perceivable jitter when the broken messages are displayed by the terminal program, even though the µC is sending them at exact 1-second intervals.
As far as I understand, the 16550A has a 16-byte FIFO, and it will trigger an IRQ when the FIFO is filled up to a specific portion like 1 or 4 or 14 bytes. It seems the PC is no more servicing the IRQ 4 after wake-up, or the 16550A is no more raising IRQs?
Some more data from setserial and stty:
> setserial /dev/ttyS0 -a
/dev/ttyS0, Line 0, UART: 16550A, Port: 0x03f8, IRQ: 4
Baud_base: 115200, close_delay: 50, divisor: 0
closing_wait: 3000
Flags: spd_normal skip_test low_latency
> stty -F /dev/ttyS0 -a
speed 115200 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany
-imaxbel -iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
-flusho -extproc
What I also tried is to use Xon/Xoff software flow-control, but the PC won't send ^S. Which is presumably because linux's serial buffer is several kBytes in size, and that buffer is never anywhere near to full. And if the PC is not working correct to read out the FIFO in time, it would also not be able to send ^S in time.
Hardware flow-control is not an option, because the µC board just has TxD and RxD connected.