Page 1 of 5

UART not working with today's version of micropython

Posted: Wed Apr 14, 2021 12:40 pm
by Tinus
I tried todays version of micropython for the pico but my code doesn't work anymore.

I am communicating between the pi and an ESP32 and where before I was able to send lines of text from the ESP to the pico I no only receive the last few characters.

before I would receive

Code: Select all

heartrate=64\r\n
but now I only get:

Code: Select all

ate=64\r\n
when I do readline()

I understand that something has changed in the UART code, can somebody tell me what I have to change to be able to get full lines of text over serial in this new version?

Thanks

Re: UART not working with today's version of micropython

Posted: Wed Apr 14, 2021 1:45 pm
by Tinus
This is the code I have been using:

Code: Select all

class MyHr:
    hr = 0
    uart = None
    
    def __init__(self, TXPinNr=12, RXPinNr=13):
        self.uart = UART(0, 9600 , parity=None, stop=1, bits=8, tx=Pin(TXPinNr), rx=Pin(RXPinNr))
    
    def read(self):
        if (self.uart.any()):
            raw = self.uart.readline()
            strRaw = raw.decode().replace('\r\n','')
            if (strRaw.find('heartrate=')==0):
                try:
                    self.hr = int(strRaw.replace('heartrate=',''))
                except ValueError:
                    pass
        return self.hr

Re: UART not working with today's version of micropython

Posted: Wed Apr 14, 2021 2:48 pm
by Roberthh
Does that happen for every message or just the first one?

Re: UART not working with today's version of micropython

Posted: Wed Apr 14, 2021 2:52 pm
by Tinus
All of them

Re: UART not working with today's version of micropython

Posted: Wed Apr 14, 2021 3:06 pm
by Roberthh
OK. I could replicate that. You have to add a small timeout to the init, like:

self.uart = UART(0, 9600 , parity=None, stop=1, bits=8, tx=Pin(TXPinNr), rx=Pin(RXPinNr), timeout=10)

The difference: before the change, UART was blocking. Now it is non-blocking like in all other ports.
Edit: See also the documentation at https://docs.micropython.org/en/latest/ ... chine.UART
Read a line, ending in a newline character. It may return sooner if a timeout is reached. The timeout is configurable in the constructor.

Re: UART not working with today's version of micropython

Posted: Wed Apr 14, 2021 4:20 pm
by Tinus
Oh super,

Thank you very much.

Re: UART not working with today's version of micropython

Posted: Thu Apr 15, 2021 5:20 am
by kevinkk525
Maybe I'm missing something but my understanding is, that if anything should be missing, it's the end of the message, not the start? Wh, would "heart" disappear?
Apart from that I never used readline() but would expect it to only return something when it had a full line (otherwise returning none?). How do other ports handle that?

Re: UART not working with today's version of micropython

Posted: Thu Apr 15, 2021 6:47 am
by Roberthh
All ports handle it the same way, and there is a note in the documentation (!) that uart.readline() may return a partial line, if timeout is not set. Why the error happens here is not clear, because uart.readline() is called only after uart.any() flags presence of data. So even if it is not an undocumented behavior, it is something worth to be analyzed.

Re: UART not working with today's version of micropython

Posted: Thu Apr 15, 2021 11:19 am
by Tinus
The timeout works for the readline().

I am also seeing some strange behaviour on the write().
I am sending commands to a Nextion display like this:

Code: Select all

 def send(self, command):
        write_buffer = bytearray(len(command) + 3)
        write_buffer[0: len(command)] = bytes(command, 'ASCII')
        write_buffer[-3:] = b'\xff\xff\xff'
        self.uart.write(write_buffer)
Before this worked flawlessly but now starnge things happen on the display. This is extra weird because the display usually just ignores any command it doesn't understand.

I am repeatedly sending commands like this:

page1.gSpeed.val=9

on a loop with a sleep(0.1)

Every other second (more or less) the display apears to receive messages like:

page1.gSpeed.val=99

the same occurs for other fields. I have tried changing the timeouts but that doesn't change anything.
I can't get my head around how the numbers get duplicated At first I thought it was just the last digit that is repeated but that makes no sense since that is not the last character sent, there is always the appended b'\xff\xff\xff' to end the command.
Then I also noticed larger numbers getting doubled up occasionally.

page1.gDistance.val=812

occasionally results in the display showing 812812

Re: UART not working with today's version of micropython

Posted: Thu Apr 15, 2021 11:45 am
by Roberthh
That seems to be a different topic. Timeout does/should not affect write.
In a simple test of sending that data to the screen I could not replicate that. It should however be considered, that uart.write() is too not blocking any more. As long as the message is shorter than the buffer size, it returns immediately. The default buffer size is 256, the minimal size is 32 (set with txbuf=nnn). So calling uart.write() again before the message actually has been transmitted will shorten the time gap between two transmissions. That may lead to an overrun in the receiver.
You could try to set txbuf to 32, which is the hardware FIFO size. Then uart.write() should behave as before.