cancel
Showing results for 
Search instead for 
Did you mean: 

working on a bootloader for the STM32H750IB, and have questions, esp about SCB->VTOR

TallMike
Associate III

Hi, I'm working on a bootloader for a board using the STM32H750IB  (the Electro-Smith Daisy Seed), and have a few questions about what all needs to be done before jumping to the main image.

The main image (a flat '.bin' file) is stored in a QSPI flash chip, which is copied to the main SRAM at 0x24000000.

In looking at various other ARM  Cortex M7 bootloaders, it seems like most of them are NOT setting the SCB->VTOR register.  But from what I otherwise read, it should be set.  But then I was also seeing some mentions that it should be copied to address 0x0, and/or that there may be an offset.

Here's the current code, it seems to work by just setting the SCB->VTOR to the base SRAM address, but is this correct?   

Also, I saw conflicting info on whether interrupts should be disabled or must not be disabled.

And what about the Watchdog timer?  I don't think it's being used.

And anything else that needs to be done?  It _seems_ to be working, but are there any potential intermittent issues?

Thanks for any feedback!

 

 

int main(void)
{
	hw.Init();
	DbgInit();

    uint8_t *app_run_image_ptr=&_app_run_address;
    DebugOut("app address = 0x%08X\r\n", app_run_image_ptr);

     uint32_t tot_len=480*1024;

    uint32_t block_count=tot_len/BLOCK_SIZE;
    
    for (uint32_t bb=0; bb < block_count; bb++)
    {
        uint32_t index=bb*BLOCK_SIZE;
        uint8_t* qspi_data_addr = (uint8_t *)hw.qspi.GetData(0x40000+index);
        // We need to explicitly invalidate the QSPI mapped memory to ensure we are
        // reading the correct data
        dsy_dma_invalidate_cache_for_buffer((uint8_t *)qspi_data_addr, BLOCK_SIZE);

        void *app_ram_dest_addr=app_run_image_ptr + index;

        memcpy(app_ram_dest_addr, qspi_data_addr, BLOCK_SIZE);
    }
      uint32_t JumpAddress = *(__IO uint32_t*) (app_run_image_ptr+4);
      uint32_t app_stack_ptr=*(__IO uint32_t*) (app_run_image_ptr+0);

    hw.DeInit();  // apparently doesn't de-init the qspi.
    hw.qspi.DeInit();

      // jump to application code

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

      RCC->CIER = 0x00000000;

      /* Disable and reset SysTick */
      SysTick->CTRL = 0;
      SysTick->LOAD = 0;
      SysTick->VAL = 0;

      /* Clear Interrupt Enable Register & Interrupt Pending Register */
      for (int i = 0;i < 8; i++) {
    	  NVIC->ICER[i]=0xFFFFFFFF;
	      NVIC->ICPR[i]=0xFFFFFFFF;
      }
        SCB->VTOR = (uint32_t)(app_run_image_ptr);   ///????

//??      // Enable IWDG if firmware has option bit set
//??      //if ((header->options >> OPT_IWDG_OFFSET) & OPT_IWDG_MASK)
//??        MX_IWDG1_Init();
//????        HAL_IWDG_Init();

      pFunction jumpToApplication = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(app_stack_ptr);

///      __enable_irq();

      jumpToApplication();

    for(;;) {}

 

 

 

3 REPLIES 3

It's normally handled by the SystemInit() of your application side code.

ST has this annoying #define methodology rather than using Linker Symbols, but that can be fixed.

Changing the stack frame pointer mid function is something I'd probably avoid, and perhaps address in startup.s and Reset_Handler more explicitly after control has actually been transferred. 

The Watchdog can't be turned off, so if you've made a contract to kick it, then the app needs to be kicking it.

You could turn it off and clear things via an expedited reset path method, but it would also drop all the external memory, etc.

Do all the Clock, PLL and external memory initialization in the loader, and don't repeat in the app, 1) it wastes more time, 2) it's disruptive

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
liaifat85
Senior III

Disable interrupts before the jump (__disable_irq();) and leave enabling them to the application.

TDK
Guru

> Here's the current code, it seems to work by just setting the SCB->VTOR to the base SRAM address, but is this correct?   

Yes, that works. Sometimes code sets it to 0 because various memory gets remapped there, but this is just for convenience. No need to follow that convention

> Also, I saw conflicting info on whether interrupts should be disabled or must not be disabled.

They are enabled by default. Re-enabling them does nothing. Whether they "should" be enabled is up to you, but disabling them globally would be an odd choice.

> And what about the Watchdog timer?  I don't think it's being used.

Up to you. Most applications will set their own watchdog. You can enable it in the bootloader if resetting the chip is the desired behavior if the application fails to start.

If you feel a post has answered your question, please click "Accept as Solution".