2021-06-07 04:22 AM
Hello everyone,
I'm currently developing a project using TouchGFX on a custom board with a STM32F469II and a 1024x600 screen in RGB interface.
Right now, I'm trying to add a SD card to the system so that eventually I'll be able to print pictures from it. If I understood the documentation correctly, this means adding a cache space in the external SDRAM where I could place images so that TouchGFX can interact with it with the dynamic bitmap functionnality.
The problem is that I cannot set up properly the cache space for TouchGFX. Here's what I'm doing in the TouchGFXHAL.cpp file :
#include <TouchGFXHAL.hpp>
/* USER CODE BEGIN TouchGFXHAL.cpp */
#include "stm32f4xx.h"
#include <cstdlib>
using namespace touchgfx;
namespace {
LOCATION_PRAGMA("BmpCacheSection")
uint16_t cache[1000000] LOCATION_ATTRIBUTE("BmpCacheSection");
}
void TouchGFXHAL::initialize()
{
// Calling parent implementation of initialize().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
// Please note, HAL::initialize() must be called to initialize the framework.
//TouchGFXGeneratedHAL::initialize();
HAL::initialize();
registerEventListener(*(Application::getInstance()));
setFrameBufferStartAddresses((void*)0xC0000000, (void*)0xC0200000, (void*)0xC0400000);
uint32_t cacheSize = sizeof(cache);
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cache, cacheSize, 4);
uint8_t* res = touchgfx::Bitmap::getCacheTopAddress();
}
And the cache section is defined like so in the linker :
/* Memories definition */
MEMORY
{
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
QUADSPI (r) : ORIGIN = 0x90000000, LENGTH = 8M
CACHE (rw) : ORIGIN = 0xC0600000, LENGTH = 2M
}
...
BmpCacheSection (NOLOAD) : { *(BmpCacheSection) } >CACHE
I plane to organize the external SDRAM of 8MB like so:
I should also mention that based on my screen's resolution, I should be able to input the second address as 0xC012C000 but If I put any lower than 0xC0200000 then the screen jitters for some reason.
However when I reach the line with the "setCache" function, the programs stops and the connection with the probe is lost without any other information. I've also tried setting up the cache like so:
uint16_t* cacheStartAddr = (uint16_t*)0xC0600000;
uint32_t cacheSize = 0x100000;
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cacheStartAddr, cacheSize, 4);
and using the following function:
HAL& touchgfx_generic_init(DMA_Interface& dma, LCD& display, TouchController& tc, int16_t width, int16_t height, uint16_t* bitmapCache, uint32_t bitmapCacheSize, uint32_t numberOfDynamicBitmaps = 0)
But nothing I did has worked so far.
How can I properly setup the cache ?
Tristan
2021-06-08 12:29 AM
Hello Tristan,
Have you tried without using the LOCATION_PRAGMA ? Removing it from the linker file and TouchGFXHAL.cpp. Do you have any other board to try and see if it works with another MCU ? Also can you try setting a cache in internal RAM to see if it works ?
/Alexandre
2021-06-08 05:26 AM
Hello Alexandre,
I've tried removing the line LOCATION_PRAGMA("BmpCacheSection") and the result is the same.
I've also tried removing the cache section from the linker file and TouchGFXHAL.cpp and the cache is now setup like so :
uint16_t cache[1000000];
uint32_t cacheSize = sizeof(cache);
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cache, cacheSize, 4);
uint8_t* res = touchgfx::Bitmap::getCacheTopAddress();
The program will not work and always goes into the hardFault_Handler since I belive there's not enough space to place a buffer this size in what I have defined in the linker.
Now if I setup a SDRAM space in the linker (for some reason, I didn't needed to do that for the frame buffer setup) like so:
/* Memories definition */
MEMORY
{
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
SDRAM (rw) : ORIGIN = 0xC0000000, LENGTH = 8M
QUADSPI (r) : ORIGIN = 0x90000000, LENGTH = 8M
}
...
BmpCacheSection (NOLOAD) : { *(BmpCacheSection) } >SDRAM
TouchGFX_Framebuffer (NOLOAD) : { *(TouchGFX_Framebuffer) } >SDRAM
TouchGFX_Framebuffer1 (NOLOAD) : { *(TouchGFX_Framebuffer1) } >SDRAM
TouchGFX_Framebuffer2 (NOLOAD) : { *(TouchGFX_Framebuffer2) } >SDRAM
The cache is now placed at the address 0xC0000000 which is the address of the first frame buffer. The result is nevertheless the same and the program stops and the connection with the ST-LINK is lost.
I also have a STM32F469II Discovery board which has an external RAM of 16MB and a screen with a resolution of 800x480. I added the following lines to the TouchGFXHAL.cpp file :
using namespace touchgfx;
namespace {
LOCATION_PRAGMA("BmpCacheSection")
uint16_t cache[100000] LOCATION_ATTRIBUTE("BmpCacheSection");
}
static CortexMMCUInstrumentation mcuInstr;
static KeySampler btnctrl;
void TouchGFXHAL::initialize()
{
GPIO::init();
// Calling parent implementation of initialize().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
// Please note, HAL::initialize() must be called to initialize the framework.
TouchGFXGeneratedHAL::initialize();
setFrameBufferStartAddresses((void*)0xC0000000, (void*)0, (void*)0xC00BB800);
lockDMAToFrontPorch(false);
mcuInstr.init();
setMCUInstrumentation(&mcuInstr);
enableMCULoadCalculation(true);
setButtonController(&btnctrl);
uint32_t cacheSize = sizeof(cache);
uint8_t* res = touchgfx::Bitmap::getCacheTopAddress();
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cache, cacheSize, 4);
res = touchgfx::Bitmap::getCacheTopAddress();
}
I've also setup the "CACHE" section just like before. In the dev board, the program goes past the line with the setCache() function and I able to use dynamic bitmap to create images over my screen.
I've also tested putting the cache in the internal RAM. According to the build information, I've got about 178 KB of unused space inside the internal RAM of my custom board which means that I sould be able to introduce a smaller buffer like so:
uint16_t cache[100];
uint32_t cacheSize = sizeof(cache);
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cache, cacheSize, 4);
uint8_t* res = touchgfx::Bitmap::getCacheTopAddress();
When defined like this, the cache is placed at 0x2004fef0 which is in the internal RAM section. When the cache is setup like so, the program goes from the setCache() function to __assert_func() then to abort() and finally to _exit() where it hangs forever.
To sum-up, while it works on the discovery board, I've yet to manage to make it work on my custom board even if I set up the cache the same way I did on the discovery board.
Tristan
2021-06-08 06:05 PM
Hello Tristan,
So there's must be a difference between your custom board and the STM32F469II Discovery board. That's a start !
Could you try to set the number of bitmaps to 1 but keeping the same cache size and see if you crash at setCache() ?
Comparing both code could help you find the issue too I think.
Unfortunately I don't have the perfect answer because I've only tried with a few ST boards and it works like a charm 😅
/Alexandre
2021-06-09 12:33 AM
Hello Alexandre,
I've tried changing the number of bitmaps in the function setCache() from 0 to 5 and each time the result is the same (crashing at setCache()).
Could you provide more information over the setCache() function (I do not have access to the source code). As an exemple, I've read the presentation at Caching Bitmaps | TouchGFX Documentation which both uses an adress or an array to define the cache space (so which one sould I use ?) and mention the file "BoardConfiguration.cpp" which doesn't seem to exist anymore. There's also the fact that in my case, I'm suppose to do this (accordinge to the previously mentionned doc):
void TouchGFXHAL::initialize()
{
/* Initialize TouchGFX Engine */
TouchGFXGeneratedHAL::initialize();
uint16_t* cacheStartAddr = (uint16_t*)0xC0008000;
uint32_t cacheSize = 0x300000; //3 MB, as example
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cache, sizeof(cache), 0);
}
But it does not show how to define "cache" only "cacheStartAddr" which it does not use.
Furthermore, the main difference I can spot between the project on the discovery board and on my custom board is the external RAM which is very different (not the same brand, not the same size,...). Is there size requierement for the external RAM to introduce a cache space inside ? Why do I have no issue placing the frame buffer inside but when I try to input a cache space it fails ?
Thanks in advance,
Tristan
2021-06-09 01:19 AM
Hi Tristan,
Yes cache is a wrong typo, I will tell the team to fix it. Here is an example of how I create my bitmap cache which is similar to you.
uint16_t* cacheStartAddr = (uint16_t*)0xC00BF400;
uint32_t cacheSize = 0x3FFFF;
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cacheStartAddr, cacheSize, 1);
The setCache() function simply updates the pointer of the cache start address, sets its size and clears the designated memory space.
The only size requirements is that the cache has to be big enough to store the number of bitmaps indicated in setCache(). An SDRAM of 8Mb is completely enough for caching bitmaps.
For the rest, I do not know because I haven't worked with your SDRAM. I'll do some investigation.
/Alexandre
2021-06-10 12:55 AM
Hi alexandre,
By following your example, I've manage to set up a cache space inside the internal RAM space like so:
void TouchGFXHAL::initialize()
{
// Calling parent implementation of initialize().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
// Please note, HAL::initialize() must be called to initialize the framework.
//TouchGFXGeneratedHAL::initialize();
HAL::initialize();
registerEventListener(*(Application::getInstance()));
setFrameBufferStartAddresses((void*)0xC0000000, (void*)0xC0200000, (void*)0xC0400000);
uint16_t* cacheStartAddr = (uint16_t*)0x20030000;
uint32_t cacheSize = 0x10000;
touchgfx::Bitmap::removeCache();
touchgfx::Bitmap::setCache(cacheStartAddr, cacheSize, 1);
}
I then could read my SD card and add images on my screen with the dynamic bitmap functionnality. Of course this workaround leaves me with a very small memory I can use to save images which thus will not work for my application since I need to input backgrounds from the SD card (with a resolution of 1024x600 and on 16 bits so this means about 1.2 MB of free space).
You say that "the cache has to be big enough to store the number of bitmaps indicated in setCache()" although I though that the size of each dynamic bitmap in the cache is inputed after the setup with the function Bitmap::dynamicBitmapCreate( ). How does the function determines the size needed for a certain number of bitmap ?
By the way, the external RAM I'm using is the IS42S16400J-7TLI which is a 1 Meg Bits x 16 Bits x 4 Banks (64-MBIT) synchronous dynamic RAM and with the 3 frame buffers i need, I should have about 2MB of free space for the bitmap cache.
Tristan
2021-06-10 01:32 AM
Hello Tristan,
I didn't say that the setCache() was determining anything. My sentence just implied that if you want to store 4 1024x600 16 bits bitmaps, you need to allocate enough memory. For a single bitmap 2M bytes are enough but not for storing 4 bitmaps for instance.
Good that now we know it works in internal RAM. So if it crashes only with external RAM, the problem was narrowed down. Is your 2MB of free space continuous ?
/Alexandre
2021-06-10 01:40 AM
Ok my bad. I actually would need to store a background and a small picture so 2 bitmaps in a 2 MB would be perfect.
Since the first 6 MB of my external RAM are occupied by the frame buffers, I would want to place it in the last remaining 2 MB so from the address 0xC0600000 to the end of the RAM at 0xC07FFFFF. I believe this space is thus continuous.
Tristan