Replies: 4 comments 7 replies
-
This is a bit beyond me as I haven't explored this at all beyond the top level functions. But SPI being so central/universal for embedded systems, anything with a 50% boost is pretty important in my opinion! |
Beta Was this translation helpful? Give feedback.
-
This is impressing. If you do not get the full attention/feedback of developers here it might be advantageous to submit your developments in form of a pull request or an issue with enhancement label. As for the Raspberry Pico, after reading your descriptions and findings, I got the idea that all the transfer from the framebuffer memory to the SPI, including color lookup, might be achieved by a chain like this: |
Beta Was this translation helpful? Give feedback.
-
There is a lot to unpack here. First the general point: in the nine years I've been involved with MP there have been periodic discussions of nonblocking device drivers. I can't speak for the maintainers but I think there would be interest in a solution subject to agreement on an API. A possible approach would be to raise an RFC issue. On the specific of micro-gui I'd make the following comments:
Some of that downtime is caused by the mechanism described above where |
Beta Was this translation helpful? Give feedback.
-
I'm currently building an embedded platform that needs a lot of bulk transfer. From a software / firmware development view I'd very much appreciate an On platform that support e.g. DMA, this could mean the operation yields after writing to memory (and the wait is asynchronous), on platforms that only support blocking operations, this might mean a fallback to the blocking api, a purely software impl impl might or might not yield depending on selected clock speeds or buffer sizes. Ideally, this behavior could be mirrored across different hardware APIs, and the documentation would state which specific behavior is chosen on which platform. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
While tinkering with micropython-micro-gui I noticed that transferring data to the display takes quite some time. Peter Hinch, the author of micropython-micro-gui, mentions this too.
I'm using an ESP32 board and an ILI9341 LCD display with 360x240 pixels, driven by the ILI9486 driver from the micropython-micro-gui library.
Looking a bit closer at the SPI bus (using a DSO) and at the source code of the driver (with my eyes ;) it turned out that the driver uses the SPI bus only for a bit more than 50% of the entire runtime of a display update. The remaining time is mostly needed to map framebuffer data, having 4 bits per pixel, to a representation with 16 bit per pixel, as needed by the ILI9341.
The ESP32 uses DMA for its hardware SPI interfaces, hence methods like
machine.SPI.write()
spend most of the time waiting until a chunk of data has been transferred.This time spent waiting for data to be transferred to the display could be used by the display driver to do the 4->16bit conversion for the next SPI transfer. Out of curiosity I turned the file
ports/esp32/machine_hw_spi.c
into an experimental C module that provides nonblocking access to the SPI bus. (As written in the README file there, I do not consider the module in any way as "ready for general usage" – it is just intended to be a proof of concept.)If the ILI9486 module uses an instance of
machine.SPI
to control the display, a full image update takes 101ms .. 117ms, with my experimental_ASPI
class it takes 58ms .. 60ms.IMHO this is enough of a performance increase to ask if it would make sense to add support for nonblocking data transfer to class
machine.SPI
. I know that implementing this is a bigger task than what I wrote in mp-aspi since most Micropython ports are affected. I am not even sure if such methods would be useful for each microcontroller supported by Micropython - do all of them support DMA?Anyway – what about this: struct
mp_machine_spi_p_t
(defined inextmod/machine_spi.h
) could get additional fieldsstart_transfer
,finish_transfer
,transfer_finished
,queue_full
. These would be pointers to functions for nonblocking data transfers.Ports that do not support nonblocking SPI data transfers simply set these pointers to NULL. (Such NULL pointers already exist in some ports for the field
deinit
.)Ports that support the nonblocking SPI data transfers would implement an internal queue that allows to queue at least two SPI transfers.
int start_transfer(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest)
queues an SPI data transfer and returns an ID for the queued transfer. The function blocks when the internal queue is full until another transfer is finished. (It might make sense to add a timeout parameter.)void finish_transfer(int id)
blocks until the given transfer is finished. Again, an additional timeout parameter might make sense.int transfer_finished(int id)
returns 0 if the given transfer is still under way, otherwise it returns 1. (Hrm... What about invalid IDs? Return -1 or perhaps raise aValueError
?)Changes on the "Python side" would mostly mean to add a parameter
blocking=True
to the methodsread()
,read_into()
,write()
,write_readinto()
. Depending on the value ofblocking
, these methods would either call the existing C functiontransfer()
or the new functionstart_transfer()
. The methods would have to return a transfer ID.If a port does not support nonblocking transfers, the methods would raise a
NotImplementedError
if they are called withblocking=False
.Three additional methods would be necessary,
finish_transfer(id)
,transfer_finished(id)
,queue_full()
. They would also raiseNotImplementedError
if a port does not support nonblocking transfer.So... Did I miss something important? Does the entire idea make sense? I'd like to offer to work on
extmod/machine_spi.c
and on the ESP32 port; perhaps also on the ESP8266 port. Can't promise much for other ports. Currently, I have only modules with these processors aside from two Raspberry Pico modules that I bought a few weeks ago – but I did not even open their anti-static bags yet...Beta Was this translation helpful? Give feedback.
All reactions