0
votes

EDIT: Inorder to devan's solution, i manage to jump system bootloader from user code with STM32F042K6.

boot.h

/* boot.h */
#include "stm32f0xx_hal.h"

#if defined(STM32F042x6) || defined(STM32F048xx) 
    #define SYSTEM_MEMORY_ADDRESS       0x1FFFC400
#elif defined(STM32F070xB)
    #define SYSTEM_MEMORY_ADDRESS   0x1FFFC800
#elif defined(STM32F070x6)
    #define SYSTEM_MEMORY_ADDRESS       0x1FFFC400
#endif

HAL_StatusTypeDef SystemBootloaderJump(void);

boot.c

/* boot.c */
#include "boot.h"

/* I just re-write this code -> https://electronics.stackexchange.com/questions/312303/stm32f091-jump-to-bootloader-from-application */
HAL_StatusTypeDef SystemBootloaderJump(void)
{
    typedef void (*pFunction)(void);
    pFunction JumpToApplication;

    __HAL_RCC_USART1_FORCE_RESET();
    HAL_Delay(5);
    __HAL_RCC_USART1_RELEASE_RESET();
    HAL_Delay(5);

    HAL_RCC_DeInit();

    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    /**
     * Step: Disable all interrupts
     */
    __disable_irq();

    /* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
    __DSB();

    __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();

    /* Remap is bot visible at once. Execute some unrelated command! */
    __DSB();
    __ISB();

    /** Get option bytes. 
        *   More info at -> RM0091 Reference manual STM32F0x1/STM32F0x2/STM32F0x8 advanced ARM®-based 32-bit MCUs
        *   4 Option byte 
        *           There are up to 8 option bytes. They are configured by the end user depending on the
        *       application requirements. 
        *       ...
        *       ...
        *           4.1 Option byte description
        *               4.1.1 User and read protection option byte
        *                   Flash memory address: 0x1FFF F800
        *                   ...
        *                   Bits 23:16 USER: User option byte (stored in FLASH_OBR[15:8])
        *                       Bit 23: BOOT_SEL
        *                           0: BOOT0 signal is defined by nBOOT0 option bit
        *                           1: BOOT0 signal is defined by BOOT0 pin value (legacy mode)
        *                       Available on STM32F04x and STM32F09x devices only. Considered as “1” on other devices.
        *                       ...
        *                       ...
        *                       Bit 19: nBOOT0
        *                       When BOOT_SEL is cleared, nBOOT0 bit defines BOOT0 signal value used to select the
        *                       device boot mode. Refer to Section 2.5: Boot configuration for more details.
        *                       Available on STM32F04x and STM32F09x devices only.
        */
    FLASH_OBProgramInitTypeDef pOBInit;
    /* Get the Option byte configuration */
    HAL_FLASHEx_OBGetConfig(&pOBInit);

    /* BOOT_SEL = 0 */
    pOBInit.USERConfig &= ~(OB_BOOT_SEL_SET);
    /* nBOOT0=1 */
    pOBInit.USERConfig |= OB_BOOT0_SET;


    /** HAL_FLASHEx_OBProgram && HAL_FLASHEx_OBErase
      * HAL_FLASH_OB_Unlock() should be called before to unlock the options bytes
      */
    if(HAL_FLASH_OB_Unlock() != HAL_OK)
    {
        return HAL_ERROR;
    }

    /*We need to erase option bytes before write. */
    if(HAL_FLASHEx_OBErase() != HAL_OK)
    {
        return HAL_ERROR;
    }

    /* Write changed option bytes */
    if(HAL_FLASHEx_OBProgram(&pOBInit))
    {
        return HAL_ERROR;
    }

    JumpToApplication = (void (*)(void)) (*((uint32_t *) ((SYSTEM_MEMORY_ADDRESS + 4))));

    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t*) SYSTEM_MEMORY_ADDRESS);

    JumpToApplication();
    return HAL_OK;
}

How can i reset STM32 microcontroller after erase flash page?

My goal is jump system bootloader from user flash with STM32F042K6 microcontroller. But in AN2606 Application note STM32 microcontroller system memory boot mode its says;

Due to empty check mechanism present on this product, it is not possible to jump from user code to system bootloader. Such jump will result in a jump back to user flash space. But if the first 4 bytes of User Flash (at 0x0800 0000) are empty at the moment of jump (ie. erase first sector before jump or execute code from SRAM while Flash is empty), then system bootloader will be executed when jumped to.

So, i put my functions, except main(), in ROM 0x08007C00 - 0x08007FFF (last page of my flash memory). In my main function, i'm calling erase function -located at last page in my microcontroller flash- and erase first page. It erases succesfully first page but after that i can't reset my microcontroller in software or can't jump to system bootloader. Microcontroller stuck somewhere but i couldn't found. But when i reset microcontroller with reset pin, it boots from system bootloader. That means if i can reset microcontroller somehow, i will achieve my goal.

I'm open other solutions. My code is like that;

/* main.c located at 0x0800 0000 - 0x0800 7BFF */
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM16_Init();

  StartBoot();

  while(1){}
 }

/* boot.c located at 0x0800 7C00 - 0x0800 7FFF */

#define ADDR_FLASH_PAGE_0     ((uint32_t)0x08000000) /* Base @ of Page 0, 1 Kbyte */

void StartBoot(void)
{
    if(ErasePage(ADDR_FLASH_PAGE_0) == HAL_OK)
    {
        HAL_FLASH_Lock();
        NVIC_SystemReset();
    }
}

HAL_StatusTypeDef ErasePage(uint32_t address)
{
/* Unlock the Flash to enable the flash control register access */
  HAL_FLASH_Unlock();

  /* Erase the user Flash area */

  /* Fill EraseInit structure*/
  EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
  EraseInitStruct.PageAddress = address;
  EraseInitStruct.NbPages     = 1; /* Erase 1 Page */

  /* Note: If an erase operation in Flash memory also concerns data in the data or instruction cache,
     you have to make sure that these data are rewritten before they are accessed during code
     execution. If this cannot be done safely, it is recommended to flush the caches by setting the
     DCRST and ICRST bits in the FLASH_CR register. */
  if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
  {
    /*
      Error occurred while page erase.
      User can add here some code to deal with this error.
      PAGEError will contain the faulty page and then to know the code error on this page,
      user can call function 'HAL_FLASH_GetError()'
    */
        HAL_FLASH_Lock();
        return HAL_ERROR;

  }
    return HAL_OK;
}
1

1 Answers

2
votes

That app note guidance is a little weird. I have worked with the STM32F042 series, including the STM32F042K6 specifically. My experience has been that the only weird behavior compared to other STM32 family parts is that the bootloader enforces the BOOT_SEL bit at run-time, not just when the chip boots up from reset.

The run-time check for the status of BOOT0 is what normally causes it to jump back to main flash even if you manually remap memory and jump to the bootloader as one would with other STM32 family parts.

To work around this, you can set BOOT_SEL=0 and nBOOT0=1 in the option bytes so that at boot, it always boots to main flash, as shown in the table below: Table 3. Boot Modes, from section 2.5 of RM0091

After setting the option bytes this way, you can take the normal remap-memory-and-jump-to-the-bootloader approach that has already been covered a few times.

(Note: the STM32F042 series boot memory lives at 0x1FFFC400, as opposed to 0x1FFFC800 shown in the STM32F072 example).

As a word of caution, disabling the BOOT pin check will prevent you from using the BOOT pin to force the chip into the bootloader. You may want to add your own software check to read the BOOT0 pin early during boot and jump to the bootloader.