Electronics > Microcontrollers

STM32G4: Jump to bootloader mode Bus Fault (Makefile)

(1/2) > >>

betocool:
Hi all,

I'm working on an STM32G491 processor, and one of our requirements is to have a UART bootloader. No biggie, the controller has a UART (and several other) bootloaders in the system memory. In the past I've used it with USB and DFU and it works alright.

The development environment is the usual STM32CubeIDE with initialising over CubeMX. I'm using FreeRTOS as well, but I was able to jump into bootloader mode by using this code (reference only):

--- Code: ---#include "bootload.h"

const uint8_t bootload_cmd[5] = BOOTLOAD_COMMAND;

void (*JumpToApplication)(void);

void bootload_enable(void)
{
    /* Disable LPUART1 */
    HAL_UART_DeInit(&hlpuart1);
    HAL_UART_DeInit(&huart1);
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Send system to sleep */
    vTaskSuspendAll();
    vPortRaiseBASEPRI();


    /* Disable all interrupts */
    __disable_irq();

    /* Disable Systick timer */
    SysTick->CTRL = 0;

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

    /* Re-enable all interrupts */
    __enable_irq();

    /* Set the main stack pointer to the boot loader stack */
    __set_MSP(*(uint32_t *)BOOTLOADER_ADDRESS);

    /* Jump to system memory bootloader */
    JumpToApplication = (void (*)(void)) (*((uint32_t *) ((BOOTLOADER_ADDRESS + 4))));
    JumpToApplication();

    while(1);
}

--- End code ---

Anyway, the code works.

A few days later I decided I want to switch to VSCode for coding, compiling and flashing. I followed a few instructions online and it's not as hard as it seems. CubeMX generates a Makefile of the project, what could possibly go wrong?

Well, I had to adapt most of the flags between what the IDE was doing and what the makefile was telling the compiler. I "think" I managed most of it, but to be fair I might have missed the odd flag here or there. So or so, after a few trial and error I was able to run my application OK. Everything worked as expected, and compilation, flashing, etc worked well.

At some point I tested again the "enter bootloader" mode, but that failed miserably. After a lot of testing and some debugging later I found out that the micro went into HardFault mode, and it happened just by trying to enter the "JumpToApplication()" address. The complaint was a BusFault error (I think, I don't have the code open anymore).

I went back to compile with the IDE, and lo and behold, it all works fine again. So for the time being I'm coding in VS code and using a 1.7GB IDE to click the compile and flash buttons  ???

I'm guessing that I'm missing some flag, option or something that tells the micro to allow jumping to that address, but from what I've looked (not extensively) I cannot find the difference between the Makefile flags and the IDE flags. At some point I even copied them verbatim. I might have missed the assembler flags. As additional information, I'm using the arm-none-eabi-gcc binaries that are part of the IDE (plugin.blablabla.stmarm....) and I am flashing using the ST-Link V2. For flashing with the makefile I used:


--- Code: ---flash:
STM32_Programmer_CLI -c port=SWD freq=4000 -w $(BUILD_DIR)\$(TARGET).elf

--- End code ---

Have you guys had issues with that before? Any information where I should be looking at is appreciated. It's not a dealbreaker fortunately, more like an annoyance...

Cheers,

Alberto

eutectique:
First, you should not re-enable the interrupts. You came to the point of no return, setting the new stack, and the last thing you would want is an interrupt.

Then, is there any difference in generated assembly code?

Also, step through assembly instructions in the debugger. Is there anything unexpected?

A better option -- use AIRCR.

An even better and cleaner hardware reset, as opposed to just jumping to reset vector, is watchdog reset. Your peripherals would be in a known state.

ataradov:
Yes, use AIRCR.

Separate  __set_MSP() and JumpToApplication() is not the best idea and the results may vary depending on compiler optimization settings. You should really do that in an atomic assembly section, since you can't use the old stack after __set_MSP().

betocool:
Thanks, I will look into AIRCR, I'm not aware of what it is to be honest.

I will also try out your other suggestions. I did try going the Reset route reading backup registers, but for some reason that didn't quite work for me. Might try it again sometime

Cheers,

Alberto

ataradov:
Assuming  you are using standard CMSIS harder files for the core peripherals, then you have a convenient function defined - NVIC_SystemReset(). Just call that, it will write the AIRCR.

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod