Jump to content

File from extneral SPI flash


Hilco

Recommended Posts

Hello,

I want to store my pictures on an external SPI-flash memory, because the flash of the microcontroller is to small.
 

At the moment I store them in raw format, containing no more then pixeldata, no header at all.
In the application I know for each picture what the length, width and hight is and what the offset is in the SPI-flashmemory.

I have written a function which uses DMA to read from the SPI-flash,
I use double buffering to read a complete image as quick as possible from the SPI-flash.
One buffer is filled with DMA, while the other is used to write with bitbanging to an ILI9341 with parallel interface.

I have added a  gdisp_lld_blit_area  function in the gdisp_lld_ILI9341.c file, and call the function described above.

But know I'm stuck at how to use the uGFX library correct to pass picture-information so that the GDisplay struct is filled the correct way with x-size , y-size etc.

What is the best way to continue?

Kind Regards,

Hilco

 

Link to comment
Share on other sites

Hello @Hilco and welcome to the µGFX community.

The easiest way is to use the NATIVE GDISP image format that already exists. It is a format that we created to support exactly your use case. However, unlike just having the pixel data the image format stores the width and height as well. The overhead is just 8 bytes for the entire header. It's documented here: https://wiki.ugfx.io/index.php/Images#NATIVE
So if you use that format to store your images on the external SPI Flash you can easily load and display them using existing GFILE and GDISP API.

If that doesn't suite your needs you'll have to implement your own GDISP image handler. The existing one will serve as examples.

/* The structure defining the routines for image drawing */
typedef struct gdispImageHandlers {
	gdispImageError	(*open)(gdispImage *img);					/* The open function */
	void			(*close)(gdispImage *img);					/* The close function */
	gdispImageError	(*cache)(gdispImage *img);					/* The cache function */
	gdispImageError	(*draw)(GDisplay *g,
							gdispImage *img,
							coord_t x, coord_t y,
							coord_t cx, coord_t cy,
							coord_t sx, coord_t sy);			/* The draw function */
	delaytime_t		(*next)(gdispImage *img);					/* The next frame function */
	uint16_t		(*getPaletteSize)(gdispImage *img);			/* Retrieve the size of the palette (number of entries) */
	color_t			(*getPalette)(gdispImage *img, uint16_t index);							/* Retrieve a specific color value of the palette */
	bool_t			(*adjustPalette)(gdispImage *img, uint16_t index, color_t newColor);	/* Replace a color value in the palette */
} gdispImageHandlers;

 

Link to comment
Share on other sites

If you are adding a blit call to the driver you need to turn its use on using the define in the gdisp_lld_config.h

You would then use the gdispBlit function to send information to the driver to end up in that call.

Note that while you can do it that way you must remember that uGFX can use the gdispBlit function and will expect it to work in the normal fashion. If you are changing the meaning of any of the parameters including the image pointer then you are not going to get what you want.

Note the gdispBlit functions are fairly efficient for the ILI9341 so it is unlikely that you will see a huge improvement in performance over the standard driver provided you have the portion of the image being blitted already in RAM.

@Joel Bodenmann approach above is probably the best way to handle it without having to make custom changes to the driver. Another way without making custom changes is to use the following strategy...

1. Load a block into buffer 1 using dma

2. Start the next block dma loading into buffer 2

3. GdispBitBlit the first block

4. Wait for buffer 2 to complete

5. Start the load of the next block to buffer 1

6. GdispBitBlit the 2nd buffer

7. Wait for buffer 1 to complete

8. Repeat from step 2.

In all cases adding a bitBlit acceleration routine to the driver is likely to give little value.  If you do add it make sure it operates in the standard manner or you will cause yourself a lot of unnecessary drama.

If you really want your own special driver routines that operates in a non standard way the correct approach is to add it as a gdispControl command.

Link to comment
Share on other sites

Note that using the proper GDISP image approach by either modifying your SPI flash content format to match the existing NATIVE image format or by implementing your own you get a few benefits such as the fact that you'll be able to display your images within a GWIN imagebox widget and you could optionally implement caching. Manually blitting the pixel contents means that you loose the added value of having a concept of an image object. There are other benefits as well such as the ability to modify the palettes, background colors and so on - all stuff that already exists in GDISP image.

Link to comment
Share on other sites

Thanks Joel and Inmarket for the quick reply,

I already had taken a look into the NATIVE image format, it looks like a good option for me.
I also had already played with in ROMFS
Putting the NATIVE image format on my SPI-Flash is no big deal

But do I need a file-system like FATFS for reading from the SPI-FLASH.
I know I can add FATFS with Cube-MX, (I am using an STM-32) but in my opinion it is a little overkill, and not to mention it needs precious microcontroller flash.

I was thinking to use the USERFS, and make a simple file-system. Is there an example for that?

 

@Inmarket,
I think the GdispBitBlit  is a good option for me.
What I already did was adding the   #define GDISP_HARDWARE_BITFILLS                TRUE 
and I looked into the example from the driver of the STM32LTDC, "gdisp_lld_STM32LTDC.c" where also a gdisp_lld_blit_area routine is used.
I used that example as a startingpoint for my own implemtation in the "gdisp_lld_ILI9341.c"

 

Kind regards,

Hilco

 

Link to comment
Share on other sites

You do not have to use FatFS to load your NATIVE image. It's correct that the GDISP module provides a function to open an image from a file but you're not forced to use that. You can also use gdispImageOpenMemory() which allows you to open an image from any memory location. However, that won't be as easy if you image is not in your main memory. Note that a gdispImage object is comprised of a pointer to a GFILE object. Using a file system one way or another is therefore a must have. But whether you use something very small such as ROMFS or a custom file system (USERFS) or something big and complex such as FatFS is completely up to you.

USERFS allows you to implement your own file system. You can do pretty much anything you want that way and still use the high-level API such as gdispImageOpenFile(). Whether or not that's a good option depends on your goals and experience.
Examples exist in form of the already implemented file systems. USERFS really just exposes the existing GFILE abstraction interface. Here's all the information you need: https://wiki.ugfx.io/index.php/USERFS

Link to comment
Share on other sites

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...