Skip to main content
LCE
Principal II
June 9, 2026
Question

H7: DTCM variables strange behaviour

  • June 9, 2026
  • 12 replies
  • 78 views

Heyho,

H723..H735, using DTCM a lot, also ITCM for some functions.

Recently I found some strange behaviour:

  • the global pointer sFlashIntCtl.pu8WrBuf to the buffer u8FlashIntPageBuf (global) is set in function A
    • setting the pointer is working, printf via UART
  • later on function A calls function B
    • pointer sFlashIntCtl.pu8WrBuf is not changed anywhere, no IRQ or anywhere
  • first thing function B is doing:
    • check if pointer sFlashIntCtl.pu8WrBuf != NULL
    • check fails, because sFlashIntCtl.pu8WrBuf = 0 (checked via UART, see below)

Here’s the UART output:

function A UART output:

*** start *** wr SPI flash to APP flash

&u8FlashIntPageBuf[0] 20000800
sFlashIntCtl.pu8WrBuf 20000800 <- this OKAY
sOspiFlashCtl.pu8RdBuf 20000800
sFlashIntCtl.u32WrAddr 08040000
sFlashIntCtl.u32ChkAddr 08040000
sOspiFlashCtl.u32RdAddr 00000100
sOspiFlashCtl.u32RdLen 32

...
function A calls function B


function B UART output:

#E FlashIntWrPage(): pu8WrBuf = NULL

sFlashIntCtl.pu8WrBuf 00000000 <- WTF ?
&u8FlashIntPageBuf[0] 20000800

 

Any ideas?

12 replies

LCE
LCEAuthor
Principal II
June 9, 2026

This must be something really stupid…

And it does not matter if the variables are in DTCM or AXI RAM.

sFlashIntCtl.u32WrAddr is also somehow = 0 in function B, although it is set to 0x08040000 in A (as seen above in UART output).

 

mƎALLEm
ST Technical Moderator
June 9, 2026
  • pointer sFlashIntCtl.pu8WrBuf is not changed anywhere, no IRQ or anywhere

 

You need to double check this.. You can suppose it was not modified elsewhere in your code but it does ;).

Make a search with the keyword sFlashIntCtl.pu8WrBuf,

Otherwise it could be something else modifying it. ex: a DMA overwriting that area?

Do step by step debug and use the Memory view and see when it is changing.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
LCE
LCEAuthor
Principal II
June 9, 2026

Thanks for the reply!

Believe me before coming here I did search …

And it can’t be DMA, because DMA cannot access DTCM on H723.

Debug: I tried, but for these variables the display in CubeIDE had some problems: 

                 sFlashIntCtl.pu8WrBuf: 0x80000 <error: Cannot access memory at address 0x80000>

I’ll try that again.

mƎALLEm
ST Technical Moderator
June 9, 2026

   sFlashIntCtl.pu8WrBuf: 0x80000 <error: Cannot access memory at address 0x80000>

Address at 0x80000 ?

 

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
LCE
LCEAuthor
Principal II
June 9, 2026

Here’s an extract of function A, which sets things up then calls function B = FlashIntWrPage

	/* +++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* write from SPI flash to internal application flash */
case FLINT_STATE_WRITE:
{
/* check state of transfer from SPI flash to internal application flash
* read from SPI flash to buffer and start flash writing
*/
/* check written length */
if( sFlashIntCtl.u32WrBtDone < sSpiFileInfo.u32Size )
{
/* set start variables */
if( 0 == sFlashIntCtl.u32WrBtDone )
{
#if DEBUG_FLASH_INT
UartDbgTxString("FLINT_STATE_WRITE\n\r");
UartDbgTxString("*** start *** wr SPI flash to APP flash\n\r");
#endif /* DEBUG_FLASH_INT */

/* internal flash - WRITE settings */
sFlashIntCtl.u32Errors = 0;
sFlashIntCtl.pu8WrBuf = (uint8_t *)&u8FlashIntPageBuf[0];
sFlashIntCtl.u32WrLen = FLASH_INT_SIZE_PAGE;
sFlashIntCtl.u32WrAddr = FLASH_INT_ADDR_START_APP;
sFlashIntCtl.u32ChkAddr = FLASH_INT_ADDR_START_APP;

/* SPI flash - READ settings */
sOspiFlashCtl.u32RdLen = FLASH_INT_SIZE_PAGE;
sOspiFlashCtl.u32RdAddr = sFlashIntCtl.u32SpiAddr + OCTOSPI_FILE_BUF_OFFSET;
sOspiFlashCtl.pu8RdBuf = (uint8_t *)&u8FlashIntPageBuf[0];

#if DEBUG_FLASH_INT
uart_printf("&u8FlashIntPageBuf[0] %08lX\n\r", (uint32_t)&u8FlashIntPageBuf[0]);
uart_printf("sFlashIntCtl.pu8WrBuf %08lX\n\r", (uint32_t)sFlashIntCtl.pu8WrBuf);
uart_printf("sOspiFlashCtl.pu8RdBuf %08lX\n\r", (uint32_t)sOspiFlashCtl.pu8RdBuf);
uart_printf("sFlashIntCtl.u32WrAddr %08lX\n\r", sFlashIntCtl.u32WrAddr);
uart_printf("sFlashIntCtl.u32ChkAddr %08lX\n\r", sFlashIntCtl.u32ChkAddr);
uart_printf("sOspiFlashCtl.u32RdAddr %08lX\n\r", sOspiFlashCtl.u32RdAddr);
uart_printf("sOspiFlashCtl.u32RdLen %lu\n\r", sOspiFlashCtl.u32RdLen);
u32TickStrtFI = HAL_GetTick();
dflRtcSecStrt = dflTimeRTCtoSec();
#endif /* DEBUG_FLASH_INT */
}
/* or increment / set */
else
{
/* internal flash - WRITE settings */
sFlashIntCtl.pu8WrBuf = (uint8_t *)&u8FlashIntPageBuf[0];
sFlashIntCtl.u32WrLen = FLASH_INT_SIZE_PAGE;
sFlashIntCtl.u32WrAddr += FLASH_INT_SIZE_PAGE;
sFlashIntCtl.u32ChkAddr += FLASH_INT_SIZE_PAGE;
/* SPI flash - READ settings */
sOspiFlashCtl.u32RdLen = FLASH_INT_SIZE_PAGE;
sOspiFlashCtl.u32RdAddr += FLASH_INT_SIZE_PAGE;
sOspiFlashCtl.pu8RdBuf = (uint8_t *)&u8FlashIntPageBuf[0];
}

/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* read from SPI flash
* BLOCKING &
* ### outside of state machine ###
*/
sOspiFlashCtl.u8RdActive = 1;
sFlashIntCtl.u8WrError = OspiFlashRdPage();
__DMB();
__DSB();
sOspiFlashCtl.u8RdActive = 0;

if( sFlashIntCtl.u8WrError != HAL_OK )
{
#if DEBUG_FLASH_INT_ERR
UartDbgTxString(SZC_TEXT_ERR "FLINT_STATE_WRITE OspiFlashRdPage()\n\r");
#endif /* DEBUG_FLASH_INT_ERR */
u8FlashIntState = FLINT_STATE_ERROR;
}
else
{
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* trigger internal flash page WRITING */
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

/* get time */
sFlashIntCtl.u32TckStrt = HAL_GetTick();

/* write start */
sFlashIntCtl.u8WrActive = 1;
sFlashIntCtl.u8WrError = FlashIntWrPage(FLASH_INT_WRITE_BLOCK);

And here’s function B = FlashIntWrPage
 

#define FLINT_WRPAGE_USE_POINTER		1

__ATT_NO_OPTIM
#if ITCM_RAM_FUNC_FLINT
__ATT_SECT_ITCM_FUNC
#endif
uint8_t FlashIntWrPage(uint8_t u8WrBlock)
{
volatile uint8_t u8RetVal = 0;

#if FLINT_WRPAGE_USE_POINTER
/* check source pointer */
if( NULL == sFlashIntCtl.pu8WrBuf )
{
#if DEBUG_FLASH_INT_ERR
UartDbgTxString(SZC_TEXT_ERR "FlashIntWrPage(): pu8WrBuf = NULL\n\r");
uart_printf("sFlashIntCtl.pu8WrBuf %08lX\n\r", (uint32_t)sFlashIntCtl.pu8WrBuf);
uart_printf("&u8FlashIntPageBuf[0] %08lX\n\r", (uint32_t)&u8FlashIntPageBuf[0]);
#endif /* DEBUG_FLASH_INT_ERR */
return HAL_ERROR;
}
#endif /* FLINT_WRPAGE_USE_POINTER */

/* check flash destination address */
if( (sFlashIntCtl.u32WrAddr < (uint32_t)FLASH_INT_ADDR_START_APP) ||
(sFlashIntCtl.u32WrAddr >= (uint32_t)FLASH_INT_ADDR_END_APP) )
{
#if DEBUG_FLASH_INT_ERR
uart_printf(SZC_TEXT_ERR "FlashIntWrPage(): u32WrAddr out of range = %08lX\n\r", sFlashIntCtl.u32WrAddr);
#endif /* DEBUG_FLASH_INT_ERR */
return HAL_ERROR;
}

...

 

Strange color coding… 

mƎALLEm
ST Technical Moderator
June 9, 2026

@LCE 

As I said need to double check in all of your code “sFlashIntCtl.pu8WrBuf”. Sometimes we are sure about something while it’s not true in the reality.

Otherwise it could be something else modifying it. ex: a DMA overwriting that area?

Do step by step debug and use the Memory view and see when it is changing.

 

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
TDK
June 9, 2026

Writing to FLASH does not change what is in DTCM.

Set a hardware watchpoint. It will break when the memory is changed. Then you will see where the bug is.

"If you feel a post has answered your question, please click ""Accept as Solution""."
LCE
LCEAuthor
Principal II
June 9, 2026

different kind of wrong now, CubeIDE Debug vs UART 

 

LCE
LCEAuthor
Principal II
June 9, 2026

The variables are changed in the function that reads SPI flash to buffer u8FlashIntPageBuf, to which sFlashIntCtl.pu8WrBuf is pointing.

I don’t get this, esp. because it worked some time ago. Have to check old sources...

LCE
LCEAuthor
Principal II
June 10, 2026

More info:

the H7 internal flash is updated from an external quad SPI flash connected to OCTOSPI.

In the update control function’s “flash write loop” (after internal flash was erased), all pointers and addresses
are set before reading from OCTOSPI (= “OSPI”) and writing to internal flash:

  • write int. flash settings:
    • sFlashIntCtl.pu8WrBuf: pointer for data to write to int. flash, pointing to u8FlashIntPageBuf[0]
    • sFlashIntCtl.u32WrLen: int. flash page size
    • sFlashIntCtl.u32WrAddr: int. flash address to write to, starts at 0x08040000, incremented by page size
  • read OSPI settings:
    • sOspiFlashCtl.pu8RdBuf: pointer to buffer for data from OSPI, pointing to u8FlashIntPageBuf[0]
    • sOspiFlashCtl.u32RdLen: read length from OSPI
    • sOspiFlashCtl.u32RdAddr: read address for OSPI flash

Then new data (32 bytes = flash page size) is read from OSPI flash
with the function “uint8_t OspiFlashRdPage(void)”.
This handles all the OSPI commands and fills a global byte buffer via the pointer “sOspiFlashCtl.pu8RdBuf”,
which is pointing to “uint8_t u8FlashIntPageBuf[FLASH_INT_SIZE_PAGE]”.
The pointer sOspiFlashCtl.pu8RdBuf for the read buffer is set before calling OspiFlashRdPage().

After reading from OCTOSPI, the buffer is written to internal flash.

 

Observation (with hardware watchpoints, thanks to ​@TDK ):

In the OSPI read function “OspiFlashRdPage()” the unrelated global struct variables “sFlashIntCtl.pu8WrBuf” and “sFlashIntCtl.u32WrAddr” are changed within the read from OSPI loop:

uint8_t OspiFlashRdPage(void)
{
setup checks
...
/* +++++++++++++++++++++++++++++++++++++++++++ */
/* trigger command & reading */

/* get data via pointer for byte cast */
uint32_t *pu32DataReg = (uint32_t *)&pOspiFlash->DR;

/* reset number of received bytes */
sOspiFlashCtl.u32RdRcvd = 0;

/* CR: functional mode = 01 = indirect READ */
pOspiFlash->CR = OSPI_FLASH_CR_EN_IREAD;
/* trigger transfer by writing address register */
pOspiFlash->AR = sOspiFlashCtl.u32RdAddr;

for( uint32_t i = 0; i < OSPI_FLASH_PAGE_SIZE; i++ )
{
/* timeout ? */
if( OspiFlashWaitFlagSetTo((OCTOSPI_SR_FTF | OCTOSPI_SR_TCF), OSPI_FLASH_TO_RDBT_MS) )
{
u8RetVal++;
break;
}
else
{
/* get data from flash */
sOspiFlashCtl.pu8RdBuf[i] = *((uint8_t *)pu32DataReg);
sOspiFlashCtl.u32RdRcvd++; ###### HERE the sFlashIntCtl. variables are changed
}
}
...

 What’s going on there?

I checked the DTCM addresses of the structs sFlashIntCtl and sOspiFlashCtl, there’s no overlap or stuff. 

Now checking list and map files… and I find that I lack knowledge of ARM assembler… 😶

In the list file, in the OSPI read function “OspiFlashRdPage()” I don’t see any use of data in the area of the sFlashIntCtl struct, which is in DTCM at address 0x20000820.

from list file:

0000340a <OspiFlashRdPage>:
{
340a: b580 push {r7, lr}
340c: b084 sub sp, #16
340e: af00 add r7, sp, #0
uint8_t u8RetVal = 0;
3410: 2300 movs r3, #0
3412: 73fb strb r3, [r7, #15]
if( NULL == sOspiFlashCtl.pu8RdBuf )
3414: 4b67 ldr r3, [pc, #412] ; (35b4 <OspiFlashRdPage+0x1aa>)
3416: 691b ldr r3, [r3, #16]
3418: 2b00 cmp r3, #0
341a: d104 bne.n 3426 <OspiFlashRdPage+0x1c>
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): pu8RdBuf = NULL\n\r");
341c: 4866 ldr r0, [pc, #408] ; (35b8 <OspiFlashRdPage+0x1ae>)
341e: f001 f9c3 bl 47a8 <__printf_veneer>
return HAL_ERROR;
3422: 2301 movs r3, #1
3424: e0c2 b.n 35ac <OspiFlashRdPage+0x1a2>
if( (0 == sOspiFlashCtl.u32RdLen) ||
3426: 4b63 ldr r3, [pc, #396] ; (35b4 <OspiFlashRdPage+0x1aa>)
3428: 689b ldr r3, [r3, #8]
342a: 2b00 cmp r3, #0
342c: d004 beq.n 3438 <OspiFlashRdPage+0x2e>
(sOspiFlashCtl.u32RdLen > OSPI_FLASH_PAGE_SIZE) )
342e: 4b61 ldr r3, [pc, #388] ; (35b4 <OspiFlashRdPage+0x1aa>)
3430: 689b ldr r3, [r3, #8]
if( (0 == sOspiFlashCtl.u32RdLen) ||
3432: f5b3 7f80 cmp.w r3, #256 ; 0x100
3436: d904 bls.n 3442 <OspiFlashRdPage+0x38>
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): u32RdLen out of range\n\r");
3438: 4860 ldr r0, [pc, #384] ; (35bc <OspiFlashRdPage+0x1b2>)
343a: f001 f9b5 bl 47a8 <__printf_veneer>
return HAL_ERROR;
343e: 2301 movs r3, #1
3440: e0b4 b.n 35ac <OspiFlashRdPage+0x1a2>
if( OspiFlashCheckSrWip() != 0 )
3442: f7ff fb99 bl 2b78 <OspiFlashCheckSrWip>
3446: 4603 mov r3, r0
3448: 2b00 cmp r3, #0
344a: d004 beq.n 3456 <OspiFlashRdPage+0x4c>
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): WIP\n\r");
344c: 485c ldr r0, [pc, #368] ; (35c0 <OspiFlashRdPage+0x1b6>)
344e: f001 f9ab bl 47a8 <__printf_veneer>
return HAL_ERROR;
3452: 2301 movs r3, #1
3454: e0aa b.n 35ac <OspiFlashRdPage+0x1a2>
if( (OSPIFLSH_MODE_SPI != u8OspiFlashMode) &&
3456: 4b5b ldr r3, [pc, #364] ; (35c4 <OspiFlashRdPage+0x1ba>)
3458: 781b ldrb r3, [r3, #0]
345a: 2b00 cmp r3, #0
345c: d008 beq.n 3470 <OspiFlashRdPage+0x66>
(OSPIFLSH_MODE_MULT != u8OspiFlashMode) )
345e: 4b59 ldr r3, [pc, #356] ; (35c4 <OspiFlashRdPage+0x1ba>)
3460: 781b ldrb r3, [r3, #0]
if( (OSPIFLSH_MODE_SPI != u8OspiFlashMode) &&
3462: 2b01 cmp r3, #1
3464: d004 beq.n 3470 <OspiFlashRdPage+0x66>
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): not in SPI or MULT mode\n\r");
3466: 4858 ldr r0, [pc, #352] ; (35c8 <OspiFlashRdPage+0x1be>)
3468: f001 f99e bl 47a8 <__printf_veneer>
return HAL_ERROR;
346c: 2301 movs r3, #1
346e: e09d b.n 35ac <OspiFlashRdPage+0x1a2>
if( OspiFlashCheckBusyTo(OSPI_FLASH_TO_BUSY_MS) != HAL_OK )
3470: 2019 movs r0, #25
3472: f000 f9c7 bl 3804 <OspiFlashCheckBusyTo>
3476: 4603 mov r3, r0
3478: 2b00 cmp r3, #0
347a: d004 beq.n 3486 <OspiFlashRdPage+0x7c>
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): OCTOSPI_SR_BUSY\n\r");
347c: 4853 ldr r0, [pc, #332] ; (35cc <OspiFlashRdPage+0x1c2>)
347e: f001 f993 bl 47a8 <__printf_veneer>
return HAL_ERROR;
3482: 2301 movs r3, #1
3484: e092 b.n 35ac <OspiFlashRdPage+0x1a2>
pOspiFlash->CR = OSPI_FLASH_CR_EN_IWRITE;
3486: 4b52 ldr r3, [pc, #328] ; (35d0 <OspiFlashRdPage+0x1c6>)
3488: 681b ldr r3, [r3, #0]
348a: f240 3201 movw r2, #769 ; 0x301
348e: 601a str r2, [r3, #0]
pOspiFlash->DLR = (sOspiFlashCtl.u32RdLen - 1);
3490: 4b48 ldr r3, [pc, #288] ; (35b4 <OspiFlashRdPage+0x1aa>)
3492: 689a ldr r2, [r3, #8]
3494: 4b4e ldr r3, [pc, #312] ; (35d0 <OspiFlashRdPage+0x1c6>)
3496: 681b ldr r3, [r3, #0]
3498: 3a01 subs r2, #1
349a: 641a str r2, [r3, #64] ; 0x40
if( OSPIFLSH_MODE_SPI == u8OspiFlashMode )
349c: 4b49 ldr r3, [pc, #292] ; (35c4 <OspiFlashRdPage+0x1ba>)
349e: 781b ldrb r3, [r3, #0]
34a0: 2b00 cmp r3, #0
34a2: d10f bne.n 34c4 <OspiFlashRdPage+0xba>
pOspiFlash->TCR = OSPI_FLASH_TCR_SPI_STR_RDF;
34a4: 4b4a ldr r3, [pc, #296] ; (35d0 <OspiFlashRdPage+0x1c6>)
34a6: 681b ldr r3, [r3, #0]
34a8: 2208 movs r2, #8
34aa: f8c3 2108 str.w r2, [r3, #264] ; 0x108
pOspiFlash->CCR = OSPI_FLASH_CCR_SPI_STR_D1A32I8;
34ae: 4b48 ldr r3, [pc, #288] ; (35d0 <OspiFlashRdPage+0x1c6>)
34b0: 681b ldr r3, [r3, #0]
34b2: 4a48 ldr r2, [pc, #288] ; (35d4 <OspiFlashRdPage+0x1ca>)
34b4: f8c3 2100 str.w r2, [r3, #256] ; 0x100
pOspiFlash->IR = OSPI_FLASH_CMD_SPI_RD_DATF_4BA;
34b8: 4b45 ldr r3, [pc, #276] ; (35d0 <OspiFlashRdPage+0x1c6>)
34ba: 681b ldr r3, [r3, #0]
34bc: 220c movs r2, #12
34be: f8c3 2110 str.w r2, [r3, #272] ; 0x110
34c2: e018 b.n 34f6 <OspiFlashRdPage+0xec>
else if( OSPIFLSH_MODE_MULT == u8OspiFlashMode )
34c4: 4b3f ldr r3, [pc, #252] ; (35c4 <OspiFlashRdPage+0x1ba>)
34c6: 781b ldrb r3, [r3, #0]
34c8: 2b01 cmp r3, #1
34ca: d10f bne.n 34ec <OspiFlashRdPage+0xe2>
pOspiFlash->TCR = OSPI_FLASH_TCR_QUAD_STR_RD_DAT + 2;
34cc: 4b40 ldr r3, [pc, #256] ; (35d0 <OspiFlashRdPage+0x1c6>)
34ce: 681b ldr r3, [r3, #0]
34d0: 220a movs r2, #10
34d2: f8c3 2108 str.w r2, [r3, #264] ; 0x108
pOspiFlash->CCR = OSPI_FLASH_CCR_QUAD_STR_D4A32I8;
34d6: 4b3e ldr r3, [pc, #248] ; (35d0 <OspiFlashRdPage+0x1c6>)
34d8: 681b ldr r3, [r3, #0]
34da: 4a3f ldr r2, [pc, #252] ; (35d8 <OspiFlashRdPage+0x1ce>)
34dc: f8c3 2100 str.w r2, [r3, #256] ; 0x100
pOspiFlash->IR = OSPI_FLASH_CMD_MULT_STR_RD_DATA;
34e0: 4b3b ldr r3, [pc, #236] ; (35d0 <OspiFlashRdPage+0x1c6>)
34e2: 681b ldr r3, [r3, #0]
34e4: 22ec movs r2, #236 ; 0xec
34e6: f8c3 2110 str.w r2, [r3, #272] ; 0x110
34ea: e004 b.n 34f6 <OspiFlashRdPage+0xec>
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): not in SPI or MULT mode\n\r");
34ec: 4836 ldr r0, [pc, #216] ; (35c8 <OspiFlashRdPage+0x1be>)
34ee: f001 f95b bl 47a8 <__printf_veneer>
return HAL_ERROR;
34f2: 2301 movs r3, #1
34f4: e05a b.n 35ac <OspiFlashRdPage+0x1a2>
uint32_t *pu32DataReg = (uint32_t *)&pOspiFlash->DR;
34f6: 4b36 ldr r3, [pc, #216] ; (35d0 <OspiFlashRdPage+0x1c6>)
34f8: 681b ldr r3, [r3, #0]
34fa: 3350 adds r3, #80 ; 0x50
34fc: 607b str r3, [r7, #4]
sOspiFlashCtl.u32RdRcvd = 0;
34fe: 4b2d ldr r3, [pc, #180] ; (35b4 <OspiFlashRdPage+0x1aa>)
3500: 2200 movs r2, #0
3502: 60da str r2, [r3, #12]
pOspiFlash->CR = OSPI_FLASH_CR_EN_IREAD;
3504: 4b32 ldr r3, [pc, #200] ; (35d0 <OspiFlashRdPage+0x1c6>)
3506: 681b ldr r3, [r3, #0]
3508: 4a34 ldr r2, [pc, #208] ; (35dc <OspiFlashRdPage+0x1d2>)
350a: 601a str r2, [r3, #0]
pOspiFlash->AR = sOspiFlashCtl.u32RdAddr;
350c: 4b30 ldr r3, [pc, #192] ; (35d0 <OspiFlashRdPage+0x1c6>)
350e: 681b ldr r3, [r3, #0]
3510: 4a28 ldr r2, [pc, #160] ; (35b4 <OspiFlashRdPage+0x1aa>)
3512: 6852 ldr r2, [r2, #4]
3514: 649a str r2, [r3, #72] ; 0x48
for( uint32_t i = 0; i < OSPI_FLASH_PAGE_SIZE; i++ )
3516: 2300 movs r3, #0
3518: 60bb str r3, [r7, #8]
351a: e019 b.n 3550 <OspiFlashRdPage+0x146>
if( OspiFlashWaitFlagSetTo((OCTOSPI_SR_FTF | OCTOSPI_SR_TCF), OSPI_FLASH_TO_RDBT_MS) )
351c: 210a movs r1, #10
351e: 2006 movs r0, #6
3520: f000 f94e bl 37c0 <OspiFlashWaitFlagSetTo>
3524: 4603 mov r3, r0
3526: 2b00 cmp r3, #0
3528: d003 beq.n 3532 <OspiFlashRdPage+0x128>
u8RetVal++;
352a: 7bfb ldrb r3, [r7, #15]
352c: 3301 adds r3, #1
352e: 73fb strb r3, [r7, #15]
break;
3530: e011 b.n 3556 <OspiFlashRdPage+0x14c>
sOspiFlashCtl.pu8RdBuf[i] = *((uint8_t *)pu32DataReg);
3532: 4b20 ldr r3, [pc, #128] ; (35b4 <OspiFlashRdPage+0x1aa>)
3534: 691a ldr r2, [r3, #16]
3536: 68bb ldr r3, [r7, #8]
3538: 4413 add r3, r2
353a: 687a ldr r2, [r7, #4]
353c: 7812 ldrb r2, [r2, #0]
353e: 701a strb r2, [r3, #0]
sOspiFlashCtl.u32RdRcvd++;
3540: 4b1c ldr r3, [pc, #112] ; (35b4 <OspiFlashRdPage+0x1aa>)
3542: 68db ldr r3, [r3, #12]
3544: 3301 adds r3, #1
3546: 4a1b ldr r2, [pc, #108] ; (35b4 <OspiFlashRdPage+0x1aa>)
3548: 60d3 str r3, [r2, #12]
for( uint32_t i = 0; i < OSPI_FLASH_PAGE_SIZE; i++ )
354a: 68bb ldr r3, [r7, #8]
354c: 3301 adds r3, #1
354e: 60bb str r3, [r7, #8]
3550: 68bb ldr r3, [r7, #8]
3552: 2bff cmp r3, #255 ; 0xff
3554: d9e2 bls.n 351c <OspiFlashRdPage+0x112>
if( OspiFlashWaitFlagSetTo(OCTOSPI_SR_TCF, OSPI_FLASH_TO_RDBT_MS) )
3556: 210a movs r1, #10
3558: 2002 movs r0, #2
355a: f000 f931 bl 37c0 <OspiFlashWaitFlagSetTo>
355e: 4603 mov r3, r0
3560: 2b00 cmp r3, #0
3562: d008 beq.n 3576 <OspiFlashRdPage+0x16c>
u8RetVal++;
3564: 7bfb ldrb r3, [r7, #15]
3566: 3301 adds r3, #1
3568: 73fb strb r3, [r7, #15]
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): OCTOSPI_SR_TCF, u32RdRcvd = %lu\n\r", sOspiFlashCtl.u32RdRcvd);
356a: 4b12 ldr r3, [pc, #72] ; (35b4 <OspiFlashRdPage+0x1aa>)
356c: 68db ldr r3, [r3, #12]
356e: 4619 mov r1, r3
3570: 481b ldr r0, [pc, #108] ; (35e0 <OspiFlashRdPage+0x1d6>)
3572: f001 f919 bl 47a8 <__printf_veneer>
pOspiFlash->FCR = OCTOSPI_FCR_CTCF;
3576: 4b16 ldr r3, [pc, #88] ; (35d0 <OspiFlashRdPage+0x1c6>)
3578: 681b ldr r3, [r3, #0]
357a: 2202 movs r2, #2
357c: 625a str r2, [r3, #36] ; 0x24
if( pOspiFlash->SR & OCTOSPI_SR_TEF )
357e: 4b14 ldr r3, [pc, #80] ; (35d0 <OspiFlashRdPage+0x1c6>)
3580: 681b ldr r3, [r3, #0]
3582: 6a1b ldr r3, [r3, #32]
3584: f003 0301 and.w r3, r3, #1
3588: 2b00 cmp r3, #0
358a: d00e beq.n 35aa <OspiFlashRdPage+0x1a0>
u8RetVal++;
358c: 7bfb ldrb r3, [r7, #15]
358e: 3301 adds r3, #1
3590: 73fb strb r3, [r7, #15]
u32OspiFlashErrTE++;
3592: 4b14 ldr r3, [pc, #80] ; (35e4 <OspiFlashRdPage+0x1da>)
3594: 681b ldr r3, [r3, #0]
3596: 3301 adds r3, #1
3598: 4a12 ldr r2, [pc, #72] ; (35e4 <OspiFlashRdPage+0x1da>)
359a: 6013 str r3, [r2, #0]
pOspiFlash->FCR = OCTOSPI_FCR_CTEF;
359c: 4b0c ldr r3, [pc, #48] ; (35d0 <OspiFlashRdPage+0x1c6>)
359e: 681b ldr r3, [r3, #0]
35a0: 2201 movs r2, #1
35a2: 625a str r2, [r3, #36] ; 0x24
uart_printf(SZC_TEXT_ERR "OspiFlashRdPage(): OCTOSPI_SR_TEF\n\r");
35a4: 4810 ldr r0, [pc, #64] ; (35e8 <OspiFlashRdPage+0x1de>)
35a6: f001 f8ff bl 47a8 <__printf_veneer>
return u8RetVal;
35aa: 7bfb ldrb r3, [r7, #15]
}
35ac: 4618 mov r0, r3
35ae: 3710 adds r7, #16
35b0: 46bd mov sp, r7
35b2: bd80 pop {r7, pc}
35b4: 20000aa0 .word 0x20000aa0
35b8: 08024b08 .word 0x08024b08
35bc: 08024b34 .word 0x08024b34
35c0: 08024b64 .word 0x08024b64
35c4: 20000a9c .word 0x20000a9c
35c8: 08024b84 .word 0x08024b84
35cc: 08024bb8 .word 0x08024bb8
35d0: 24000e58 .word 0x24000e58
35d4: 01003101 .word 0x01003101
35d8: 03003303 .word 0x03003303
35dc: 10000301 .word 0x10000301
35e0: 08024be4 .word 0x08024be4
35e4: 2000089c .word 0x2000089c
35e8: 08024c20 .word 0x08024c20

 

LCE
LCEAuthor
Principal II
June 10, 2026

I found that in OspiFlashRdPage() another struct’s member (sSpiFileInfo.u32Size) is reset, which is also not used in that function.

After a few “sOspiFlashCtl.u32RdRcvd++;” in OspiFlashRdPage() (see code above)  sSpiFileInfo.u32Size is also changed.

 

EDIT: 

ITCM RAM is used for heap & stack, some functions, and the vector table. Changing this didn’t change anything.

I also turned off the optimization for some functions with 
__attribute__((optimize("O0")))
before function declaration.
Also no change.

LCE
LCEAuthor
Principal II
June 10, 2026

I searched all the relevant sources, I have no idea why these struct members are changed.

They are also not used in any interrupt handlers.

Is there any Cortex M7 or gcc compiler shenanigans that I’m not aware off?

 

Ah, caches: 

  • data cache is completely off
  • instruction cache is used
    • is there any instruction cache handling required? I thought not...
    • any problems with functions in ITCM ?
mƎALLEm
ST Technical Moderator
June 10, 2026

Without a minimal example running on one of the ST boards we can’t determine the source of the issue.

Try to invalidate the instruction cache before jumping to the internal Flash (SCB_InvalidateICache()).

To my knowledge no issues with ITCM.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.