Hilco Posted October 5, 2017 Report Posted October 5, 2017 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
Joel Bodenmann Posted October 5, 2017 Report Posted October 5, 2017 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;
inmarket Posted October 5, 2017 Report Posted October 5, 2017 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.
Joel Bodenmann Posted October 6, 2017 Report Posted October 6, 2017 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.
Hilco Posted October 6, 2017 Author Report Posted October 6, 2017 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
inmarket Posted October 6, 2017 Report Posted October 6, 2017 Note you don't need a driver bitblit routine for the gdispBitBlit to work. In the case of the ILI9341 a driver bitblit routine would not add much speed as uGFX uses the windowing commands to implement the high kevel bitblit routine.
Joel Bodenmann Posted October 6, 2017 Report Posted October 6, 2017 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
Hilco Posted October 6, 2017 Author Report Posted October 6, 2017 Thanks for the quick reply, I will look at it what's best for me. I have another question regarding code-size. I will open a new topic about that. Kind regards, Hilco
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