I'm contributing to a project that was developed in Coocox CoIDE 2.0.6 for STM32F103RB (128Kb flash). I have to write a custom boot loader using CoIDE that can upgrade the application to the flash via serial. I started writing the boot loader in .c, at the moment it creates some console messages then tries to jump to the application immediately. I'm using this example: https://embetronicx.com/tutorials/microcontrollers/stm32/stm32f1-bootloader/stm32f1-firmware-update-using-custom-bootloader/ As you might found out already, I'm having trouble jumping to the "main" application - it just hangs. I 'm obviously not an expert on the matter.

I created a custom .ld file to the main app:

  FLASH (rx) : ORIGIN = 0x08004400, LENGTH = 111K
  RAM (rwx) : ORIGIN = 0x200000EC, LENGTH = 20K - 0xEC

Also I added this to the main app code:

#define VECT_TAB_OFFSET 0x00004400U

I uploaded the bootloader to 0x08000000 and the main app to 0x08004400 via STLink.

If I look to the .bin file, I see at BASEADDRESS + 4U an address that seems correct: 0x08004ab5. If I'm right, the boot loader should read this entry point address from 0x08004404 and then jump to it. However, I can see in the console "Go to app^@^@" then nothing happens. I also have little clue how to effectively debug an STM32, I've been working with Arduinos before. Could you please guide me by reviewing the code? Thank you much!


#include "main.h"
#include <stdbool.h>
#include <stdio.h>

#define ETX_APP_START_ADDRESS   0x08004400
UART_HandleTypeDef huart2;

void SystemClock_Config(void);
static void MX_USART2_UART_Init(void);
static void goto_application( void );

int main(void){



  printf("Go to app\r\n");

  while (1){


void SystemClock_Config(void){

  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

  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)

static void MX_USART2_UART_Init(void){
  // USART2 init
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK){


int fputc(int ch, FILE *f){
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;

static void goto_application( void ){

    typedef void (*jump_app)(void) __attribute__((noreturn));

    uint32_t *_vectable = (__IO uint32_t*)ETX_APP_START_ADDRESS;  // point _vectable to the start of the application at 0x08004400

    jump_app app_jump = (jump_app) *(_vectable + 1);   // get the address of the application's reset handler (4th byte in the table)
    SCB->VTOR = _vectable;


void Error_Handler(void){
  while (1)


#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {

#include "stm32f1xx_hal.h"

void Error_Handler(void);

#ifdef __cplusplus

#endif /* __MAIN_H */

FYI I don't own the main app, I'm using a simple Blink example for that.

  • \$\begingroup\$ So, what did debugging the software tell you? \$\endgroup\$
    – Justme
    Jun 21, 2023 at 20:59
  • \$\begingroup\$ Do you have 'real' debugging tools which allow you to step through the code line-by-line, or are you still stuck in the 'just download it and let it run and see what happens' paradigm? \$\endgroup\$
    – brhans
    Jun 22, 2023 at 4:06
  • \$\begingroup\$ This is the biggest pain. It's a custom hardware (not a Bluepill development board) and I only have UART2 for debugging. I also have a header with SW_CLK, SW_IO, 3.3V and GND for upload. Is there any way to do debug using these pins? Sorry for my ignorance but I only started with this platform and there are quite a few restrictions. :( \$\endgroup\$
    – Otto
    Jun 22, 2023 at 15:23
  • 2
    \$\begingroup\$ Is there any way to do debug using these pins? Yes, that's a SWD debug interface and it is supported by the ST-LINK probe (among many others). \$\endgroup\$
    – nanash1
    Jun 22, 2023 at 15:46
  • \$\begingroup\$ Maybe we're getting somewhere. I've installed STM32CubeIDE instead of Coocox (despite I've been told not to do). Now the debug is not broken anymore. Just before app_jump() _vectable points to 0x8004400 (OK), its in 0x20005000 (I guess it's the stack so also OK) and app_jump points to 0x8004ab5 (also seems OK). When I click 'continue' nothing seems to happen, the debug runs but I can see nothing. I guess I should see some assembly output? \$\endgroup\$
    – Otto
    Jun 22, 2023 at 18:30

1 Answer 1


I removed the fputc() function, the printf() calls and also the include to stdio.h. I also removed HAL_DeInit() and now the code works. I can still write to console using HAL_UART_Transmit() directly so that's not a problem. I can't explain why these changes made it work.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.