2020-05-26 02:09 AM
I'm working on a STM32H7B3I-DK with a 565 format frame buffer.
In my design, the Serial Flash that contents the ExtFlashSection in a standard project will not be memory mapped because I need part of it to record other data.
I followed the topics about caching bitmaps (https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/caching-bitmaps and https://support.touchgfx.com/docs/development/ui-development/scenarios/using-non-memory-mapped-flash )
In TouchGFX Designer, if I put the ’section’ part of the image to ExtFlashSection and the ‘Extra Section’ (e.g. the CLUT) in IntFlashSection everything is fine.
But if I try to put the ‘Extra Section’ in the ExtFlashSection the engine crashes on a HardFault because the library code tries to access directly the extra section in a memory mapped fashion.
Here is the state when hitting the HardFault exception
EXEC_RETURN (LR):
lr 0xffffffed -19
xPSR 0x21000000
ReturnAddress 0x8026bbe
LR (R14) 0x8026edb
R12 0x0
R3 0x1fe00
R2 0x14
R1 0x9001fe00
R0 0x80363d8
Return instruction:
0x8026bbe <_ZN8touchgfx6Bitmap15getSizeOfBitmapEt+198>: ldrb r0, [r1, #3]
LR instruction:
0x8026edb <_ZN8touchgfx6Bitmap5cacheEt+62>: mov r9, r0
I keep the linker file to have the ExtFlashSection mapped to 0x90000000 addresses so the data is loaded on debugger start but these addresses are not directly available at run time because the OSPI flash is not memory mapped as in a default TouchGfx project.
I put in bold the offending intsr/data in cpu trace. As you see, the R1 register holds the address of where is linked the _black_extra_data[] array (the CLUT of an image called ‘black’).
This fault happens before my overloaded blockCopy function is called.
Using the working linker map (with extra_ data section in internal flash), I verified that all images were copied to the cache by tracking the calls to my overloaded blockCopy function after a call to Bitmap::cacheAll() (both pixels and clut's are effectively copied to cache but this happen after the offending code !! )
Solved! Go to Solution.
2020-06-02 08:25 AM
More info ...
With original library , if I search in the archive the 'cacheAll' function, I get this :
arm-none-eabi-objdump -x libtouchgfx-float-abi-hard.a | grep cacheAll
24 .text._ZN8touchgfx6Bitmap8cacheAllEv 0000003c 00000000 00000000 00000bcc 2**2
48 .rodata._ZN8touchgfx6Bitmap8cacheAllEv.str1.1 0000002a 00000000 00000000 00001107 2**0
54 .rodata._ZZN8touchgfx6Bitmap8cacheAllEvE19__PRETTY_FUNCTION__ 00000029 00000000 00000000 000012a0 2**0
00000000 l d .rodata._ZN8touchgfx6Bitmap8cacheAllEv.str1.1 00000000 .rodata._ZN8touchgfx6Bitmap8cacheAllEv.str1.1
00000000 l d .rodata._ZZN8touchgfx6Bitmap8cacheAllEvE19__PRETTY_FUNCTION__ 00000000 .rodata._ZZN8touchgfx6Bitmap8cacheAllEvE19__PRETTY_FUNCTION__
00000000 l O .rodata._ZZN8touchgfx6Bitmap8cacheAllEvE19__PRETTY_FUNCTION__ 00000029 _ZZN8touchgfx6Bitmap8cacheAllEvE19__PRETTY_FUNCTION__
00000000 l d .text._ZN8touchgfx6Bitmap8cacheAllEv 00000000 .text._ZN8touchgfx6Bitmap8cacheAllEv
00000000 g F .text._ZN8touchgfx6Bitmap8cacheAllEv 0000003c _ZN8touchgfx6Bitmap8cacheAllEv
RELOCATION RECORDS FOR [.text._ZN8touchgfx6Bitmap8cacheAllEv]:
00000030 R_ARM_ABS32 .rodata._ZN8touchgfx6Bitmap8cacheAllEv.str1.1
00000034 R_ARM_ABS32 .rodata._ZZN8touchgfx6Bitmap8cacheAllEvE19__PRETTY_FUNCTION__
After replacing the Bitmap.o module, I get :
arm-none-eabi-objdump -x libtouchgfx-float-abi-hard.a | grep cacheAll
22 .text._ZN8touchgfx6Bitmap8cacheAllEv 0000003c 00000000 00000000 00000c10 2**2
45 .rodata._ZN8touchgfx6Bitmap8cacheAllEv.str1.1 0000002a 00000000 00000000 00001145 2**0
51 .rodata._ZZN8touchgfx6Bitmap8cacheAllEvE19__PRETTY_FUNCTION__ 00000029 00000000 00000000 000012de 2**0
There are clearly some differences, but I'm not an object format specialist :\
2020-06-02 11:14 AM
If it's easier i could just give you the entire lib (sounds like it is!).
/Martin
2020-06-02 12:56 PM
Well .....
Compiling with this lib I got plenty of messages like ..
arm-none-eabi/bin/ld: error: ch_stm32h7b3_touch.elf uses VFP register arguments, ... libtouchgfx-float-abi-hard.a(AbstractPartition.o) does not
This message repeats for all modules but not for the Bitmap.o ... looks like this lib has all objects compiled with soft float but the Bitmap.o is hard-float !!
So I extracted the Bitmap.o from the new library you just sent ... and replaced this Bitmap.o in the original 4.13.0 library and ... yessssssss it compiled ;)
And the Hard Fault disappeared
2020-06-02 02:54 PM
Yeah, sorry! I just realized that i forgot to do a clean build, and the .o files that were already built (some days ago) were apparently built with soft-float. I edited my previous post with a new lib, all built with hard-float
So no hard fault, great! And you're getting the clut read correctly?
/Martin
2020-06-02 03:10 PM
2020-06-02 11:55 PM
:thumbs_up:
This one is the good one !
No more HardFault and a correctly loaded L8_RGB565 bitmap , this case is closed ;)
Good job !
Thx,
Pierre
2020-06-03 12:12 AM
Thanks for reporting and helping test it! :)
/Martin
2020-06-04 07:40 AM
Hi PJEN.
Can describe how you implemented it, preferably share your relevant code, thanks.
2020-06-04 09:22 AM
Hi Skullboyer,
I followed the official doc about "Caching Bitmap" and "Using non memory mapped flash" as yo did.
The steps are :
Change the linker file so only the image data is going to external flash. here is my linker file (I'm using GCC !! )
Relevant parts are here :
Extract from my STM32H7A3.ld linker file :
...
MEMORY
{
flash0 (rx) : org = 0x08000000, len = 2M /* Flash bank1+bank2 */
.... (other memory regions come here .. but are not relevants)
gui (xrw) : ORIGIN = 0x90000000, LENGTH = 4M
}
...
FontFlashSection :
{
*(FontFlashSection FontFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >flash0
TextFlashSection :
{
*(TextFlashSection TextFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >flash0
IntFlashSection :
{
*(IntFlashSection IntFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >flash0
ExtFlashSection :
{
*(ExtFlashSection ExtFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >gui
In the MEMORY table, the flash0 section is the internal flash of my STM32H7 cpu, the gui section is where the image data will be addressed by the "BlockCopy" function
The other instructions tell the linker to put "FontFlashSection" , "TextFlashSection", and "IntFlashSection" inside the CPU flash (flash0 bank) and to put "ExtFlashSection " inside the gui bank (mapped from 0x90000000)
The names of these sections are referred to by TouchGFX Designer software and thats's how you tell the Designer where to put things.
You then go to touchGfx designer to tell where your image data are stored like in the screenshot below
You have to know that an image may be cut in two parts depending on its format. That's why you have 'Section' and 'Extra Section' (surrounded by red ellipse). The 'Section' part are the actual pixels of the image and it's the only used part if your image is a non indexed format (RGB888 , RGB565, ARGB8888 ...) , with these formats the 'Extra Section' is not needed to store the image. But, if your image has an indexed format (L8_RGB565, L8_RGB888 ) these formats need a CLUT (Colour lookup table with the 256 colours used in your image) .. and this CLUT is stored in the 'Extra Section'. In the screenshot my image is an indexed L8_RGB565 and I ask TouchGFX Designer to put both pixels and CLUT in 'ExtFlashSection' (The name of the section we find in the Linker file above)
If you compile the code generated with this configuration and the modified linker file and look at the map file searching the name of your image (In my case it's Vert256) you should find lines like this ...
ExtFlashSection
0x0000000090061018 0x1fed4 TouchGFX/generated/images/src/Vert256.o
0x0000000090061018 _vert256
0x0000000090080e18 _vert256_extra_data
That means that the two parts of the image are mapped at addresses above 0x90000000 (FYI _vert256 are the Pixels, _vert256_extra_data are the CLUT)
If you make this run on your target, the GFX engine will try to load your image accessing at adresses 0x90000000 by calling the TouchGFXGeneratedHAL::blockCopy() function ... The default implementation of this function HAL::blockCopy() will simply make a memcpy of your image data (@ 0x90000000 addresses) into a RAM buffer so it will only work if the 0x90000000 address range is available with direct access ... that's not the case with 'non memory mapped' memory so this will lead to a HardFault ... So we have to change the blockCopy function to handle this case
here is my implementation in target/generated/TouchGFXGeneratedHAL.cpp :
// This function is called whenever a bitmap is cached. Must copy a number of bytes from the (non-memory-mapped) source
// to the cache.
bool TouchGFXGeneratedHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes)
{
// If requested data is located within the memory block we have assigned for ExtFlashSection,
// provide an implementation for data copying.
uint32_t offset = (uint32_t) src;
if (offset >= 0x90000000 && offset < 0x91000000)
{
// Get image data from SNOR flash
offset -= 0x90000000;
flashDirectRead(offset, (uint8_t*) dest, numBytes);
return true;
}
else
{
// For all other addresses, just use the default implementation.
// This is important, as blockCopy is also used for other things in the core framework.
return HAL::blockCopy(dest, src, numBytes);
}
}
When blockCopy wants to get data from 0x90000000 and above we do not call the default 'memcpy like' default HAL-blockCopy but, instead, call a specific function to read the requested data from the external flash (in my case flashDirectRead() will do his job.) .. Of course, that supposes that the image data where stored in the external memory by some means before you run the program ;)
There is one thing left to say .... my example will not work with the official libtouchgfx.a but only with the one Martin built yesterday. That's because the official library has an issue with the copy of indexed images (the ones using CLUT's). To make my sample work you have to either not use indexed image format ... (RGB565 / RGB888) as those images will not access the 'extra data' section (You will not find the _vert256_extra_data in the map file) ... or ask touchGFX Designer to put this 'extra data' in a memory mapped area selecting 'IntFlashSection' in the combo 'Extra Section' of the image.
In this last case the map file should show something like :
ExtFlashSection
0x0000000090061018 0x1fe00 TouchGFX/generated/images/src/Vert256.o
0x0000000090061018 _vert256
...
IntFlashSection
0x000000000806ef4c 0xd4 TouchGFX/generated/images/src/Vert256.o
0x000000000806ef4c _vert256_extra_data
Showing that the extra part (the CLUT) is now placed in the Internal CPU Flash ans thus can be accessed directly by the library avoiding the HardFault
Hoping I did not forget something important ;)
2020-06-04 09:33 AM
... And I forgot something important ..... :grinning_face:
You have to register the Bitmap Cache in your Bitmap::registerBitmapDatabase( ...) call ... and somewhere in your code ,before to use the images, make a call to Bitmap::cacheAll(); to put the images in RAM