2
votes

I use the STM32L073RZ (Nucleo 64 board).

I would like to jump into the system memory in application programming (IAP).

My code works on the revision B of the STM32L073 microcontroller but fails on the latest revision, rev Z.

I read the errata sheet, no details are given, just a limitation fixed on the dual boot mechanism into system memory according to the BFB2 bit.

Is the system memory no longer supports an IAP jumping to execute its code (to flash firmwares through USB or UART without using the BOOT0 pin) ?

The function is the first line of my main program, it tests if the code has to jump to the booloader:

void jumpBootLoader(void)
{
    /* to do jump? */
    if ( *((unsigned long *)0x20003FF0) == 0xDEADBEEF  ) 
    {
        /* erase the label */
        *((unsigned long *)0x20003FF0) = 0xCAFEFEED;

        /* set stack pointer to the bootloader start address */
        __set_MSP(*((uint32_t*)(0x1FF00000)));

        /* system memory mapped at 0x00000000 */
        __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();

        /* jump to @bootloader + 4 */
        ((void (*)(void))(*((uint32_t*)(0x1FF00004))))();
    }
}   

I call these two lines as soon as the BP1 button is pressed to trig the jump operation after resetting the µC:

*((unsigned long *)0x20003FF0) = 0xDEADBEEF;
NVIC_SystemReset();

I use the HSI 16Mhz clock source.

4
Most likely no one will be able to help you if you don't show us the code...Freddie Chopin

4 Answers

1
votes

The solution is to jump twice to the system memory. First Jump to bootloader startup to initialize Data in RAM until the Program counter will returned to Flash by the Dualbank management. Second Jump: Jump to the Dualbank bypassed address

How to use: User has first to initialize a variable “ Data_Address” (must be an offset Flash sector aligned address) in Flash to distinguish between first/second Jump.

EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = Data_Address;
EraseInitStruct.NbPages     = 1;


    First_jump = *(__IO uint32_t *)(Data_Address);

    if (First_jump == 0) {  
        HAL_FLASH_Unlock();
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Data_Address, 0xAAAAAAAA);
        HAL_FLASH_Lock();

        /* Reinitialize the Stack pointer and jump to application address */ 
        JumpAddress = *(__IO uint32_t *)(0x1FF00004);
    }
    if (First_jump != 0) {  
        HAL_FLASH_Unlock();
        HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
        HAL_FLASH_Lock();

        /* Reinitialize the Stack pointer and jump to application address */ 
        JumpAddress =  (0x1FF00369);
    }

    Jump_To_Application = (pFunction) JumpAddress;
    __set_MSP(*(__IO uint32_t *)(0x1FF00000));
    Jump_To_Application(); 
1
votes

First important thing: you use 0x1FF0 0000 as the addres where SP is stored, this is correct. Then you use 0x1 FF00 0004 as the address from which you load the function pointer. This is not correct - one zero too many.

Note that using __set_MSP() is generally not such a good idea if you also use MSP as your stack pointer (which you most likely are). The recent definition of this function, which marks "sp" as clobbered register, causes your change to be reverted almost immediately. Incidentally today I was doing exactly the same thing you are doing and I've found that problem. In your assembly listing you'll see that SP is saved into some other register before the msr msp, ... instruction and restored right after that.

Finally I wrote that manually (STM32F4, so different addresses):

constexpr uint32_t systemMemoryBase {0x1fff0000};

asm volatile
(
        "   msr     msp, %[sp]      \n"
        "   bx      %[pc]           \n"

        ::  [sp] "r" (*reinterpret_cast<const uint32_t*>(systemMemoryBase)),
            [pc] "r" (*reinterpret_cast<const uint32_t*>(systemMemoryBase + 4))
);

BTW - you don't need to set memory remap for the bootloader to work.

1
votes

Thanks for your help. I have my answer !

The v4.0 bootloader (initial version) does not implement the dual bank mechanism but this feature is supported by v4.1.

Software can jump to bootloader but it will execute the dual boot mechanism. So the bootloader goes back to bank1 (or bank2 if a code is "valid").

Today it is not possible to bypass the dual bank mechanism to execute the bootloader with my configuration: The boot0 pin is reset and the protection level is 0 (see "Table 11. Boot pin and BFB2 bit configuration" in the reference manual).

0
votes

Where is your program counter when you call __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH()?

Remapping a memory region while you're executing out of that same region will end poorly! You may need to relocate this code into SRAM, or execute this code with PC set to the fixed FLASH memory mapping (0x0800xxxx).