Interrupt handler for UART

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
VikMal
Posts: 1
Joined: Tue Aug 09, 2022 7:51 am

Interrupt handler for UART

Post by VikMal » Tue Aug 09, 2022 8:04 am

Hello everyone,

I would like to ask if it is possible to attach a handler to an UART objet the same way as with the Timer object ? I mean using the callback() method the same way as it is used with the Timer object. I have looked into the MicroPython code and the uart_irq_handler() function doesn't execute any callbacks (in comparison to the timer_irq_handler() ). Is it done on purpose ?

Thank you in advance :)

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Interrupt handler for UART

Post by Roberthh » Tue Aug 09, 2022 9:03 am

It does not exist and it is intentional. Because the existing interrupt handlers are used for fast receive and send. A Micropython callback may be too slow for that purpose. There could be additionally a callback scheduled, which just signals an event. But event that scheduling takes time and may affect the ability to deal with fast baud rates.
On which situation do you miss a callback?

DeaD_EyE
Posts: 19
Joined: Sun Jul 17, 2022 12:57 pm
Contact:

Re: Interrupt handler for UART

Post by DeaD_EyE » Wed Aug 10, 2022 9:23 am

I think you should use uasnyio.
The funny thing is, that using UART together with uasyncio is easier than with CPython and serial_async.

Code: Select all

import uasyncio as asyncio
from uasyncio import StreamReader, StreamWriter
from machine import UART


def received(data):
    """
    Synchronous function without much blocking
    sleeping is not allowed, because this will pause the whole eventloop
    also long running task can not be done here
    """
    if not data:
        return
    print("Received Data:", data.decode())

    
async def read(stream):
    while True:
        # the await keyword gives control back to eventloop
        # and will block here, until control is given back
        # also telling uart how much data to read
        # stream.s is the UART instance
        # on network, it's a socket
        received(await stream.read(stream.s.any()))


async def main():
    uart = UART(2, baudrate=9600)
    sr = StreamReader(uart)
    sw = StreamWriter(uart)
    # await read(sr) # will block forever, because in read is a while True loop
    asyncio.create_task(read(sr)) # does not block, the eventloop has the control over the task
    # if await is used in front of asyncio.create_task, then you'll get the return value, but a while True loop never finishes
    # this will also block until the task is finished
    print("Receiving for 30 seconds")
    await asyncio.sleep(30) # blocks for 30 seconds
    # async main is left here and all remaining tasks are removed (afik)


if __name__ == "__main__":
    asyncio.run(main())
Tested communication with an ESP32 and RPi0W.
Don't forget the GND-Connection.

Jibun no kage
Posts: 144
Joined: Mon Jul 25, 2022 9:45 pm

Re: Interrupt handler for UART

Post by Jibun no kage » Thu Aug 11, 2022 1:27 am

I am working on a ESP01 to (original Pico) solution that uses the UARTs on each as a communication bridge, the ESP handles the WiFi/MQTT traffic and the Pico does the heavy lifting. Given the testing I have done, seems best to let the first processor on Pico handle UART traffic. Using uasynio I push much of the Pico load to the 2nd processor, so the primary processor is responsive to the UART traffic. So far everything is working at the level I need. Been a really interesting project thus far.

jameswise
Posts: 5
Joined: Tue Aug 16, 2022 1:32 am

Re: Interrupt handler for UART

Post by jameswise » Tue Aug 16, 2022 1:04 pm

Jibun no kage wrote:
Thu Aug 11, 2022 1:27 am
I am working on a ESP01 to (original Pico) solution that uses the UARTs on each as a communication bridge, the ESP handles the WiFi/MQTT traffic and the Pico does the heavy lifting. Given the testing I have done, seems best to let the first processor on Pico handle UART traffic. Using uasynio I push much of the Pico load to the 2nd processorUnscramble Word Finder, so the primary processor is responsive to the UART traffic. So far everything is working at the level I need. Been a really interesting project thus far.
This is an interesting project! I'm curious to know how you are finding the performance of the ESP01 and Pico working together. Have you found any bottlenecks or issues with using the UARTs for communication between the two processors?

Jibun no kage
Posts: 144
Joined: Mon Jul 25, 2022 9:45 pm

Re: Interrupt handler for UART

Post by Jibun no kage » Tue Aug 16, 2022 7:14 pm

Using mqtt simple and robust (original, not simple2 or robust2) if I send MQTT messages too fast I can flood the ESP01 or any ESP8266. Typically I get a recursive (stack exhausted) error, but this is misleading, because I am not using uasyncio, I think something is getting crushed as the requests are not queued. If I keep the rate of messages about 1 per second, no issues. Also, I don't use multiple subscribes, I parse the MQTT topic to call the given function rather than 1 topic per function. You can do something like following.

Say theTopic='cmnd/test/1/2/3', So the function would be 'On123' when you split the topic, then join it. You then can call the function with:

theParse=''.join(theTopic.split('/')[2:])
theFunction='On{0}'.format(theParse)
globals[theFunction](theTopic, thePayLoad)

I usually just replace 'cmnd' with 'status' to publish results back, and create thePayLoad as applicable.

As for the ESP01 to/from Pico... I just use UART raw, nothing fancy, at most, passing the topic and payload as json formatted string to/from. Using json I can catch any obvious corrupted communication. But, there are more elegant and resilient ways, to make sure UART communication is stable, but I have not as yet had to do such. All depends on if I can use such with the 1MB limit. The 'bridge' project is one such elegant UART protocol. Reference https://github.com/peterhinch/micropyth ... ter/bridge

I plan to use mqtt_as at some point for the MQTT client, but to get that on a 1MB ESP01 with uasyncio I will need a custom firmware image or frozen/bytecode MPY files on the ESP01. Reference https://github.com/peterhinch/micropyth ... er/mqtt_as

So my next effort is learning how to create custom firmware image of MP. This is going slow, since there is some MUCH outdated information on how to generate MP ports. Got the Unix port generated in minutes, but ESP8266 port keeps failing for different reasons, given different examples.

I am really enjoying figuring out each step/stage of this project. Having written ESP C code via the Arduino IDE, was an initial test, where the ESP MQTT/UART is all a Arduino sketch. But I digress.

jameswise
Posts: 5
Joined: Tue Aug 16, 2022 1:32 am

Re: Interrupt handler for UART

Post by jameswise » Wed Aug 17, 2022 4:09 am

Jibun no kage wrote:
Tue Aug 16, 2022 7:14 pm
Using mqtt simple and robust (original, not simple2 or robust2) if I send MQTT messages too fast I can flood the ESP01 or any ESP8266. Typically I get a recursive (stack exhausted) error, but this is misleading, because I am not using uasyncio, I think something is getting crushed as the requests are not queued. If I keep the rate of messages about 1 per second, no issues. Also, I don't use multiple subscribes, I parse the MQTT topic to call the given function rather than 1 topic per function. You can do something like following.

Say theTopic='cmnd/test/1/2/3', So the function would be 'On123' when you split the topic, then join it. You then can call the function with:

theParse=''.join(theTopic.split('/')[2:])
theFunction='On{0}'.format(theParse)
globals[theFunction](theTopic, thePayLoad)

I usually just replace 'cmnd' with 'status' to publish results back, and create thePayLoad as applicable.

As for the ESP01 to/from Pico... I just use UART raw, nothing fancy, at most, passing the topic and payload as json formatted string to/from. Using json I can catch any obvious corrupted communication. But, there are more elegant and resilient ways, to make sure UART communication is stable, but I have not as yet had to do such. All depends on if I can use such with the 1MB limit. The 'bridge' project is one such elegant UART protocol. Reference https://github.com/peterhinch/micropyth ... ter/bridge

I plan to use mqtt_as at some point for the MQTT client, but to get that on a 1MB ESP01 with uasyncio I will need a custom firmware image or frozen/bytecode MPY files on the ESP01. Reference https://github.com/peterhinch/micropyth ... er/mqtt_asWalmart Supercenters

So my next effort is learning how to create custom firmware image of MP. This is going slow, since there is some MUCH outdated information on how to generate MP ports. Got the Unix port generated in minutes, but ESP8266 port keeps failing for different reasons, given different examples.

I am really enjoying figuring out each step/stage of this project. Having written ESP C code via the Arduino IDE, was an initial test, where the ESP MQTT/UART is all a Arduino sketch. But I digress.
It's great that you're enjoying the project and learning new things! The process of creating a custom firmware image for the ESP8266 can be a bit tricky, but it's definitely doable. If you keep at it, you'll eventually get it figured out.

Jibun no kage
Posts: 144
Joined: Mon Jul 25, 2022 9:45 pm

Re: Interrupt handler for UART

Post by Jibun no kage » Thu Aug 18, 2022 4:11 pm

Yup, I know I could just use 'bridge' module that exists, and establish ESP01/Pico integration/communication. But then I would not get the opportunity to build a custom firmware image. That seems... ah, too easy. LOL!

Post Reply