cancel
Showing results for 
Search instead for 
Did you mean: 

Run app to jump bootloader stm32G

Abus-k
Associate

Hello everyone, for a few days I have been struggling with skipping and running the bootloader on stm32g474ret6 via usart.

I have an STM, 12MHz crystal, and an FTDI chip on my own PCB, with RTS/CTS disconnected for now. After sending a command via USART, the control LED lights up, but the bootloader doesn't start. What am I doing wrong?

#include <stdint.h>
#include "stm32g4xx.h"
#include "stm32g4xx_hal.h"

#define SYS_MEM_BASE 0x1FFF0000

void JumpToBootloader(void)
{
    __disable_irq();


    SysTick->CTRL = 0;


    for (int i = 0; i < 8; i++) {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }
    __DSB(); __ISB();


    HAL_DeInit();
    HAL_RCC_DeInit();


    __HAL_RCC_HSI_ENABLE();
    while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET);
    __HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_HSI);

    __DSB(); __ISB();


    uint32_t msp   = *(__IO uint32_t *)(SYS_MEM_BASE + 0x0);
    uint32_t reset = *(__IO uint32_t *)(SYS_MEM_BASE + 0x4);


    SCB->VTOR = SYS_MEM_BASE;
    __DSB(); __ISB();


    __set_MSP(msp);
    void (*BootJump)(void) = (void (*)(void))reset;
    BootJump();

    while (1) { }
}

ob.png

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main 
  ******************************************************************************
  * @attention
  * Copyright (c) 2025 ST.
  * This software is provided AS-IS.
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "fdcan.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "bootjump.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
static uint8_t rx1;          
static char     cmd_buf[64]; 
static uint8_t  cmd_len = 0; 
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
static inline void UART1_StartRxIT(void);
static void Handle_Command_Line(const char *line);
static void UART1_Diag(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

static inline void UART1_StartRxIT(void)
{
  if (HAL_UART_Receive_IT(&huart1, &rx1, 1) != HAL_OK) {
    __HAL_UART_CLEAR_OREFLAG(&huart1);
    __HAL_UART_CLEAR_FEFLAG(&huart1);
    __HAL_UART_CLEAR_NEFLAG(&huart1);
    (void)HAL_UART_Receive_IT(&huart1, &rx1, 1);
  }
}


static void Handle_Command_Line(const char *line)
{
  //  cut CR/LF/itp
  size_t n = strlen(line);
  while (n && (line[n-1] == '\r' || line[n-1] == '\n' || line[n-1] == ' ' || line[n-1] == '\t')) {
    n--;
  }

  
  char tmp[sizeof(cmd_buf)];
  size_t m = (n < sizeof(tmp) - 1) ? n : (sizeof(tmp) - 1);
  for (size_t i = 0; i < m; i++) {
    char c = line[i];
    if (c >= 'a' && c <= 'z') c = (char)(c - 32);
    tmp[i] = c;
  }
  tmp[m] = 0;

  
  if ((strcmp(tmp, "UPDATE") == 0) || (strcmp(tmp, "BOOT") == 0)) {

    const char *msg =
      "OK: entering ROM bootloader jumping now.\r\n"
      "Reconnect as 115200, 8E1 and send 0x7F.\r\n";
    (void)HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 200);

    // LED na PA8
    for (int i = 0; i < 3; ++i) {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
      HAL_Delay(120);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
      HAL_Delay(120);
    }
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
    HAL_Delay(200);

    
    JumpToBootloader();
    return;
  }

  
  if (m > 0) {
    const char *unk = "Use only: UPDATE\r\n";
    (void)HAL_UART_Transmit(&huart1, (uint8_t*)unk, strlen(unk), 100);
  }
}


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance != USART1) return;

  uint8_t c = rx1;

  
  static uint8_t last_cr = 0;
  if (c=='\r' || c=='\n') {
    if (c=='\r') last_cr=1;
    else if (c=='\n' && last_cr){ last_cr=0; UART1_StartRxIT(); return; }

    (void)HAL_UART_Transmit(&huart1,(uint8_t*)"\r\n",2,20);
    cmd_buf[cmd_len]=0;
    Handle_Command_Line(cmd_buf);
    cmd_len=0;
    UART1_StartRxIT();
    return;
  }
  last_cr=0;

  
  if (cmd_len < sizeof(cmd_buf)-1) {
    cmd_buf[cmd_len++] = (char)c;
    (void)HAL_UART_Transmit(&huart1,&c,1,10); // echo
  } else {
    cmd_len=0;
    const char *msg="\r\nERR: line too long\r\n";
    (void)HAL_UART_Transmit(&huart1,(uint8_t*)msg,strlen(msg),50);
  }

  UART1_StartRxIT();
}

static void UART1_Diag(void)
{
  uint32_t cr3 = READ_REG(USART1->CR3);
  if (cr3 & (USART_CR3_CTSE | USART_CR3_RTSE)) {
    for (int i=0;i<5;i++){ HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); HAL_Delay(80); }
    CLEAR_BIT(USART1->CR3, USART_CR3_CTSE | USART_CR3_RTSE);
  }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1) {
    __HAL_UART_CLEAR_OREFLAG(huart);
    __HAL_UART_CLEAR_FEFLAG(huart);
    __HAL_UART_CLEAR_NEFLAG(huart);
    UART1_StartRxIT();
  }
}
/* USER CODE END 0 */


int main(void)
{
  HAL_Init();
  SystemClock_Config();

 

  
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_FDCAN1_Init();
  MX_FDCAN2_Init();
  MX_USART1_UART_Init();
  UART1_Diag();

  const char *hello =
    "READY: USART1. Type 'UPDATE' to enter ROM bootloader.\r\n";
  (void)HAL_UART_Transmit(&huart1,(uint8_t*)hello,strlen(hello),200);

  UART1_StartRxIT();

  while (1)
  {
    
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
  }
}


void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); }
}

/* USER CODE BEGIN 4 */
/* USER CODE END 4 */

void Error_Handler(void)
{
  __disable_irq();
  while (1) { }
}

#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
  (void)file; (void)line;
}
#endif /* USE_FULL_ASSERT */

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

Don't jump from within an interrupt context. Set a flag and jump from the main thread instead.

Don't disable interrupts without re-enabling them.

Working jump to bootloader code is here:

How to jump to system bootloader from application ... - STMicroelectronics Community

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

View solution in original post

1 REPLY 1
TDK
Super User

Don't jump from within an interrupt context. Set a flag and jump from the main thread instead.

Don't disable interrupts without re-enabling them.

Working jump to bootloader code is here:

How to jump to system bootloader from application ... - STMicroelectronics Community

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