Skip to main content
Associate III
May 26, 2020
Solved

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

  • May 26, 2020
  • 34 replies
  • 7057 views

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

This topic has been closed for replies.
Best answer by Martin KJELDSEN

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

34 replies

PJENAuthor
Associate III
June 2, 2020

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

Martin KJELDSEN
Principal III
June 2, 2020

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

/Martin

PJENAuthor
Associate III
June 2, 2020

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

Martin KJELDSEN
Principal III
June 2, 2020

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

PJENAuthor
Associate III
June 3, 2020

: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

Martin KJELDSEN
Principal III
June 3, 2020

Thanks for reporting and helping test it! :)

/Martin

PJENAuthor
Associate III
June 5, 2020

Hello,

I suspect that your problem is that the Bitmap::cacheAll() is called too early (before the initialisation process is done), you need to cache the Bitmap just before you use it .

First, in my case, the call to registerBitmapDatabase is done in the touchgfx_init() function found in target/generated/TouchGFXConfiguration.cpp (I'm not sure but I think that this call to registerBitmapDatabase is written by the Designer (without the parameters giving the bitmap cache memory !!) .Check this TouchGFXConfiguration.cpp file in your project and if the registerBitmapDatabase call is there, make the cache init there to not call registerBitmapDatabase() twice ).

Next, in my project the Bitmap::cacheAll() is called in the setupScreen() function of the start screen (it's called Splash in my project):

void SplashView::setupScreen()
{
 Bitmap::cacheAll();
 SplashViewBase::setupScreen();
}

I tried to move this 'cacheAll()' call in the initialisation code like you do and the program crashes !!

Cross the fingers ;)

skullboyer
Associate III
June 6, 2020

Hi PJEN,

I modified it as you said and it now displays the image, but there are still some problems!

My current project is composed of two screens, the start screen shows normal, the second screen shows abnormal, the specific display is as follows

0693W000001qBFeQAM.jpg

A normal display screen should look like this

0693W000001qBFjQAM.png

0693W000001qBFoQAM.png

And now TouchGFX Designer will report an error when running the project!

0693W000001qBFyQAM.png

PJENAuthor
Associate III
June 6, 2020

Hi,

For the simulator, the message seems clear ... there is no memory to cache the bitmaps.

The Simulator does not run exactly the same code as the target, you'll have to specify cache memory for the simulator run.

Modify the TouchGFX/simulator/main.cpp to something like that :

(See line 15 that declare a 4Mbytes cache area and line 36 that register this cache area )

#include <platform/hal/simulator/sdl2/HALSDL2.hpp>
#include <touchgfx/hal/NoDMA.hpp>
#include <common/TouchGFXInit.hpp>
#include <gui_generated/common/SimConstants.hpp>
#include <platform/driver/touch/SDL2TouchController.hpp>
#include <touchgfx/lcd/LCD.hpp>
#include <stdlib.h>
#include <simulator/mainBase.hpp>
 
#include <touchgfx/canvas_widget_renderer/CanvasWidgetRenderer.hpp>
#define CANVAS_BUFFER_SIZE (3600)
 
using namespace touchgfx;
 
uint16_t imageCache[4*1024*1024/2] ;
 
 
#ifdef __linux__
int main(int argc, char** argv)
{
#else
#include <shellapi.h>
#ifdef _UNICODE
#error Cannot run in unicode mode
#endif
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 int argc;
 char** argv = touchgfx::HALSDL2::getArgv(&argc);
#endif
 
 touchgfx::NoDMA dma; //For windows/linux, DMA transfers are simulated
 LCD& lcd = setupLCD();
 touchgfx::SDL2TouchController tc;
 
 touchgfx::HAL& hal = touchgfx::touchgfx_generic_init<touchgfx::HALSDL2>(dma, lcd, tc, SIM_WIDTH, SIM_HEIGHT,imageCache,sizeof(imageCache),10);
 
 setupSimulator(argc, argv, hal);
 
 // Ensure there is a console window to print to using printf() or
 // std::cout, and read from using e.g. fgets or std::cin.
 // Alternatively, instead of using printf(), always use
 // touchgfx_printf() which will ensure there is a console to write
 // to.
 //touchgfx_enable_stdio();
 
 // Setup the CanvasWidgetRenderer. ONLY needed if you use CanvasWidgets
 // in your application. The CANVAS_BUFFER_SIZE can be adjusted to match
 // your needs in performance vs. RAM usage. Read more on this in the
 // TouchGFX Manual.
 static uint8_t canvasBuffer[CANVAS_BUFFER_SIZE];
 touchgfx::CanvasWidgetRenderer::setupBuffer(canvasBuffer, CANVAS_BUFFER_SIZE);
 
 touchgfx::HAL::getInstance()->taskEntry(); //Never returns
 
 return EXIT_SUCCESS;
}

On the target, it's like some bitmaps where not correctly cached ... Check the size of the RAM you allocated for the cache ... Check the function that copy the Flash to the cache during BlockCopy ... verify that the images have been correctly stored in the external flash ...

skullboyer
Associate III
June 6, 2020

PJEN, Thank you very much for your patience in answering my questions.

I solved the simulator error problem with target board macros.

The image is not displaying fully, I checked the data reading interface and found that it's the spi reading that's having a slight problem.