0

I am trying to develop a bootloader with STM32F469BIT mcu. First of all, I divided the 2048K flash area allocated to me into zones according to certain sector addresses. These areas;

Bootloader -> FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 32K
App1 -> FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 1008K
App2 -> FLASH (rx) : ORIGIN = 0x08104000, LENGTH = 1008K

After separating these areas the vector tab offsets are;

App1 -> #define VECT_TAB_OFFSET 0x00008000U
App2 -> #define VECT_TAB_OFFSET 0x00104000U

I have a task in the bootloader and I control a button with an EXTI in this task. I specify that the jump operation will be performed when the button is pressed.

typedef StaticTask_t osStaticThreadDef_t;
typedef void (*pFunction)(void);

#define APP1_ADDRESS  ((uint32_t)0x08008000)
#define NVIC_IRQ_COUNT  240
#define BASEPRI_MASK   ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << \
                         (8 - configPRIO_BITS) )

extern TIM_HandleTypeDef htim6;
extern TIM_HandleTypeDef htim2;

static void prvSafeGPIODeInit(void) {
    GPIO_InitTypeDef init = { 0 };
    const uint32_t keepA = GPIO_PIN_13 | GPIO_PIN_14;        /* SWD */

    HAL_GPIO_DeInit(GPIOA, ~keepA);
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOE, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOF, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOG, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOH, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOI, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOJ, GPIO_PIN_All);
    HAL_GPIO_DeInit(GPIOK, GPIO_PIN_All);

    init.Pin = keepA;
    init.Mode = GPIO_MODE_AF_PP;
    init.Pull = GPIO_NOPULL;
    init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    init.Alternate = GPIO_AF0_SWJ;
    HAL_GPIO_Init(GPIOA, &init);
}

static void prvNVIC_Reset(void) {
    for (uint32_t i = 0; i < NVIC_IRQ_COUNT; ++i) {
        NVIC_DisableIRQ((IRQn_Type) i);
        NVIC_ClearPendingIRQ((IRQn_Type) i);
    }
}

static void prvPeriph_DeInit(void) {
    HAL_TIM_Base_DeInit(&htim6);
    HAL_TIM_Base_DeInit(&htim2);
}

static void prvBoot_DeInit(void) {
    __disable_irq();
    __set_BASEPRI(0xf0);

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

    prvSafeGPIODeInit();
    prvNVIC_Reset();
    prvPeriph_DeInit();

    HAL_RCC_DeInit();
    HAL_DeInit();
}

static void prvJumpToApp(uint32_t appAddr) {
    uint32_t newSP  = *(uint32_t*)appAddr;
    pFunction entry = (pFunction)*(uint32_t*)(appAddr + 4);

    prvBoot_DeInit();

    SCB->VTOR = appAddr;
    __DSB();
    __ISB();
    __set_MSP(newSP);

    __enable_irq();

    entry();

    while (1) {
        __NOP();
    }
}

void StartupEntry(void *argument) {
    /* USER CODE BEGIN StartupEntry */
    /* Infinite loop */
    (void) argument;
    for (;;) {
        HAL_GPIO_TogglePin(BM83_EN_GPIO_Port, BM83_EN_Pin);
        if (HAL_GPIO_ReadPin(ENC2_SW_GPIO_Port, ENC2_SW_Pin) == GPIO_PIN_SET) {
            prvJumpToApp(APP1_ADDRESS);
        }
        osDelay(20);
    }
    /* USER CODE END StartupEntry */
}

After jumping, the software in the app does not work. I see that the jump was done successfully, but no task is running on the application it jumped to. When I examine the flash areas through the created .elf file, I get an output like below.

Boot .isr_vector is:

Section: .isr_vector
Region: FLASH
Address: 0x08000000
Size: 436
00 00 05 20 25 16 00 08 7D 14 00 08 85 14 00 08 8D 14 00 08 95 14 00 08 9D 14 00 08 00 00 00 00 ...

App1 .isr_vector is:

Section: .isr_vector
Region: FLASH
Address: 0x08008000
Size: 436
00 00 05 20 B5 C7 00 08 CD B7 00 08 D5 B7 00 08 DD B7 00 08 E5 B7 00 08 ED B7 00 08 00 00 00 00 00 ...

After the jumping process i cannot see any reaction in my tasks. What are the places that I should pay attention to and not examine? If there is a wrong operation, can you also help me fix it?

Thanks for your attention and help.

2
  • 1
    Any bootloader I've made for STM32 either immediately chains the main app (so no need to uninitialize anything), or runs some bootloader functionality, then eventually does a full-chip reset. Hard to tell where your problem is, but seems a weird design to me. Commented Apr 17 at 23:15
  • I agree it's hard to tell. Changing SCB->VTOR and enabling interrupts before jumping seems strange to me. One thing I have learned with my toolchain is that jumping to the application like this does not work when compiler optimizations are disabled because of the way it accesses the stack. You may need to step through the disassembly and study what is going on. Commented Apr 18 at 10:16

1 Answer 1

2

Do not enable interrupts before entry() the application start-up may not expect that, and may assume interrupts are disabled.

You should in any case start the application with the MCU in the state it would be on a POR. "De-initialising" in software will not guarantee that, and is hard to maintain across parts with different hardware or from different manufacturers.

By calling entry() you are decrementing the SP for the return address, so losing a small bit of stack for something you are not going to return to. Better to set the PC directly. Create an assembler function like:

__asm void boot_jump( uint32_t address )
{
   LDR SP, [R0]       ;Load new stack pointer address
   LDR PC, [R0, #4]   ;Load new program counter address
}

Noting that in-line assembler syntax varies across compilers; this example is Keil ARM-MDK / ARM Compiler.

Then at the end of your bootloader:

// Switch vector table
SCB->VTOR = APPLICATION_START_ADDR ;

//Jump to start address
boot_jump( APPLICATION_START_ADDR ) ;

Note that APPLICATION_START_ADDR in this case is the base or location address of your linked application code, not the entry point indicated in the link map. The application vector table is located at this address, and the start of the vector table contains the application's initial stack pointer address and program counter (the actual code entry point).

The boot_jump() function loads a stack pointer and program counter from the application's vector table, simulating what happens on reset where they are loaded from the base of Flash memory (the bootloader's vector table).

A safer and simpler mechanism in your case, where you want the application to start when the button is pressed, is to reserve two words in SRAM so they are not zero initialised by the runtiime start-up, and write a signature there when the button is pressed, then reset. Then you check that signature on start-up, before initialising any hardware, and if it is set you jump straight to the application from reset. That way the application environment on start-up is identical to as if it were started from the reset vector.

Pseudocode:

if( *BOOT_SIGNATURE == ~(*BOOT_SIGNATURE + 1)
{
  *BOOT_SIGNATURE = 0 ;
  (*BOOT_SIGNATURE+1) = 0 ;

  // Switch vector table
  SCB->VTOR = APPLICATION_START_ADDR ;

  //Jump to start address
  boot_jump( APPLICATION_START_ADDR ) ;
}

buttonInit() ;
while( button() != PRESSED ) {  }

*BOOT_SIGNATURE = 0xBOODBOOD ;
*(BOOT_SIGNATURE+1) = ~(*BOOT_SIGNATURE) ;

NVIC_Reset() ;

An even simpler and more power efficient method would be to wire your button to the WKUP pin (PA0) and enter the STANDBY low power state rather than busy-waiting for a button press.

// If Wakeup...
if( PWR->WUPF )
{
  PWR->CWUPF = 1 ;

  // Switch vector table
  SCB->VTOR = APPLICATION_START_ADDR ;

  //Jump to start address
  boot_jump( APPLICATION_START_ADDR ) ;
}

// Enable Standby low power mode
// With WKUP enabled
PWR->EWUP ;
enterStandby() ;

Then when power is applied, it will immediately enter standby until the WKUP pin is asserted when it will launch the application. If the application enters standby, it should do so with the WKUP pin enabled in order to re-wake through the button, otherwise you will need to cycle the power supply to be able to start.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.