kengineer Posted February 23, 2016 Report Posted February 23, 2016 I had a question regarding support for DMA SPI in the ILI9341 driver. I've got a display that utilizes the ILI9341 that I plan to drive using the uGFX library. One thing I've noticed, is that the ILI9341 driver does many individual writes to SPI. On my system, even with a 24 MHz SPI bus, due to the large gaps in between successive SPI write calls, the init calls and screen draws are visually slow. The part I'm using has DMA SPI and I have gotten this working. My question is that do I need to restructure the driver code to utilize this method, seems the answer is yes. I'm also wondering how this is going to play into reading from SPI flash in the future though I haven't gotten that far in regards to understanding the entire uGFX library.
Joel Bodenmann Posted February 23, 2016 Report Posted February 23, 2016 Yes, it's correct that using DMA with the ILI9341 driver will require some driver code modifications. However, that shouldn't require a lot of modification. Most drivers have been contributed by countless users over the years. We don't have the resources to properly implement each driver on our own. So as soon as we see that there's a working driver that meets our coding standards we make sure that it works on one way or the other and then it goes into the repository. But the list of implemented features is usually a lot smaller than with the drivers that we implemented ourselves. You can have a look at the SSD1289 driver to get an idea on how to add DMA support to an existing driver. To actually talk about your problem: Make sure that streaming is enabled. That way the GDISP module will make burst writes whenever possible.
kengineer Posted February 24, 2016 Author Report Posted February 24, 2016 Understood, thanks for the quick reply. Just wanted to make sure this was the case before I started modifying the code. Thanks!
kengineer Posted February 24, 2016 Author Report Posted February 24, 2016 Doesn't this mean with streaming enabled that I have to modify the gdisp driver as well? Look at the example below for the code used when streaming to clear an area of the screen: // Next best is streaming #if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT if (gvmt(g)->writestart) #endif { uint32_t area; g->p.x = g->p.y = 0; g->p.cx = g->g.Width; g->p.cy = g->g.Height; g->p.color = color; area = (uint32_t)g->p.cx * g->p.cy; gdisp_lld_write_start(g); #if GDISP_HARDWARE_STREAM_POS #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT if (gvmt(g)->writepos) #endif gdisp_lld_write_pos(g); #endif for(; area; area--) gdisp_lld_write_color(g); gdisp_lld_write_stop(g); autoflush_stopdone(g); MUTEX_EXIT(g); return; } #endif That for loop at the bottom was written to make individual calls to gdisp_lld_write_color for the number of pixels being written meaning I cannot write a stream of bytes at a time without changing this correct?
inmarket Posted February 27, 2016 Report Posted February 27, 2016 If it is possible to write a block of bytes to the controller then ugfx will do it. The ILI9341 is considered a streaming controller. Normally you set up a window and then stream bytes individually into the window. If you want to accelerate block type operations using DMA then you change the driver definition to turn on routines for those block operations. In gdisp_lld_config.h you would add something like: #define GDISP_HARDWARE_FILLS TRUE #define GDISP_HARDWARE_BITFILLS TRUE and then you would define the appropriate driver functions to implement those calls. When those flags are enabled the gdisp drawing layer will use the accelerated block routines whenever feasible and the normal streaming calls when it can't. This way you get the best performance (non-DMA) for single-pixel/streaming operations and the best efficiency (DMA) for block operations. For an example of a streaming controller that implements these functions have a look at the Nokia6610GE8 driver. This driver does this to get around controller bugs rather than for speed but the method still applies. The Win32 driver also has defines that enable it to emulate just about any combination of controller support. This is useful to identify how GDISP uses the various calls but in a non-embedded environment where it is easy to debug and monitor. Not that you will need to ensure that any running DMA operation is complete before you start a new operation (either DMA or non-DMA). This will obviously (but unfortunately) involve busy polling. Note the best way to do all this is to create a new driver (say ILI9341DMA) rather than directly modifying the existing one as the changes are significant although the new driver can start as a copy of the original.
kengineer Posted March 14, 2016 Author Report Posted March 14, 2016 Thanks this works out quite well at least for doing things like clearing the screen (just have splash screen example running right now). One thing I'm not certain of yet because I haven't done this is for displaying images or graphics. Let's suppose for example when the display starts I need to draw a background image. What determines how much of an image is actually buffered at a time and therefore how much of it can really be DMA'd at once without breaks?
Joel Bodenmann Posted March 14, 2016 Report Posted March 14, 2016 Glad to hear that you got it working! 1 hour ago, kengineer said: What determines how much of an image is actually buffered at a time Each image decoder defines its own buffer size internal. That's a setting that is not available for configuration to the user of the µGFX library. You can find those definitions at the top of the source file of each image decoder.
kengineer Posted March 15, 2016 Author Report Posted March 15, 2016 So I cannot change this correct? Any other tips on speeding up draw time other than just sticking to drawing functions rather than images?
Joel Bodenmann Posted March 15, 2016 Report Posted March 15, 2016 That's correct, you are not supposed to change those settings. Are you experiencing performance issues or are you just asking generally? You can cache images which will store the decoded image in RAM which will vastly reduce image rendering time as there's no more decoding to do. You can find more information about image caching here: http://wiki.ugfx.org/index.php/Images#Caching For generic speed-ups you might consider using Pixmaps. Pixmaps provide dynamic, partial framebuffers that allow you to render anything in RAM first and then blitting everything in one burst write to any location on the display. This usually speeds things up a lot. You can find more information about pixmaps here: http://wiki.ugfx.org/index.php/Pixmaps Note that it's always a trade-off between speed and memory usage.
kengineer Posted March 15, 2016 Author Report Posted March 15, 2016 Yes unfortunately non DMA SPI is pretty slow on my platform. Pixmaps sound like a good idea. I can allocate a good portion of RAM if needed so this might be a good solution.
rreignier Posted November 21, 2016 Report Posted November 21, 2016 Hello, Sorry for using an old thread but I wonder if @kengineer managed to add DMA support to the ILI9341 driver? I am using this display with uGFX with an STM32F103 and ChibiOS but I have noticed slow operations when filling some rather big surfaces. So if it was already done, it will be nice if @kengineer could share his work. Thanks
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now