cancel
Showing results for 
Search instead for 
Did you mean: 

How to solve HardFault exception loading L8 images from non memory mapped flash

PJEN
Associate III

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 !! ) 

34 REPLIES 34
PJEN
Associate III

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 :\

If it's easier i could just give you the entire lib (sounds like it is!).

/Martin

PJEN
Associate III

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

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

This library calls blockCopy() before reading the CLUT for L8 images.

PJEN
Associate III

👍

This one is the good one !

No more HardFault and a correctly loaded L8_RGB565 bitmap , this case is closed 😉

Good job !

Thx,

Pierre

Thanks for reporting and helping test it! 🙂

/Martin

Hi PJEN.

Can describe how you implemented it, preferably share your relevant code, thanks.

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

0693W000001q4GkQAI.png

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 😉

... And I forgot something important ..... 😀

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