Hi @danielmartynek
Thanks for your response.
To clarify, we are observing two intermittent behaviours:
1) Bootloader active but jump fails:
- Bootloader receives update command and successfully programs the application.
- Application CRC check passes.
- However, after issuing jump, control does not transfer to the application.
2) Bootloader becomes unresponsive:
- No UART response and no LED indication.
- POR/software reset does not recover.
- Only reflashing via debugger restores the system.
So far, POR alone does NOT resolve the issue.
For the jump sequence, we are currently using the following approach:
- Validate application before jump:
- IVT marker check
- Stack pointer (not 0x0 / 0xFFFFFFFF)
- Reset handler validity
- Jump sequence includes:
- Disable interrupts (clearing individually)
- Disable SysTick
- Cache clean + invalidate
- VTOR update
- MSP/PSP update
- DSB/ISB barriers
- Jump to reset handler
/* -------------------------------------------------------------------------- */
/* Flash memory layout */
/* -------------------------------------------------------------------------- */
/** @brief Base address of internal flash memory. */
#define FLASH_BASE_ADDR (0x00400000U)
/** @brief Total flash memory size (1 MB). */
#define FLASH_TOTAL_SIZE (0x00100000U)
/** @brief End address of internal flash memory. */
#define FLASH_END_ADDR (FLASH_BASE_ADDR + FLASH_TOTAL_SIZE)
/** @brief Start address of the application image region. */
#define APP_STARTADDR (0x00422000U)
/** @brief Maximum supported application image size in bytes. */
#define APPLICATION_IMAGE_SIZE (FLASH_END_ADDR - APP_STARTADDR)
/** @brief Maximum payload buffer allocated per transfer step. */
#define FLASH_CHUNK_SIZE (512U)
/** @brief Chunk size used during post-reset CRC verification. */
#define CRC_CHUNK_SIZE (4096U)
/** @brief Expected IVT marker value at the application image base. */
#define IVT_MARKER_MAGIC (0x5AA55AA5U)
/** @brief Kept for layout compatibility with existing application image builds. */
#define IVT_ENTRY_ADDR (APP_STARTADDR + 0x2000U)
/* -------------------------------------------------------------------------- */
/* Application Jump Configuration */
/* -------------------------------------------------------------------------- */
/** @brief Offset to core entry address from application start. */
#define FLASH_APP_CORE_ENTRY_OFFSET (0x0CU)
/** @brief Offset to reset handler from core entry address. */
#define FLASH_APP_RESET_HANDLER_OFFSET (0x04U)
/** @brief Expected IVT marker magic value for valid application image. */
#define FLASH_IVT_MARKER_MAGIC (0x5AA55AA5U)
/** @brief Default erased 32-bit flash value. */
#define FLASH_ERASED_U32_VALUE (0xFFFFFFFFU)
/** @brief Default zero 32-bit value. */
#define FLASH_ZERO_U32_VALUE (0x00000000U)
/**
* @brief Validate an address read from application flash.
*
* @details
* This function checks whether a given address value is valid and usable.
* It filters out common invalid values such as:
* - 0x00000000 (unprogrammed / null)
* - 0xFFFFFFFF (erased flash)
*
* This function is used for validating stack pointer and reset handler.
*
* @param addressValue Address read from flash (stack pointer or reset handler).
*
* @return TRUE if the value is valid, otherwise FALSE.
*/
static boolean Flash_IsAddressValid(uint32 addressValue)
{
return ((addressValue != FLASH_ZERO_U32_VALUE) &&
(addressValue != FLASH_ERASED_U32_VALUE)) ? TRUE : FALSE;
}
static AppJumpError_t Flash_PrecheckApplication(void)
{
uint32 appStack;
uint32 coreEntry;
uint32 resetHandler;
/* IVT marker validation */
if ((*(volatile const uint32 *)APP_STARTADDR) != FLASH_IVT_MARKER_MAGIC)
{
return APP_JUMP_ERR_CORRUPT;
}
/* Stack pointer validation */
appStack = *(volatile const uint32 *)APP_STARTADDR;
if (Flash_IsAddressValid(appStack) == FALSE)
{
return APP_JUMP_ERR_STACKPTR;
}
/* Reset handler validation */
coreEntry = *(volatile const uint32 *)(APP_STARTADDR + FLASH_APP_CORE_ENTRY_OFFSET);
resetHandler = *(volatile const uint32 *)(coreEntry + FLASH_APP_RESET_HANDLER_OFFSET);
if (Flash_IsAddressValid(resetHandler) == FALSE)
{
return APP_JUMP_ERR_RESETHANDLER;
}
return APP_JUMP_OK;
}
/**
* @brief Transfer execution from bootloader to application.
*
* @details
* This function performs the final steps required to transfer control
* from the bootloader to the application firmware:
*
* - Disables all interrupts
* - Stops system tick
* - Clears and invalidates caches
* - Sets the Main Stack Pointer (MSP)
* - Updates vector table
* - Jumps to application reset handler
*
* IMPORTANT:
* - All validation must be completed before calling this function.
* - This function does not return.
*/
void JumpToApplication(void)
{
uint32 appStack;
uint32 coreEntry;
uint32 resetHandler;
/* ------------------------------------------------------------------ */
/* Read application vector table */
/* ------------------------------------------------------------------ */
appStack = *(volatile const uint32 *)(APP_STARTADDR);
coreEntry = *(volatile const uint32 *)(APP_STARTADDR + FLASH_APP_CORE_ENTRY_OFFSET);
resetHandler = *(volatile const uint32 *)(coreEntry + FLASH_APP_RESET_HANDLER_OFFSET);
/* ------------------------------------------------------------------ */
/* Disable interrupts */
/* ------------------------------------------------------------------ */
Flash_DisableAllInterrupts();
/* Disable SysTick */
S32_SysTick->CSRr = 0x00000000;
/* ------------------------------------------------------------------ */
/* Cache handling */
/* ------------------------------------------------------------------ */
Cache_Ip_Clean(CACHE_IP_CORE, CACHE_IP_DATA, TRUE);
Cache_Ip_Invalidate(CACHE_IP_CORE, CACHE_IP_INSTRUCTION);
/* ------------------------------------------------------------------ */
/* Set vector table address */
/* ------------------------------------------------------------------ */
S32_SCB->VTOR = (uint32)APP_STARTADDR;
/* ------------------------------------------------------------------ */
/* Set Main Stack Pointer */
/* ------------------------------------------------------------------ */
__asm volatile ("msr msp, %0" :: "r"(appStack));
__asm volatile ("msr psp, %0" :: "r"(appStack));
__asm__ __volatile__ ("dsb 0xF" : : : "memory");
__asm__ __volatile__ ("isb 0xF" : : : "memory");
/* Ensure Thumb mode */
resetHandler = (resetHandler & FLASH_THUMB_ADDRESS_MASK) | FLASH_THUMB_ADDRESS_BIT;
/* ------------------------------------------------------------------ */
/* Jump to application */
/* ------------------------------------------------------------------ */
((void (*)(void))resetHandler)();
/* Should never reach here */
while (1)
{
/* Trap */
}
}
We have a few specific questions:
1) Is there anything critical missing or incorrect in this validation/jump sequence?
2) Do you recommend additional checks (e.g., stricter SP/PC range validation or alignment checks)?
3) Could cache/MPU state or missing barriers still cause this intermittent behaviour even with this sequence?
4) Is there any known dependency on flash alignment or ECC correction that could explain why debugger reflashing always resolves the issue?
5) Additionally, we observed that using global interrupt disable:
__asm volatile("cpsid i");
causes the jump to fail, whereas disabling interrupts one-by-one works reliably:
for (irqIndex = DMATCD0_IRQn; irqIndex <= SoC_IRQn; irqIndex++)
{
IntCtrl_Ip_DisableIrq((IRQn_Type)irqIndex);
IntCtrl_Ip_ClearPending((IRQn_Type)irqIndex);
}
Could you please advise why global interrupt disable might affect the jump behaviour in this case?
S32DS-ARM S32K3
Best regards,
Yusup