iMXRT1024 Bootloader jump to application not working

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

iMXRT1024 Bootloader jump to application not working

335 Views
m1raculix
Contributor I

Dear community,

I am developing a bootloader for the rt1024-evk evaluation board which receives the application data via canbus and flashes it to a custom location on the onboard flexspi flash.

The bootloader is located at position 0 on the flash (0x60000000)

The application should be located at an offset, for example if the bootloader size is ~0x9000 bytes i would place the app at 0x60000000 + 0xA000 to be on the next flash-sector.

 

Now i have two questions:

1: First of all how do i build and flash the application correctly to place it at the offset in flash (just to test if my bootloader would jump to the application)? 

- i have tried using the led blinky example for the imxrt1024 and changed in the memory settings under project setting the flash location to 0x6000A000 and flashed the app via the gui flash tool

 

2. how to i correctly jump to the application?

- i have tried the attached code (void jump_to_application()), which i reduced from the flashloader example - together with the blinky example hopefully flashed at 0x6000A000 but it didn't work.

 

Note: - bootloader and application should be on the the flash

- my bootloader is based on the flexspi_nor_polling_transfer example which includes some linkscript modifications (attached as well). The .ldt files are not modified in comparison to the example project, but i had to remove the one for .bss, otherwise it would instantly run into a hardfault.

 

 

/////////////////////////////////////////////////////////

jump_to_application code:

 

/*
* application.cpp
*
*/
 
#include "utils/timer_counter.h"
#include "../utilities/serial_debug.h"
 
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
 
#include "application.h"
 
#include "../fusemap.h"
 
 
#define BL_APP_VECTOR_TABLE_ADDRESS (0x6000A000u)
#define APP_VECTOR_TABLE ((uint32_t *)BL_APP_VECTOR_TABLE_ADDRESS)
#define FREQ_396MHz (396UL * 1000 * 1000)
#define FREQ_528MHz (528UL * 1000 * 1000)
#define FREQ_24MHz (24UL * 1000 * 1000)
#define FREQ_480MHz (480UL * 1000 * 1000)
#ifdef __cplusplus
extern "C" {
#endif
void jump_to_application();
__STATIC_INLINE void NVIC_ClearEnabledIRQs(void);
__STATIC_INLINE void NVIC_ClearAllPendingIRQs(void);
void configure_clocks();
#ifdef __cplusplus
}
#endif
 
// default constructor
Application::Application()
{
 
} //application
 
 
/* Steps to initialize the Application */
void Application::initialize()
{
checkStartupConditions();
}
 
/*Start the Application */
void Application::run()
{
while (1)
{
}
}
 
void Application::checkStartupConditions()
{
jump_to_application();
}
 
 
// default destructor
Application::~Application()
{
} //~application
 
void jump_to_application()
{
 
PRINTF("Jump1\r\n");
// Clear any IRQs that may be enabled, we only want the IRQs we enable to be active
NVIC_ClearEnabledIRQs();
 
// Clear any pending IRQs that may have been set
NVIC_ClearAllPendingIRQs();
 
// Set the VTOR to default.
SCB->VTOR = 0; //Address of the default vector table, which is always 0.
// Restore clock to default before leaving bootloader.
configure_clocks();
// De-initialize hardware such as disabling port clock gate
//deinit_hardware();
CLOCK_DisableClock(kCLOCK_UsbOh3);
 
// Restore global interrupt.
__enable_irq();
 
// Memory barriers for good measure.
__ISB();
__DSB();
 
 
uint32_t applicationAddress, stackPointer;
 
applicationAddress = APP_VECTOR_TABLE[1]; //Reset handler
stackPointer = APP_VECTOR_TABLE[0]; //Stack pointer
 
 
 
// Create the function call to the user application.
    // Static variables are needed since changed the stack pointer out from under the compiler
    // we need to ensure the values we are using are not stored on the previous stack
    static uint32_t s_stackPointer = 0;
    s_stackPointer = stackPointer;
    static void (*farewellBootloader)(void) = 0;
    farewellBootloader = (void (*)(void))applicationAddress;
 
    // Set the VTOR to the application vector table address.
    SCB->VTOR = (uint32_t)APP_VECTOR_TABLE;
 
    // Set stack pointers to the application stack pointer.
    __set_MSP(s_stackPointer);
    __set_PSP(s_stackPointer);
 
    // Jump to the application.
    farewellBootloader();
    // Dummy fcuntion call, should never go to this fcuntion call
    jump_to_application();
}
 
 
#ifdef __cplusplus
extern "C" {
#endif
/** \brief  Clear Enabled IRQs
 
    The function clears all device IRQs
 */
__STATIC_INLINE void NVIC_ClearEnabledIRQs(void)
{
    NVIC->ICER[0] = 0xFFFFFFFF;
    NVIC->ICER[1] = 0xFFFFFFFF;
    NVIC->ICER[2] = 0xFFFFFFFF;
    NVIC->ICER[3] = 0xFFFFFFFF;
    NVIC->ICER[4] = 0xFFFFFFFF;
    NVIC->ICER[5] = 0xFFFFFFFF;
    NVIC->ICER[6] = 0xFFFFFFFF;
    NVIC->ICER[7] = 0xFFFFFFFF;
}
 
/** \brief  Clear All Pending Interrupts
 
    The function clears the pending bits of all external interrupts.
 
 */
__STATIC_INLINE void NVIC_ClearAllPendingIRQs(void)
{
    NVIC->ICPR[0] = 0xFFFFFFFF;
    NVIC->ICPR[1] = 0xFFFFFFFF;
    NVIC->ICPR[2] = 0xFFFFFFFF;
    NVIC->ICPR[3] = 0xFFFFFFFF;
    NVIC->ICPR[4] = 0xFFFFFFFF;
    NVIC->ICPR[5] = 0xFFFFFFFF;
    NVIC->ICPR[6] = 0xFFFFFFFF;
    NVIC->ICPR[7] = 0xFFFFFFFF;
}
 
void configure_clocks()
{
    uint32_t clock_divider = 1;
    uint32_t fuse_div = 0;
    uint32_t clock_freq = 0;
 
    CLOCK_SetXtal0Freq(CPU_XTAL_CLK_HZ);
    // Get the Boot Up CPU Clock Divider
    // 00b = divide by 1
    // 01b = divide by 2
    // 10b = divide by 4
    // 11b = divide by 8
    fuse_div = ROM_OCOTP_LPB_BOOT_VALUE();
    clock_divider = 1 << fuse_div;
 
    // Get the Boot up frequency
    // 0 = 396Mhz
    // 1 = 528Mhz
    clock_freq = ROM_OCOTP_BOOT_FREQ_VALUE();
 
    // Bypass clock configurations if clock is configured
    CCM_ANALOG->PLL_SYS |= CCM_ANALOG_PLL_SYS_BYPASS_MASK;
    CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_BYPASS_MASK;
 
    /* Configure PLL_SYS */
    CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_POWERDOWN_MASK;
    // Wait Until clock is locked
    while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0)
    {
    }
    CCM_ANALOG->PLL_SYS |= CCM_ANALOG_PLL_SYS_BYPASS_MASK;
 
    // Configure SYS_PLL PFD
    // PFD0 = 396MHz  - uSDHC CLOCK Source
    // PFD1 = 396MHz
    // PFD2 = 500MHz  - SEMC CLOCK Source
    // PFD3 = 396MHz
    CCM_ANALOG->PFD_528 =
        (CCM_ANALOG->PFD_528 & (~(CCM_ANALOG_PFD_528_PFD0_FRAC_MASK | CCM_ANALOG_PFD_528_PFD1_FRAC_MASK |
                                  CCM_ANALOG_PFD_528_PFD2_FRAC_MASK | CCM_ANALOG_PFD_528_PFD3_FRAC_MASK))) |
        CCM_ANALOG_PFD_528_PFD0_FRAC(24) | CCM_ANALOG_PFD_528_PFD1_FRAC(24) | CCM_ANALOG_PFD_528_PFD2_FRAC(19) |
        CCM_ANALOG_PFD_528_PFD3_FRAC(24);
 
    // Always configure USB1_PLL
    CCM_ANALOG->PLL_USB1 =
        CCM_ANALOG_PLL_USB1_DIV_SELECT(0) | CCM_ANALOG_PLL_USB1_POWER(1) | CCM_ANALOG_PLL_USB1_ENABLE(1);
    while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0)
    {
    }
    CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
 
    // Configure USB_PLL PFD
    // PFD0 = 247MHz  - FLEXSPI CLOCK Source
    // PFD1 = 247MHz  - LPSPI CLOCK Source
    // PFD2 = 332MHz
    // PFD3 = 576MHz
    CCM_ANALOG->PFD_480 =
        (CCM_ANALOG->PFD_480 & (~(CCM_ANALOG_PFD_480_PFD0_FRAC_MASK | CCM_ANALOG_PFD_480_PFD1_FRAC_MASK |
                                  CCM_ANALOG_PFD_480_PFD2_FRAC_MASK | CCM_ANALOG_PFD_480_PFD3_FRAC_MASK))) |
        CCM_ANALOG_PFD_480_PFD0_FRAC(35) | CCM_ANALOG_PFD_480_PFD1_FRAC(35) | CCM_ANALOG_PFD_480_PFD2_FRAC(26) |
        CCM_ANALOG_PFD_480_PFD3_FRAC(15);
 
    // Set up CPU_PODF
    if (clock_freq == 1)
    {
        clock_divider *= 2;
        if (clock_divider >
        {
            clock_divider = 8;
        }
    }
    // Calculate the Final Core Clock, it will be used to calculate the AHB / ARM Core divider later.
    uint32_t core_clock = ((clock_freq == 0) ? FREQ_396MHz : FREQ_528MHz) / clock_divider;
 
    // Calculate the AHB clock divider
    uint32_t ahb_divider = 1;
    while ((core_clock / ahb_divider) > 144000000UL)
    {
        ++ahb_divider;
    }
 
    // Set up AXI_PODF - SEMC clock root
    // Set up AHB_PODF - CORE clock
    // Set up IPG_PODF - BUS clock
    CCM->CBCDR = (CCM->CBCDR & (~(CCM_CBCDR_SEMC_PODF_MASK | CCM_CBCDR_AHB_PODF_MASK | CCM_CBCDR_IPG_PODF_MASK))) |
                 CCM_CBCDR_SEMC_PODF(ahb_divider - 1) | CCM_CBCDR_AHB_PODF(clock_divider - 1) |
                 CCM_CBCDR_IPG_PODF(ahb_divider - 1);
 
    // LPUART clock configuration, peripheral clock 20MHz
    CCM->CSCDR1 =
        (CCM->CSCDR1 & (~(CCM_CSCDR1_UART_CLK_SEL_MASK | CCM_CSCDR1_UART_CLK_PODF_MASK))) | CCM_CSCDR1_UART_CLK_PODF(3);
 
    if (clock_freq == 1) // PRE_PERIPH Clock source is SYS_PLL
    {
        // Pre-peripheral clock configuration
        CCM->CBCMR = (CCM->CBCMR & (~CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)) | CCM_CBCMR_PRE_PERIPH_CLK_SEL(0);
    }
    else // PRE_PERIPH Clock source is PFD_528_PFD3
    {
        // Pre-peripheral clock configuration
        CCM->CBCMR = (CCM->CBCMR & (~CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)) | CCM_CBCMR_PRE_PERIPH_CLK_SEL(2);
    }
 
    // LPSPI clock configuration, Peripheral clock: 20MHz
    CCM->CBCMR = (CCM->CBCMR & (~(CCM_CBCMR_LPSPI_CLK_SEL_MASK | CCM_CBCMR_LPSPI_PODF_MASK))) |
                 CCM_CBCMR_LPSPI_CLK_SEL(0) | CCM_CBCMR_LPSPI_PODF(3);
 
    // FLEXSPI clock configuration, safe frequency: 30MHz
    CCM->CSCMR1 = ((CCM->CSCMR1 & ~(CCM_CSCMR1_FLEXSPI_CLK_SEL_MASK | CCM_CSCMR1_FLEXSPI_PODF_MASK |
                                    CCM_CSCMR1_PERCLK_PODF_MASK | CCM_CSCMR1_PERCLK_CLK_SEL_MASK)) |
                   CCM_CSCMR1_FLEXSPI_CLK_SEL(3) | CCM_CSCMR1_FLEXSPI_PODF(7) | CCM_CSCMR1_PERCLK_PODF(1));
 
    // NOTE: SEMC clock configuration needs handshake, so it will be handled by SEMC driver itself
    // uSDHC1&2 clock configuration
    // SEL: PULLL2 PFD0; DIV: 1 (PFD/2, freq=200MHz)
    CCM->CSCMR1 = (CCM->CSCMR1 & (~(CCM_CSCMR1_USDHC1_CLK_SEL_MASK | CCM_CSCMR1_USDHC2_CLK_SEL_MASK))) |
                  CCM_CSCMR1_USDHC1_CLK_SEL(1) | CCM_CSCMR1_USDHC2_CLK_SEL(1);
    CCM->CSCDR1 = (CCM->CSCDR1 & (~(CCM_CSCDR1_USDHC1_PODF_MASK | CCM_CSCDR1_USDHC2_PODF_MASK))) |
                  CCM_CSCDR1_USDHC1_PODF(1) | CCM_CSCDR1_USDHC2_PODF(1);
 
    // Finally, Enable PLL_ARM, PLL_SYS and PLL_USB1
    CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK;
    CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
 
    // Calculate the Final System Core Clock, it will be used to calculate the AHB / ARM Core divider later.
    SystemCoreClock = ((clock_freq == 0) ? FREQ_396MHz : FREQ_528MHz) / clock_divider;
}
#ifdef __cplusplus
}
#endif

 

 

 

I would be very grateful if you could help me!

Best regards,

Maximilian

0 Kudos
5 Replies

267 Views
m1raculix
Contributor I

Hi Kerry,

thanks for your reply!

What do you mean by "FCB" and what do i need to modify in my code to jump to the reset handler directly?

 

I have attached the bootloader and blink projects below.

The bootloader jumps to the blinky application and the led blinks, only when i comment out the flash.init() line. Otherwise it wont start the application.

The code in the flash.init() is from the evkmimxrt1024_flexspi_not_polling_transfer example, which will work fine if not used in combination with a "jump".

 

Thanks allot and best regards,

Maximilian

0 Kudos

244 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi @m1raculix ,

  Thanks for your updated information.

  From your description, your app should already remove the FCB, and just the secondary bootloader have the FCB.

  About the  flash.init() , do you use the ROM or the flash register code? If it is the ROM API, you need to make sure, leave enough RAM for the ROM code, if it is the flash flexSPI code, you need to copy it to the internal RAM, as the flash can't support the RWW function.

Best Regards,

Kerry

 

0 Kudos

191 Views
m1raculix
Contributor I

Hi Kerry,

What do you mean by remove the FCB?

I have one Application at 0x0 in Flash and one for example at 0xA600. The one at 0x0 will jump to the other if the start conditions allow it. I have no "second" bootloader i guess.

 

For the flash init(): I use the exact code from the flexspi_nor_polling example project for the imxrt1024 evk board and the linker files as well which link the corresponding functions to ram.

 

Best regards,

Maximilian

 

 

0 Kudos

184 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi @m1raculix ,

  This is the FDCB:

kerryzhou_0-1715661164865.png

 Which is used to configure the external flash.

You can check your side, the code after power on to boot should need the FDCB, to the new jumped app, you don't need it, just entry the reset handler is OK.

 

Wish it helps you!

If you still have question about it, please kindly let me know.

Best Regards,

Kerry

 

0 Kudos

287 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi @m1raculix ,

  To your app, you don't need to add the FCB any more, and the jump will need to jump to the reset handler directly for your real app.

  You can attach your current secondary bootloader and the app project, then I can help you to check it on my side, thanks.

Best Regards,

Kerry

0 Kudos