Non-blocking UART transmit on PyBoard #17085
-
Non-blocking I/O (non-blocking everything, in fact) is a prerequisite for a real-time environment. The pyb library provides uart.any() to enable non-blocking UART receive. There appears to be no equivalent method for UART transmit. Before you jump in, I know that UART transmit has complications, but I am chasing the simplest possible configuration - one source of characters and no modem control. The only solution that comes to mind is to use a timer interrupt routine to dish out characters to the UART at a rate marginally slower than it can send them (yuk). The PyBoard documentation is quite sparse on UART.send(), not mentioning (for example) anything about software / hardware buffering (if any) or how to build a UART transmit interrupt routine. Obviously all transmit failures should also be non-blocking. All hints, clues and experience will be welcome. TIA. |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 18 replies
-
Micropython is in no way, shape or form even close to a real-time system. |
Beta Was this translation helpful? Give feedback.
-
@etherbrat UART output of the STM32 port is not buffered. That's a long outstanding improvement. Since uart.write() is blocking, the methods uart.flush() and uart.txdone() are not really helpful. They exist for compliance. As far as I can tell, transmit failures are non-blocking. The only failure ATM that could happen is timeout, and that raises an error. |
Beta Was this translation helpful? Give feedback.
-
No processor + program is an any way, shape or form even close to a real-time system unless you firstly define “real time”.
The PyBoard with Micropython will be good enough for me, if I can solve this problem.
Since the PyBoard Python docs don’t even mention DMA, I have to rule out your suggestion, but thanks anyway.
|
Beta Was this translation helpful? Give feedback.
-
Thanks, you have confirmed my suspicions.
So, given the limitations I have mentioned, sending should be effectively non-blocking if an interrupt routine dishes out characters more slowly than the UART can send them. That’s ugly (my own buffering, etc.), but achievable.
|
Beta Was this translation helpful? Give feedback.
-
Thumb? Jeez! Nice, maybe, but not for me. I’m a copy and paste programmer. Show me how.
|
Beta Was this translation helpful? Give feedback.
-
It's worth noting that the |
Beta Was this translation helpful? Give feedback.
-
I got my ugly version working. The only tricky part was (since uart.write() is in an ISR and requires bytes or bytearray objects) finding a zero-constructor way of slicing the output into single characters. I did this by buffering single-character bytes objects. Because the ISR runs slower than the UART, the buffer will overflow for long outputs, but as I’m only doing command line interaction, this won’t be a problem for me. Given that the UART is unbuffered, it’s unclear how asyncio would magically fix things. |
Beta Was this translation helpful? Give feedback.
It's worth noting that the
asyncio
StreamWriter
class achieves background UART transmission. See this tutorial section. While this isn't the "hard" concurrency of DMA, it works well in a wide range of applications.