Serial Port Doesn't Work Properly After Reboot, Unless I Execute Minicom

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



Leave a reply



Submit