cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3 DISCOVERY - PLL not behaving as expected in IAP code

SimonG
Associate II

Hello, Im writing a bootloader for the STM32F303 and I have some issue with the use of the HSE through the PLL using rcc_clock_setup_pll from libopencm3.

I have three pieces of software on the MCU, flashed using OpenOCD :
- A start bootloader flashed at 0x8000000 (role : select whether we start the main bootloader or the application)
- A main bootloader flashed at 0x8001800 (role : for now simply blink LEDs on the board to see that we entered it, set a flag in RAM to switch to the application, then do a system reset)
- An application flashed at 0x8010000 (simply blinky program started by the start bootloader after the system reset)

My issue :
- If I place the call rcc_clock_setup_pll(&rcc_hse8mhz_configs[RCC_CLOCK_HSE8_72MHZ]); at the start of the start bootloader (and never call it after in the main bootloader / application) it works fine
- If, instead, I place the call at the start of the main bootloader (while also removing the call from the start bootloader), we never exit the function.

After a check with GDB, I see the execution being stuck at two steps :
- After rcc_wait_for_osc_ready(RCC_PLL);
- And if I remove the line above, the execution is stuck at rcc_set_sysclk_source(RCC_CFGR_SW_PLL);

It seems like the PLLRDY flag never becomes true when we wait on it.

Removing the two call "solves" the issue (we exit the function) but the clock is not correctly configured (The MCU does not run on the PLL).

It seems weird to me because the only difference between the two scenarios (put rcc_clock_setup_pll in the start bootloader or in the main bootloader) is the time to reach the function call. Im doing nothing special in between, no clock configuration, no peripheral use,...

For context here is the code that cause problem :

Start bootloader

 

 

 

// From libopencm3 
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock)
{
        if (clock->pllsrc== RCC_CFGR_PLLSRC_HSE_PREDIV) {
                rcc_osc_on(RCC_HSE);
                rcc_wait_for_osc_ready(RCC_HSE);
        } else {
                rcc_osc_on(RCC_HSI);
                rcc_wait_for_osc_ready(RCC_HSI);
        }
        rcc_osc_off(RCC_PLL);
        rcc_usb_prescale_1_5();
        if (clock->usbdiv1) {
                rcc_usb_prescale_1();
        }
        rcc_wait_for_osc_not_ready(RCC_PLL);
        rcc_set_pll_source(clock->pllsrc);
        rcc_set_pll_multiplier(clock->pllmul);
        rcc_set_prediv(clock->plldiv);
        /* Enable PLL oscillator and wait for it to stabilize. */
        rcc_osc_on(RCC_PLL);
        rcc_wait_for_osc_ready(RCC_PLL);
 
        /* Configure flash settings. */
        flash_prefetch_enable();
        flash_set_ws(clock->flash_waitstates);
 
        rcc_set_hpre(clock->hpre);
        rcc_set_ppre2(clock->ppre2);
        rcc_set_ppre1(clock->ppre1);
        /* Select PLL as SYSCLK source. */
        rcc_set_sysclk_source(RCC_CFGR_SW_PLL);
        /* Wait for PLL clock to be selected. */
        rcc_wait_for_sysclk_status(RCC_PLL);
 
        /* Set the peripheral clock frequencies used. */
        rcc_ahb_frequency  = clock->ahb_frequency;
        rcc_apb1_frequency = clock->apb1_frequency;
        rcc_apb2_frequency = clock->apb2_frequency;
}

static void start_application(uint32_t application_vector_table_address, uint32_t offset)
{
    // Clear all pending interrupt requests in NVIC.
    cm_disable_interrupts();
    for (uint8_t i = 0; i < NVIC_IRQ_COUNT; i++)
    {
        nvic_clear_pending_irq(i);
    }

    // Load the vector table address into VTOR.
    SCB_VTOR = application_vector_table_address;
    asm volatile("DSB");

    // Set the MSP with the value from provided by the application vector table.
    asm volatile("MSR MSP, %0" ::"r"(*(uint32_t *)SCB_VTOR));
    asm volatile("ISB");

    // Set privileged access
    uint32_t control_value = 0;
    asm volatile("MSR CONTROL, %0" ::"r"(control_value));
    asm volatile("ISB");

    // Jump to application reset handler, will never return
    cm_enable_interrupts();
    uint32_t address = ((*(uint32_t *)(application_vector_table_address + 4)) + offset);
    ((void (*)(void))(address))();

    while(1);
}

int main(void)
{
    uint32_t* boot_mode = (uint32_t*)BOOT_MODE_ADDR;
    if((*boot_mode) == BOOT_MODE_START_APP)
    {
        // Jump to application
        (*boot_mode) = BOOT_MODE_DEFAULT;
        uint32_t app_address = *((uint32_t *)(FLAGS_ADDR + APP_ADDR_FLAG_OFFSET * sizeof(uint32_t)));
        uint32_t app_offset = app_address - FLASH_START;
        start_application(app_address, app_offset);
    }
    else
    {
        // Jump to the main bootloader
        uint32_t main_btl_address = *((uint32_t *)(FLAGS_ADDR + MAIN_BTL_ADDR_FLAG_OFFSET * sizeof(uint32_t)));
        uint32_t main_btl_offset = main_btl_address - FLASH_START;
        start_application(main_btl_address, main_btl_offset);
    }
    while(1);
    return 0;
}

 

 

 

 

Main bootloader

 

 

 

 

static void blink_reverse(int count){
    /* Enable GPIO clocks. */
    rcc_periph_clock_enable(RCC_GPIOE);

    /* Setup I/O. */
    gpio_mode_setup(LEDS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
                  LED1_MASK | LED2_MASK | LED3_MASK | LED4_MASK |
                  LED5_MASK | LED6_MASK | LED7_MASK | LED8_MASK);

    /* Blink LEDs in reverse order */
    for (int i = 0; i < count; i++)
    {
        gpio_port_write(LEDS_PORT, (uint16_t) ~LED8_MASK);
        gpio_port_write(LEDS_PORT, LED1_MASK);
        delay(1000000);

        gpio_port_write(LEDS_PORT, (uint16_t) ~LED7_MASK);
        gpio_port_write(LEDS_PORT, LED8_MASK);
        delay(1000000);

        gpio_port_write(LEDS_PORT, (uint16_t) ~LED6_MASK);
        gpio_port_write(LEDS_PORT, LED7_MASK);
        delay(1000000);

        gpio_port_write(LEDS_PORT, (uint16_t) ~LED5_MASK);
        gpio_port_write(LEDS_PORT, LED6_MASK);
        delay(1000000);

        gpio_port_write(LEDS_PORT,(uint16_t) ~LED4_MASK);
        gpio_port_write(LEDS_PORT, LED5_MASK);
        delay(1000000);

        gpio_port_write(LEDS_PORT, (uint16_t) ~LED3_MASK);
        gpio_port_write(LEDS_PORT, LED4_MASK);
        delay(1000000);

        gpio_port_write(LEDS_PORT, (uint16_t) ~LED2_MASK);
        gpio_port_write(LEDS_PORT, LED3_MASK);
        delay(1000000);

        gpio_port_write(LEDS_PORT, (uint16_t) ~LED1_MASK);
        gpio_port_write(LEDS_PORT, LED2_MASK);
        delay(1000000);
    }
}

int main(void)
{
    rcc_clock_setup_pll(&rcc_hse8mhz_configs[RCC_CLOCK_HSE8_72MHZ]); // function call in which we stay stuck
    blink_reverse(1);

    // When all done reset the MCU to execute the app.
    volatile uint32_t* boot_mode = (uint32_t*)(BOOT_MODE_ADDR);
    (*boot_mode) = (uint32_t)BOOT_MODE_START_APP;
    asm volatile("DMB");
    scb_reset_system();
    while (1);

    return 0;
}

 

 

 

 

Is there missing checks / precautions in rcc_clock_setup_pll ?

4 REPLIES 4

Not familiar with your library. 

I can tell you that you can't change the running PLL. You must switch to another running clock source like HSI, waiting for the gears to mesh, and once there stop and reconfigure the PLL, start it, wait for it to lock, and then switch to the PLL for the system clock.

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

Thanks for the response!
The weird thing is that Im not running the PLL then trying to change its configuration while it is running.

When I configure the clock tree to use the HSE through the PLL in the main bootloader, the clock tree should be in its default configuration since the only code executed from the "power on" of the MCU is the start bootloader switching mechanism and the jump to the main bootloader using my function start_application (see above).

Maybe its the jump mechanism (in start_application) or the location of the main bootloader cuasing issues ?

There must be something in the code altering the PLL because if I call rcc_clock_setup_pll at the start of the start bootloader it works, if I call it in the after a delay (1000000 nop) at the start of the start bootloader it works BUT if i call it in the main bootloader (while removing the call from the start bootloader) it doesnt work anymore.

 

Amel NASRI
ST Employee

Hi @SimonG,

Similar to @Tesla DeLorean, I don't know the used library as it isn't provided by ST. So, I can't help a lot on it.

Note that in AN2606 STM32 microcontroller system memory boot mode, we say the following about the internal bootloader: 

AmelNASRI_0-1731667641178.png

The following article can be useful in your case: How to share an API between a bootloader and an application.

-Amel

PS: I removed your other 2 threads as they are duplicates of the current one.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Thank you for the reply Amel :)

I have take a look to the documents you shared but I did not helped me a lot.

I understand that the used library is not provided by ST, yet the code shown above is still explicit I think, there is no big hidden code behind.

I also checked that the reset handler of the MCU was not doing unnecessary things in the main-bootloader. I overloaded it and now it looks like this (it simply writes the data and bss segments to ram then start the main:( 

void reset_handler(void)
{
    volatile unsigned *src, *dest;
    for (src=&_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++) {
            *dest = *src;
    }
    while (dest < &_ebss) {
            *dest++ = 0;
    }
    (void)main();
}

Like that I am sure the reset_handler is not causing issues.

I am still not able to configure the PLL with the HSE in the main-bootloader (after removing the clock setuo instruction from the start-bootloader).

I do not get where this clock problem is coming from.

Thank for the help anyway!