Serial port doesn't work properly after reboot, unless I execute minicom
The symptom you have is an indication that your program is not initializing the serial terminal to the proper mode that it requires.
minicom has the same settings AFAICS
Seems like you choose to guess rather than gather actual data.
Use stty -a -F /dev/ttyUSB0
before and after using minicom.
The major difference is that the termios mode is probably canonical by default (after the reboot), and minicom leaves it in non-canonical mode.
Try using stty raw -F /dev/ttyUSB0
before starting your program.
Why serial port reading is not working after reboot?
I managed to fix this. The problem was that jpnevulator
was setting the port for me when using it for reading and then the settings remained for my app.
To fix this I set up almost everything for the serial port.
bool Serial::Setup(){
if(!openPort()){
return false;
}
tcgetattr(fdPort, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
options.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OLCUC | OPOST);
options.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON);
options.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
if(tcsetattr(fdPort, TCSANOW, &options)){
return false;
}
return true;
}
using PySerial don't work until port is opened with minicom
This issue was because of Arduino nano schematic where DTR signal is connected to the reset signal which makes the Arduino to reset each time the serial port is open. This post made me search the right thing on the internet. That's why opening minicom and closing without resetting the port makes it work...
When the serial is not used anymore by a process the DTR line is reset so next time a process open the serial port the DTR is driven which makes the Arduino reboot.
A way to fix it is to modify the board or two disable the DTR handling. This can be done by dsiable the HUPCL bit of the terminal lib.
Some people manage to fix it with pySerial but it does not work for me so I had to do as below...found here and here.
import serial
import termios
port = '/dev/ttysUSB0'
f = open(port)
attrs = termios.tcgetattr(f)
attrs[2] = attrs[2] & ~termios.HUPCL
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
f.close()
se = serial.Serial()
se.baudrate = 115200
se.port = port
se.open()
Can't read from serial port if not opened once with minicom
What is strange with the result I get is that the read blocks forever even if I know that the device is sending frames.
...
Once the port has been opened using minicom and that I have exited it, my program works well until next reboot of my computer.
Not strange at all.
That's a clear indication that your program's initialization of the serial terminal is incomplete and depends on a pre-existing initialization to be suitable.
(BTW "strange" is an opinion-based description that conveys no technical information to aid debugging.)
The default mode of the serial terminal is typically canonical mode (for transferring text) after a system boot.
Therefore an (unintentional) canonical read() of a serial terminal will block until a line termination character (e.g. a new-line character or 0x0A) is encountered.
Your program would block forever if the source never sends any line termination character.
You can confirm this by using the stty -F /dev/ttyUSB0 -a
command, and find that the icanon attribute has no hyphen preceding it.
Minicom configures the serial terminal for non-canonical mode, which is the mode that your program apparently also expects the serial terminal to operate in.
However your program only configures the termios parameters for baudrate, framing, and flow-control.
It is missing several salient terms for reliable operation of a serial terminal.
If your program requires non-canonical mode, then it must explicitly configure that mode rather than rely on a preexisting configuration.
Since numerous other related attributes should also be set or cleared for non-canonical mode, the macro cfmakeraw() is the simplest edit to your code.
Insert
cfmakeraw(&options);
in between your baudrate and "parity" configuration.
Note that use of a 7-bit data frame will likely cause corruption if the data is not exclusively ASCII text, so supporting those three modes in your program is incongruous.
The other salient omission is enabling the receiver and setting local mode:
options.c_cflag |= (CLOCAL | CREAD);
The device I'm communicating with send a frame of 11 bytes
BTW your use of "frame" in the context of a serial terminal is inappropriate. In asynchronous serial communication each character or byte is framed. Your references to a "frame" would be more appropriately called a message or packet or datagram.
Cannot send character with minicom
Local echo says nothing about what goes over the wire. It can also be something with how scanf() interprets newlines. Try to create a program with getchar() and see if that gets any input at all, especially what happens when you press enter in the different terminal emulators.
Check that all baud rate, etc settings are set correctly in minicom. Check out the command line parameters for minicom, this way you can specify options directly.
Automating serial port communication on Linux
Kermit is a serial communication app like minicom and it has its own script language, and I used it for some automatic upload on embedded devices. However, it is quite limited and/or buggy, so I finally switched to using python and pyserial.
Whenever you deal with texte mode, like AT command set or speaking to a shell over a serial line, it is really powerful.
If I need to do binary transfer using some standard protocol, I usually use command line tools in non interactive mode, and spawn them from my python script.
Here is some part of the tools I built : waiting for some input, sending data through xmodem, sending a command to u-boot and starting a transfer using the kermit protocol. I use it for automatic flashing and testing of embedded devices.
class Parser :
def __init__(self, sport_name):
self.currentMsg = ''
if sport_name :
self.ser = serial.Serial(sport_name, 115200)
def WaitFor(self, s, timeOut=None):
self.ser.timeout = timeOut
self.currentMsg = ''
while self.currentMsg.endswith(s) != True :
# should add a try catch here
c=self.ser.read()
if c != '' :
self.currentMsg += c
sys.stdout.write(c)
else :
print 'timeout waiting for ' + s
return False
return True
def XmodemSend(self,fname):
if not self.WaitFor('C', 1) :
print 'RomBOOT did not launch xmodem transfer'
return
self.ser.flushInput()
self.ser.close()
call(["xmodem","-d",self.ser.port,"-T",fname])
self.ser.open()
def UbootLoad(self, fname):
self.ser.write('loadb 0x20000000\n')
if not self.WaitFor('bps...',1) :
print 'loadb command failed'
sys.exit()
self.ser.flushInput()
self.ser.close()
retcode=call(['kermit','-y','kermit_init','-s',fname])
if retcode != 0 :
print 'error sending' + fname
sys.exit()
self.ser.open()
self.UbootCmd('echo\n')
Related Topics
Black Color Showing on Cmy Channels When Converted to Cmyk Using Ghostscript
Groovy Process Not Working with Linux Shell (Grep and Awk and Ps)
Minicom Black Background Color Is Not Respected
Every Command Is Returning 'Bash: <Command>: Command Not Found...'
Should I Rebuild a Dependent Lib After System Update
Trying to Search Files from User Keyword in Bash
How to Connect Github Desktop with Cpanel
Bash Script Runs One Command Before Previous. I Want Them One After the Other
Bash Script; How to Use Vars and Funcs Defined After Command
No Such File or Directory Find Command on Linux
How to Preserve Command Line Spaces in a Linux Application
How to Make Find and Printf Works in Bash Script
For Loop in Bash Simply Prints N Times the Command Instead of Reiterating
Different File Owner Inside Docker Container and in Host MAChine
How to Append to a File Using X86-64 Linux System Calls