PySerial generating error after successful transmitions


9 posts
by Diodo » Sun Jan 27, 2013 9:11 pm
I am very new at python. I have a R-pi connected to a PIC micro controller. The PIC has a voltage divider to lower the 5V to 3.3V. The PIC sends a "$OK" message every second. I am able to read the message with the PIC just fine, for 19 seconds. Always at the end of 19 seconds, I get the following error:
Code: Select all
z@raspberrypi ~/Tutorial $ sudo python SerialCOM.py
1
PIC Says: $OK
inWaiting: 3
Clear inbuff: 0
2
PIC Says: $OK
inWaiting: 3
Clear inbuff: 0
3
PIC Says: $OK
inWaiting: 3
Clear inbuff: 0
:
:    ......... removed all the other responses for clarity
:
17
PIC Says: $OK
inWaiting: 3
Clear inbuff: 0
18
PIC Says: $OK
inWaiting: 3
Clear inbuff: 0
Traceback (most recent call last):
  File "SerialCOM.py", line 30, in <module>
    inbuff = ser.inWaiting()
  File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 431, in inWaiting
    s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
IOError: [Errno 5] Input/output error

At first I thought that I was over flowing the buffer, hence I reduced the messages from the PIC to once a second. Originally I had set the messages to be sent every 50 msec and I still got the same error at exactly19 seconds once I run the program.

The PIC code is very simple just sending the message while I learned how to receive it with Python:
Code: Select all
MAIN:   
    X = 0
    Repeatcmd = 0
    timeout = 0
   
    CMD_in = 0
    DURATION = 0
    EOF_s = 0
   
    SEROUT rPI_TX_out, 2, ["$OK"]
    pause 1000

goto MAIN


The complete python code is as following:
Code: Select all
#! /usr/bin/python
import serial
import string
import time

# Raspberry Pi GPIO Serial Port settings
rpiCOM = '/dev/ttyAMA0'
baud = 9600
xtimes = 0
inbuff = 0

# Setup - if serial port can't be open an Exception will be raised
while True:
    try:
        ser = serial.Serial(rpiCOM, baud, timeout=1)
        # go out of while loop when connection is made
        break

    except serial.SerialException:
        print 'COM port ' + rpiCOM + ' not available. Wait...'
        time.sleep(3)

# Get input from serial buffer
while True:
    try:
        str = ""

        while 1:
           inbuff = ser.inWaiting()
           msgCOM = ser.read(inbuff)

           if msgCOM == '$OK':
                xtimes += 1
                print xtimes
                print "PIC Says: " + msgCOM
                print "inWaiting: %d" %inbuff
                ser.flushInput()
                inbuff = ser.inWaiting()
                print "Clear inbuff: %d" %inbuff
                break
           #str += msgCOM
    except serial.serialutil.SerialException:
        xtimnes = 0
        ser.close()
        time.sleep(3)
        ser = serial.Serial(rpiCOM, baud)
        ser.open()
        pass


As you noticed I have been trying to catch the error and close the port but no luck. I have started the program with the PIC turned off and the program runs, waiting for serial data without any errors for more than the 19 sec. Once I turn on the PIC and even if I turn it off, as soon as the serial data starts flowing in, the program generates an error 19 seconds later. The serial port is from the GPIO and I commented out the /etc/inittab "2:23 line", as well as deleted from the /boot/cmdline.txt the following: console=ttyAMA0,115200 kgdboc=ttyAMA0,115200

Any help and guidance you can provide I would really appreciate.

Thank you,
Posts: 4
Joined: Sun Jan 27, 2013 8:36 pm
by Diodo » Mon Jan 28, 2013 6:24 pm
in case someone is following up on this issue, or someone else runs into the same problem:

I updated the code multiple times and figured out that the 19 seconds is not really a factor, well it just happens that it is a buffer issue that I still need to trouble shoot.

Until now I notice the problem is with python code reading the serial port when there aren't anything in the buffer:
Code: Select all
inbuff = ser.inWaiting()
msgCOM = ser.read(inbuff)


The problem now is that there should be obviously characters in the buffer as I constantly send messages. I have since added to check if the buffer is empty to avoid reading it, if it is then I flush the buffer, close the port, pause and reopen the port as following:

Code: Select all
 while 1:
         inbuff = ser.inWaiting()
         if inbuff > 0:
#          msgCOM = ser.read(3)
           msgCOM = ser.read(inbuff)

           if msgCOM == '$OK':
                xtimes += 1
                print xtimes
                print "PIC Says: " + msgCOM
                print "inWaiting: %d" %inbuff
                ser.flushInput()
                inbuff = ser.inWaiting()
                print "Clear inbuff: %d" %inbuff
                ser.write('$OK')
                break
           else:
                print "NOK Message: " + msgCOM

         else:
           ser.flushInput()
           print "Buffer empty"
           ser.close()
           time.sleep(1)
           ser.open()


So that gets rid of the error, but I now have to figure out why the R-Pi is not recognizing what has arrived into the buffer all the time. Furthermore, I need to understand why the R-Pi is only sending the correct message back half of the time. At this point I have ordered a voltage level shifter to ensure that it is not a voltage related issue being too low for the PIC and the current too limited by the resistor divider from the PIC to the R-Pi.

Has anyone reliably connected a 5V PIC signal with voltage divider to a R-PI for serial communication? I currently use 3- 1.5K ohm resistors to get 3.3V from 5V
Posts: 4
Joined: Sun Jan 27, 2013 8:36 pm
by xordiss » Tue Jan 29, 2013 1:08 am
Could it be a timeout?

In the past i wrote some code using serialpy in order to comunicate a OMRON PLC and a PC
and i remember something about 20s timeout as default option for comms timeout .
It can be changed using serialpy properties . You may change this time and see what happens .

Hope it will help
Posts: 4
Joined: Tue Jan 29, 2013 12:55 am
by -rst- » Tue Jan 29, 2013 12:08 pm
There should be no reason to close and re-open the port (unless there is something really wrong with the library)...

Maybe try timeout=0 parameter when opening the port? And maybe remove the extra flush and inWaiting from handling the 'OK'...
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 900
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by xordiss » Thu Jan 31, 2013 1:19 am
I've found and old py script I made , that reads data from a bluethooth GPS using serialpy.
As you will see there's some code mixed relative to pythoncard (a sort of VB ) that you can ignore.
Beware of initialization of serialpy at first method and check timeout property. Read carefully serialpy documentation about this point . I barely remember some problems due to improper initialization , and i'm almost sure that serialpy is waiting for something that never happens (like xonxoff , rtscts or return code"\n" ) and it's because this you get a timeout despite of data is read at com port. It seems like a little piece is missing at the handshake . I don't know for shure if problem is in the raspy or the pic side but i "smell" something is missing and this is the source of problem. I don't believe voltage divider can cause this problem .
This script have been running for hours without flushing or closing the com port ( I've made it manually using 3Dbuttons).
I've not included the rsrc file (frames buttons and so) .
You can see there's some token and decoding work in order to place information in diferent boxes on screen. Pretty simple ,and it works smooth !.

Best Luck








#!/usr/bin/python

"""
__version__ = "$Revision: 1.3 $"
__date__ = "$Date: 2005/06/05 02:38:47 $"

@ J.Castells 2006
"""

import serial , string
from PythonCard import dialog,model
from PythonCard.components import textfield,button




class MyBackground(model.Background):


def on_initialize(self,event):
self.ser=serial.Serial(port=3,baudrate=9600,bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,
timeout=0.5,xonxoff=0,rtscts=0)

#def on_Button1_mouseClick(self,events):
#pass

def on_Button2_mouseClick(self,events):
if (not self.ser.isOpen()):
self.ser.open()
self.components.CheckBox1.checked=True

def on_Button3_mouseClick(self,events):
if (self.ser.isOpen()):
self.ser.close()
self.components.CheckBox1.checked=False


def on_LlegirSerie_command(self,events):
line=self.ser.readline()
print line
self.components.TextField1.text=line
tokens=string.split(line,',')
for n in range (0,len(tokens)):
if (tokens[0]=='$GPGGA'):
self.components.TextField2.text=tokens[9]
self.components.TextField3.text=tokens[7]
self.components.TextField4.text=tokens[2]
self.components.TextField5.text=tokens[3]
self.components.TextField6.text=tokens[4]
self.components.TextField7.text=tokens[5]
if (tokens[0]=='$GPGSA'):
if (tokens[2]=='1'):
self.components.TextField8.text='NO'
if (tokens[2]=='2'):
self.components.TextField8.text='2D'
if (tokens[2]=='3'):
self.components.TextField8.text='3D'

if __name__ == '__main__':
app = model.Application(MyBackground)
app.MainLoop()
Posts: 4
Joined: Tue Jan 29, 2013 12:55 am
by -rst- » Thu Jan 31, 2013 11:20 am
Please, please - always put code examples within the 'Code' tag ...especially Python because the white space...
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 900
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by xordiss » Fri Feb 01, 2013 12:33 am
Sorry it was late at night and i'm not very used to post code .
Here it goes again:

Code: Select all
#!/usr/bin/python

"""
__version__ = "$Revision: 1.3 $"
__date__ = "$Date: 2005/06/05 02:38:47 $"

    @ J.Castells  2006
"""

import serial , string
from PythonCard import dialog,model
from PythonCard.components import textfield,button




class MyBackground(model.Background):


    def on_initialize(self,event):
       self.ser=serial.Serial(port=3,baudrate=9600,bytesize=serial.EIGHTBITS,
       parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,
       timeout=0.5,xonxoff=0,rtscts=0)

    #def on_Button1_mouseClick(self,events):
        #pass
       
    def on_Button2_mouseClick(self,events):
        if (not self.ser.isOpen()):
            self.ser.open()
            self.components.CheckBox1.checked=True
       
    def on_Button3_mouseClick(self,events):
        if (self.ser.isOpen()):
            self.ser.close()
            self.components.CheckBox1.checked=False
           
           
    def on_LlegirSerie_command(self,events):
        line=self.ser.readline()
        print line
        self.components.TextField1.text=line
        tokens=string.split(line,',')
        for n in range (0,len(tokens)):
            if (tokens[0]=='$GPGGA'):
                self.components.TextField2.text=tokens[9]     
                self.components.TextField3.text=tokens[7]
                self.components.TextField4.text=tokens[2]
                self.components.TextField5.text=tokens[3]
                self.components.TextField6.text=tokens[4]
                self.components.TextField7.text=tokens[5]
            if (tokens[0]=='$GPGSA'):
                if (tokens[2]=='1'):
                    self.components.TextField8.text='NO'
                if (tokens[2]=='2'):
                    self.components.TextField8.text='2D'       
                if (tokens[2]=='3'):
                    self.components.TextField8.text='3D'
               
if __name__ == '__main__':
    app = model.Application(MyBackground)
    app.MainLoop()
Posts: 4
Joined: Tue Jan 29, 2013 12:55 am
by -rst- » Fri Feb 01, 2013 12:08 pm
Ahh, quite a lot easier on the eye ;)
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 900
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by Diodo » Sat Feb 02, 2013 7:07 pm
So I believe I have found my mistake. While I follow this instructions (lhttp://codeandlife.com/2012/07/29/arduino-and-raspberry-pi-serial-communication/) I did not pay attention at what I commented out. The instructions

So in case someone runs into this problem pay close attention. The instructions to comment out from the /etc/inittab file are:

Code: Select all
#Spawn a getty on Raspberry Pi serial line
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100


Make sure that you comment out the one that uses the ttyAMA0. I commented the wrong serial port:

Code: Select all
# Line below IS NOT to be commented out to allow use of serial port
2:23:respawn:/sbin/getty 38400 tty2


Because I noticed that it started with the 2:23:respawn: which is very close to what is in the instructions. So in reality the serial port would stop receiving commands because it was as if I was entering a very loooooong user name, :oops:

I was able to find out because when using the minicom everything I typed with Tx and Rx looped back, would appear on the screen, but if I pressed enter (ASCII: 10d) the port would block. Then seconds later the port would show a partial message that said Raspberry Pi, when I was not expecting anything.

At the end the following code works:
Code: Select all
#! /usr/bin/python
import serial
import string
import time

# Raspberry Pi GPIO Serial Port settings
rpiCOM = '/dev/ttyAMA0'
baud = 9600
xtimes = 0
inbuff = 0
msgCOM = ""

# Setup - if serial port can't be open an Exception will be raised
while True:
    try:
        print 'Opening port'
        ser = serial.Serial(rpiCOM, baud, timeout=0, stopbits=serial.STOPBITS_O$
        #time.sleep(10)
        print 'Port OPEN'
        # go out of while loop when connection is made
        break

    except serial.SerialException:
        print 'COM port ' + rpiCOM + ' not available. Wait...'
        time.sleep(3)

# Get input from serial buffer
while True:
    try:
        str = ""
        print " Ready to check inbuff: " + msgCOM
        while 1:
         inbuff = ser.inWaiting()
         if inbuff > 0:
           msgCOM = ser.read(3)

           if msgCOM != '':
                xtimes += 1
                print xtimes
                print "PIC Says: " + msgCOM
                print "inWaiting: %d" %inbuff
                ser.flushInput()
                inbuff = ser.inWaiting()
                print "Clear inbuff: %d" %inbuff
                ser.write('$OK')
                msgCOM = ""
                break
           else:
                print "NOK Message: " + msgCOM

         else:

          # print "Buffer empty:  " + msgCOM
           time.sleep(1)
       
    except serial.serialutil.SerialException:
        print "Serial Exception raised"
        pass



By the way the voltage divider works well with the PIC.
Posts: 4
Joined: Sun Jan 27, 2013 8:36 pm