Skip to main content
Associate II
November 22, 2024
Solved

STM32U599 Hard fault inside touchgfx::Application::draw(touchgfx::Rect&)

  • November 22, 2024
  • 1 reply
  • 1030 views

Hello,

I have successfully implemented a Touchgfx based UI app using cubeMX and freertos on the STM32U599 chip. This is a basic application with multiple screens, a number of components all in ARGB2222. I am now in the process of porting my app from FreeRTOS to the zephyr platform. I am able to initialize touchgfx and start the process.

Using gdb I verified the touch gfx process going through my first screen setup and invalidate it. But at some point in touchgfx::Application::draw(touchgfx::Rect&), a hard fault is produced.

I have two theories on how this could be happening:

1- Linker issues. At first zephyr was trying to allocate my UI elements where it saw fit. So I looked at the '.list' generated by cubeIDE to understand where my sections should be placed. Doing so I was able to put together the following linker sections and passed it to zephyr using cmake:

SECTION_PROLOGUE(TouchGFX_Framebuffer, (NOLOAD),)
{
 . = ALIGN(4);
 __TouchGFX_Framebuffer_start = .;
 KEEP(*("TouchGFX_Framebuffer"))
 __TouchGFX_Framebuffer_end = ALIGN(4);
} GROUP_DATA_LINK_IN(RAMABLE_REGION,ROMABLE_REGION) /*GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)*/

SECTION_PROLOGUE(FontFlashSection,,)
{
 . = ALIGN(4);
 __FontFlashSection_start = .;
 KEEP(*("FontFlashSection"))
 __FontFlashSection_end = ALIGN(4);
} GROUP_DATA_LINK_IN(ROMABLE_REGION, ROMABLE_REGION)


SECTION_PROLOGUE(FontSearchFlashSection,,)
{
 . = ALIGN(4);
 __FontSearchFlashSection_start = .;
 KEEP(*("FontSearchFlashSection"))
 __FontSearchFlashSection_end = ALIGN(4);
} GROUP_DATA_LINK_IN(ROMABLE_REGION, ROMABLE_REGION)

SECTION_PROLOGUE(FontSearchFlashSection,,)
{
 . = ALIGN(4);
 __FontSearchFlashSection_start = .;
 KEEP(*("FontSearchFlashSection"))
 __FontSearchFlashSection_end = ALIGN(4);
} GROUP_DATA_LINK_IN(ROMABLE_REGION, ROMABLE_REGION)

SECTION_PROLOGUE(TextFlashSection,,)
{
 . = ALIGN(4);
 __TextFlashSection_start = .;
 KEEP(*("TextFlashSection"))
 __TextFlashSection_end = ALIGN(4);
} GROUP_DATA_LINK_IN(ROMABLE_REGION, ROMABLE_REGION)

SECTION_PROLOGUE(ExtFlashSection,,)
{
 . = ALIGN(4);
 __ExtFlashSection_start = .;
 KEEP(*("ExtFlashSection"))
 __ExtFlashSection_end = ALIGN(4);
} GROUP_DATA_LINK_IN(ROMABLE_REGION, ROMABLE_REGION)

The following was part of the output of zephyr's compiled elf object dump. Notice how they get stored on flash and sram:

 Sections:
Idx Name Size VMA LMA File off Algn
 22 TouchGFX_Framebuffer 00012c00 20010a08 0808ded0 00052b98 2**2
 ALLOC
 23 FontFlashSection 00004bac 0808ded0 0808ded0 0004dfec 2**2
 CONTENTS, ALLOC, LOAD, READONLY, DATA
 24 FontSearchFlashSection 000004e8 08092a7c 08092a7c 00052b98 2**2
 CONTENTS, ALLOC, LOAD, READONLY, DATA
 25 FontSearchFlashSection 00000000 08092f64 08092f64 0006bc4c 2**0
 CONTENTS
 26 TextFlashSection 00000f3a 08092f64 08092f64 00053080 2**2
 CONTENTS, ALLOC, LOAD, READONLY, DATA
 27 ExtFlashSection 00017c8c 08093ea0 08093ea0 00053fbc 2**2
 CONTENTS, ALLOC, LOAD, READONLY, DATA

I chose the ramable regions and romable regions based on what cubeIDE produced. I'm wondering if this manual process of section definitions is where draw(touchgfx::Rect&) is failing?

 

2- Cache issues. My second hypothesis is that the ICACHE, DCACHE, and CRC are not working as expected. To address this issue, I used the functions inside HAL library to setup these peripherals manually as I did not find a way to have zephyr accomplish this for me. I defined the following functions directly from HAL:

static void DCACHE_Init(void)
{
 /************************ DCACHE 1 **************************/
 /* Set requested read burst type */
 MODIFY_REG(DCACHE1->CR, DCACHE_CR_HBURST, DCACHE_READ_BURST_WRAP);
 /* Enable the selected DCACHE peripheral */
 /* Check no ongoing operation */
 while (READ_BIT(DCACHE1->SR, (DCACHE_SR_BUSYF | DCACHE_SR_BUSYCMDF)) != 0U)
 {
 /* Return busy status */
 k_sleep(K_MSEC(1000));
 printk("display_interface: DCACHE1 busy.\r\n");
 }
 /* Enable the selected DCACHE peripheral */
 SET_BIT(DCACHE1->CR, DCACHE_CR_EN);

 /************************ DCACHE 2 **************************/
 /* Set requested read burst type */
 MODIFY_REG(DCACHE2->CR, DCACHE_CR_HBURST, DCACHE_READ_BURST_WRAP);
 /* Enable the selected DCACHE peripheral */
 /* Check no ongoing operation */
 while (READ_BIT(DCACHE2->SR, (DCACHE_SR_BUSYF | DCACHE_SR_BUSYCMDF)) != 0U)
 {
 /* Return busy status */
 k_sleep(K_MSEC(100));
 printk("display_interface: DCACHE2 busy.\r\n");
 }
 /* Enable the selected DCACHE peripheral */
 SET_BIT(DCACHE2->CR, DCACHE_CR_EN);
}

static void ICACHE_Init(void)
{
 /* Check cache is not enabled */
 while (READ_BIT(ICACHE->CR, ICACHE_CR_EN) != 0U)
 {
 /* Return busy status */
 k_sleep(K_MSEC(100));
 printk("display_interface: ICACHE busy.\r\ndisplay_interface: Disabling and reconfiguring ICACHE\r\n");
 /* Reset interrupt enable value */
 // WRITE_REG(ICACHE->IER, 0U);
 /* Clear any pending flags */
 // WRITE_REG(ICACHE->FCR, ICACHE_FCR_CBSYENDF | ICACHE_FCR_CERRF);

 /**** Disable cache then set default associative mode value ****/
 CLEAR_BIT(ICACHE->CR, ICACHE_CR_EN);
 WRITE_REG(ICACHE->CR, ICACHE_CR_WAYSEL);

 HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0);

 /* Peripheral interrupt init */
 /* ICACHE_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(ICACHE_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(ICACHE_IRQn);

 /* Stop monitor and reset monitor values */
 // CLEAR_BIT(ICACHE->CR, ICACHE_MONITOR_HIT_MISS);
 // SET_BIT(ICACHE->CR, (ICACHE_MONITOR_HIT_MISS << 2U));
 // CLEAR_BIT(ICACHE->CR, (ICACHE_MONITOR_HIT_MISS << 2U));
 /* Reset regions configuration values */
 // WRITE_REG(ICACHE->CRR0, ICACHE_REGIONSIZE_2MB << ICACHE_CRRx_RSIZE_Pos);
 // WRITE_REG(ICACHE->CRR1, ICACHE_REGIONSIZE_2MB << ICACHE_CRRx_RSIZE_Pos);
 // WRITE_REG(ICACHE->CRR2, ICACHE_REGIONSIZE_2MB << ICACHE_CRRx_RSIZE_Pos);
 // WRITE_REG(ICACHE->CRR3, ICACHE_REGIONSIZE_2MB << ICACHE_CRRx_RSIZE_Pos);
 }
 MODIFY_REG(ICACHE->CR, ICACHE_CR_WAYSEL, ICACHE_1WAY);
 SET_BIT(ICACHE->CR, ICACHE_CR_EN);
}

static void CRC_Init(void)
{
 printk("display_interface: CRC Init.\r\n");
 SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_CRCEN);
 /* initialize peripheral with default generating polynomial */
 WRITE_REG(CRC->POL, DEFAULT_CRC32_POLY);
 MODIFY_REG(CRC->CR, CRC_CR_POLYSIZE, CRC_POLYLENGTH_32B);
 /* set default CRC initial value */
 WRITE_REG(CRC->INIT, DEFAULT_CRC_INITVALUE);
 /* set input data inversion mode */
 MODIFY_REG(CRC->CR, CRC_CR_REV_IN, CRC_INPUTDATA_INVERSION_NONE);
 /* set output data inversion mode */
 MODIFY_REG(CRC->CR, CRC_CR_REV_OUT, CRC_OUTPUTDATA_INVERSION_DISABLE);
}

 the execution order after kernel initialization is: 

  1. DCACHE init
  2. ICACHE init
  3. CRC init
  4. TouchGFX init
  5. signalvsync
  6. TOUCHGFX process

Given all of this information, how can I find out what is causing drawCachedAreas() to fail? I believe I am very close to getting touch gfx to work on the zephyr project, I am probably not configuring some peripheral that touchgfx needs. Any help would appreciated.

Best answer by bornamm

UPDATE:

Adjusting stack and heap memory size using zephyr k_configs fixed the issue.

1 reply

bornammAuthorBest answer
Associate II
November 23, 2024

UPDATE:

Adjusting stack and heap memory size using zephyr k_configs fixed the issue.