Jump to content

ILI9341 Driver DMA SPI support


kengineer

Recommended Posts

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 3 weeks later...

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 8 months later...

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...