-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
stm32: Implement Asynchronous UART TX #1642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
DMA can certainly be used to implement non-blocking transfers, and to expand a bit on your reference to #1422, I have since managed to get it to work that way for I2S - see #1361. However, while my I2S fork does work (sort of…) it still has some issues which keep it from being ready to merge upstream just yet. |
Hi, Regarding asynchronous writes, this has been considered before, and it's somewhat planned to be added to the new hardware API. For the UART, it might be as follows: uart.write(buf, async=True) and if a callback notification is desired, previously you should have done: uart.irq(handler=some_handler, trigger=UART.TX_DONE, priority=...) |
@danicampora That's excellent! Is there a documented proposed spec I can read? EDIT: Found it: https://github.com/micropython/micropython/wiki/Hardware-API |
I found this same issue for "debug printf" in a stm32 project and the same issue applies for the print output to the UART in MP For a non-blocking wrap around serial buffer called by a "debug printf" function I've reused some code I wrote a long time ago It is still rough from a stm32 project context. |
I have a non blocking DMA driven UART TX transfer working on a local branch for UART1 and 2 on STM32L4/F4. However with the proposal I read here relies on the stream interface forwarding the Further I implemented a possibility to register a callback for a certain OR-ed IRQ sources. And I implemented the IRQ on RX IDLE (that means if after a gap less RX of serial bytes there is for the duration of one byte no traffic on the wire). Going forward to push this code I have the following questions:
For my proof of concept I created one static variable in the uart.c and if on this structure the I would like to get some feedback on my thoughts to push a proper solution to the Repo. Discussion about this and similar topics are: |
I appreciate your solution is more general and suited to high baudrates. But for many use-cases import uasyncio as asyncio
from pyb import UART
uart = UART(4, 9600)
async def sender():
swriter = asyncio.StreamWriter(uart, {})
while True:
await swriter.awrite('Hello uart\n')
await asyncio.sleep(2)
async def receiver():
sreader = asyncio.StreamReader(uart)
while True:
res = await sreader.readline()
print('Recieved', res)
loop = asyncio.get_event_loop()
loop.create_task(sender())
loop.create_task(receiver())
loop.run_forever() |
Since I'm a working mate of @tobbad and partly responsible for his work on the uPy UART a couple of comments. As @tobbad mentioned - the callback that can be registered with RX_IDLE is called if a byte-timeout occurs on the wire. The advantage is: You don't need a timeout timer or anything similar on the C-level. It's a HW feature of the STM32 uart. This allows you to respond to a received UART frame very fast and in a deterministic way. This is convinient not only in fast baudrate scenarios, but also if a lot of other activities are processed (lets say I2C, SPI etc). It also helps to create low power applications, since the callback is only called once, at the the end of the frame and you don't need to poll the interface for incoming chars all the time. I'm not much of an expert on uasyncio, but as far as I know, the scheduler of uasyncio will hop from one coro to the other in a round robin fashion? This makes generating a timely and precise response to an incoming frame difficult. I guess in such a scenario, you'll need to poll the uart fast - this generates unecessary overhead and restricts the use of coros which take a bit longer to yield. I agree though if you don't need this, then asyncio will probably be sufficient. RX_IDLE, together with the UART TX non-blocking DMA transfer allows you to implement an efficient, low overhead and fast communication RX-TX cycle to the peripheral that basically run in the "background" of uPy:
Siemens Building Technologies (the company I work for) is sponsoring work on uPy development. Our interest is to give back some of the staff we are doing to the community. We would very much look forward to feedback / opinions / suggestions to the questions asked by @tobbad (with the goal that we could provide a proper PR). Thanks. |
I agree - there are use-cases for an RX_IDLE callback where a cooperative scheduler like |
I am attempting to write large blocks (eg: 2048 bytes) of data to the UART at low baudrates whilst attempting to execute other code. I've discovered that the UART TX is actually blocking until the write is completed. This is a bit of a pain...
This issue is for creating an asynchronous write option for UART. Related to #1533
Probably either interrupt or DMA driven. Should ideally behave like the UART RX does, with a definable buffer in python code, or block as it currently does.
Reading related issues it seems like #1422 has had some success using DMA. Personally, I don't require the callback as I'm not streaming from a file, just an existing bytearray in memory.
I haven't had a chance to read the huge threads on some of the issues I've found so I'm not 100% up to date yet...
The text was updated successfully, but these errors were encountered: