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 minicom or pyserial-miniterm from 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.
Related
I am attempting to set up a basic pipe that'll transfer all data written to ttyS3 to ttyUSB0. I found a few solutions to the problem such as this, but they don't seem to help much. The issue seems to be that anytime I do anything with ttyS3, I get this:
stty: /dev/ttyS3: Input/output error
Doing ls -l /dev/ttyS* and the same for /dev/ttyUSB* I get the following:
root#arm-64:~# ls -l /dev/ttyS*
crw-rw---- 1 root dialout 4, 64 Feb 9 13:08 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 Feb 9 13:08 /dev/ttyS1
crw--w---- 1 root tty 4, 66 Feb 9 13:08 /dev/ttyS2
crw-rw---- 1 root dialout 4, 67 Feb 9 13:08 /dev/ttyS3
crw-rw---- 1 root dialout 4, 68 Feb 9 13:08 /dev/ttyS4
root#arm-64:~# ls -l /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 0 Feb 9 13:08 /dev/ttyUSB0
I've created the following script to do the job for me at startup. I changed the major/minor values to match that of USB0 after reading somewhere that this could work as a pipe. Although it does execute without throwing an Input/output error, it doesn't seem to work as intended.
#!/bin/bash
rm /dev/ttyS3
mknod -m 666 /dev/ttyS3 c 188 0
chown root.dialout /dev/ttyS3
chmod 666 /dev/ttyS3
stty -F /dev/ttyUSB0 speed 115200 cs8
stty -F /dev/ttyS3 speed 115200 cs8
cat /dev/ttyS3 > /dev/ttyUSB0 &
I just need to create a basic pipe that'll take all data written to ttyS3 and pass it on to ttyUSB0. Although I don't think it's relevant, I'm running Armbian bullseye on a TV box (Tx3 Mini)
I just need to create a basic pipe that'll take all data written to ttyS3 and pass it on to ttyUSB0
Don't see a problem so long as each serial terminal is properly setup and functional/operational. Before you create the "pipe", did you verify that each serial terminal is operating properly?
On a SBC I have the console on a serial terminal, and established two more serial terminals using a SoC USART and a USB adapter:
# ls -l /dev/tty*S*
crw-rw---- 1 root dialout 246, 0 Jan 1 2012 /dev/ttyGS0
crw------- 1 root tty 4, 64 Jul 31 22:46 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 Jul 31 22:25 /dev/ttyS1
crw-rw---- 1 root dialout 188, 0 Jul 31 22:28 /dev/ttyUSB0
#
Note that the udev daemon created these device nodes, and no funny business (i.e. manual re-creating device nodes) was necessary to accomplish the "pipe".
To remove canonical processing, each serial terminal is put in raw mode and with matching baudrates:
# stty raw 115200 -F /dev/ttyUSB0
# stty raw 115200 -F /dev/ttyS1
A report of all termios settings:
# stty -aF /dev/ttyUSB0
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
#
# stty -aF /dev/ttyS1
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
#
Then when the command
# cat /dev/ttyS1 > /dev/ttyUSB0 &
is issued, whatever is typed on the remote terminal-emulator program connected to /dev/ttyS1 shows up on the remote terminal-emulator program connected to /dev/ttyUSB0.
This seems to behave like the desired "basic pipe that'll take all data written to ttyS? and pass it on to ttyUSB0".
Bottom line:
Unable to duplicate problems, and can create "pipe" of two serial links.
# uname -a
Linux sama5d2-xplained 5.4.81-linux4sam-2020.10 #1 Thu Jan 14 12:54:56 UTC 2021
armv7l armv7l armv7l GNU/Linux
#
The issue seems to be that anytime I do anything with ttyS3, I get this:
stty: /dev/ttyS3: Input/output error
... I'm running Armbian bullseye on a TV box (Tx3 Mini)
As previously mentioned, you need to verify that each serial terminal is operating properly.
Since a "TV box" doesn't really need five (!) serial terminals, you might be seeing/creating bogus device nodes that don't have any hardware to access.
Search the system log for the actual hardware that was initialized, e.g. 'dmesg | grep tty'. One of those UARTs might be used to interface to an IR receiver.
I am looking to send a 'reboot' command over the serial port to the PDU. What I have to do in the interactive mode is this:
#screen /dev/ttyS1
>reboot
>[Detach Screen]
#
If I want to automate this task in a script, I should be able to reboot the PDU with a single command from shell like this:
#echo "reboot" >/dev/ttyS1
However, it does not work ! I don't know why.... Would you be able to help me ?
The PDU manual request baud rate of 9600 which is not a default baud rate. I have tried following command to set the baud rate but still no lock:
stty -F /dev/ttyS1 speed 9600 cs8 -cstopb -parenb
These outputs does not change with or without screen:
# stty -a -F /dev/ttyS1
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^H; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 100; time = 2;
-parenb -parodd 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
Here is how we fixed this issue:
Config serial port with RAW setting:
stty -F /dev/ttyS1 speed 9600 cs8 -cstopb -parenb raw
Send Command using echo with \r:
echo -ne "reboot\r" > /dev/ttyS1
I believe that the above might include a typo. If the above doesn't work, try:
echo -ne "reboot\n\r" > /dev/ttyS1
I have a problem with tty (I am doing UART communication PC<->uC).
I send data to uC and its sends it back (echo).
I want to read and write to tty.
cat /dev/ttyUSB0 >output.txt & #redirect output to file and move to background
echo abcd > /dev/ttyUSB0 #write to tty
At the first run script works well. But if it is runned again, it skips characters, changes order etc. I have to unplug and plug usb (pl2303 Serial Port) to make the script work properly for one time.
I think it can be problem with synchronization or some buffers. Maybe there is a command to reset ttyUSB0 without unplugging it?
My uC sends data in 9600 8N1.
$ stty -F /dev/ttyUSB0 -a
speed 9600 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; flush = ^O; min = 1; time = 0;
-parenb -parodd 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
Thanks for help ;)
I've implemented CCNET protocol to communicate with CashCode bill acceptor from my software on Linux.
Initially I spent lots of time trying to figure out why the device does not respond to the commands I'm sending. Using trial-and-error method I found the solution to set the following options for the serial port:
stty -F /dev/ttyS0 9600 cs8 -cstopb -parenb clocal -crtscts -ixon -ixoff ignpar -icrnl -opost -isig -icanon -iexten -echo
It was working on the development machine and on two another testing machines (all of them had different motherboards). However, on the third testing machine (having yet another mobo) it seems that the device is not responding again.
It is, however, working on Windows with different software on the same machine.
Under "does not respond" I mean that nothing can be read from the serial port during 10-second timeout after sending the command. The whole code is tested and working on another motherboards.
The port itself is detected by the kernel correctly as stated in dmesg:
[ 1.099382] serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[ 1.127531] 00:0b: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
There are no warnings in dmesg regarding this serial port.
Any ideas on how to debug this issue?
The full output of "stty -F /dev/ttyS0":
speed 9600 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;
flush = ^O; min = 1; time = 0;
-parenb -parodd 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
Problem is solved.
This model of bill acceptor is working at 19200 baud.
Switching the port to 19200 solves the problem.
Ctrl-c (SIGINT/SIGTERM) stopped working in cygwin. If I recall, this might have something to do with TTY settings. Please advise on how to get it working again. I did not change anything intentionally
Output from stty -a:
$ stty -a
speed 38400 baud; rows 25; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = ^Z; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo -echoe -echok -echonl -noflsh -tostop -echoctl -echoke
When pressing ctrl-c the title of the cmd window changes to ~ from Select~. Ctrl-c also interrupts a program executing but does not create a new line.
I am also running on the sessions ssh-agent
I think this might be fixed witha computer restart but let me know if you have any idea.s
I found this question when I wanted to shut down a Java process started in a Cygwin session, and Ctrl+C wasn't working for me. Then realised I could just kill the process from another Cygwin session, i.e. in a new session:
ps - ef | grep java
kill -9 <pid>
Reinstalled Cygwin and it works now.