Skip to main content
DVill
Associate II
September 11, 2026
Question

RAM HAL library code relocation firmware update on single back flash controller (STM32G070)

  • September 11, 2026
  • 1 reply
  • 21 views

Hi, 

I wrote a flash bootloader for STM32G070 using IAR ide.
It gets via modbus RTU the command/data to manage the FSM that does the update procedure.

Because the master during erasing/programming needs a real time update on overall progression, the .intvec table, the main, the modbus stack and the updaing FSM are all relocated in RAM.

With firmware in RAM and a management of FLASH delete/program via IT the firmware can handle modbus during flash programming.

The .intvec relocation is done programmtically, copying it from FLASH (0x08000000) to RAM (0x20000000)  (0xB8 bytes):  I did via explicit firmware because I’m not able to do it via .icf

Also relocated in RAM  stm32g0xx_hal_flash*.o via “initialize by copy” in .icf.

VTOR set to 0x20000000

main entry point and other self-made function as well as modbus stack’s  marked as __ramfunc.

Great, you say, if everyhing works why this topic? 

The truth is: to do all above I did a workaround  because a problem came when I linked HAL_FLASH_IRQHandler.

With HAL_FLASH_IRQHandler linked all the code related to stm32g0xx_hal_flash*.o goes in FLASH, so “initialize by copy” seems failing

But if I clone the HAL_FLASH_IRQHandler or change the signature in __ramfunc void FLASH_IRQHandler(void)  stm32g0xx_hal_flash*.o return “initialize by copy”.


I don’t want to change or rewrite HAL function, but use it.

 At the moment with the workaround the firmware works.

Do you have any idea why linking HAL_FLASH_IRQHandler from HAL does “initialize by copy” failing?

 

Thanks all for your attention.


Below I report my .icf file.

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_4.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_IROM1_start__ = 0x08000000;
define symbol __ICFEDIT_region_IROM1_end__   = 0x08006FFF;
define symbol __ICFEDIT_region_IROM2_start__ = 0x0;
define symbol __ICFEDIT_region_IROM2_end__   = 0x0;
define symbol __ICFEDIT_region_EROM1_start__ = 0x0;
define symbol __ICFEDIT_region_EROM1_end__   = 0x0;
define symbol __ICFEDIT_region_EROM2_start__ = 0x0;
define symbol __ICFEDIT_region_EROM2_end__   = 0x0;
define symbol __ICFEDIT_region_EROM3_start__ = 0x0;
define symbol __ICFEDIT_region_EROM3_end__   = 0x0;
define symbol __ICFEDIT_region_IRAM_intvec_start__ = 0x20000000;
define symbol __ICFEDIT_region_IRAM_intvec_end__  = 0x200000B7;
define symbol __ICFEDIT_region_IRAM1_start__ = 0x200000B8;
define symbol __ICFEDIT_region_IRAM1_end__   = 0x20007FFF;
define symbol __ICFEDIT_region_IRAM2_start__ = 0x20008000;
define symbol __ICFEDIT_region_IRAM2_end__   = 0x20008FFF;
define symbol __ICFEDIT_region_ERAM1_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM1_end__   = 0x0;
define symbol __ICFEDIT_region_ERAM2_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM2_end__   = 0x0;
define symbol __ICFEDIT_region_ERAM3_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM3_end__   = 0x0;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__     = 0x400;
define symbol __ICFEDIT_size_proc_stack__ = 0x0;
define symbol __ICFEDIT_size_heap__       = 0x800;
/**** End of ICF editor section. ###ICF###*/

define memory mem with size = 4G;
define symbol use_IROM1 = (__ICFEDIT_region_IROM1_start__ != 0x0 || __ICFEDIT_region_IROM1_end__ != 0x0);
define symbol use_IROM2 = (__ICFEDIT_region_IROM2_start__ != 0x0 || __ICFEDIT_region_IROM2_end__ != 0x0);
define symbol use_EROM1 = (__ICFEDIT_region_EROM1_start__ != 0x0 || __ICFEDIT_region_EROM1_end__ != 0x0);
define symbol use_EROM2 = (__ICFEDIT_region_EROM2_start__ != 0x0 || __ICFEDIT_region_EROM2_end__ != 0x0);
define symbol use_EROM3 = (__ICFEDIT_region_EROM3_start__ != 0x0 || __ICFEDIT_region_EROM3_end__ != 0x0);
define symbol use_RAM_intvec = (__ICFEDIT_region_IRAM_intvec_start__ != 0x0 || __ICFEDIT_region_IRAM_intvec_end__ != 0x0);
define symbol use_IRAM1 = (__ICFEDIT_region_IRAM1_start__ != 0x0 || __ICFEDIT_region_IRAM1_end__ != 0x0);
define symbol use_IRAM2 = (__ICFEDIT_region_IRAM2_start__ != 0x0 || __ICFEDIT_region_IRAM2_end__ != 0x0);
define symbol use_ERAM1 = (__ICFEDIT_region_ERAM1_start__ != 0x0 || __ICFEDIT_region_ERAM1_end__ != 0x0);
define symbol use_ERAM2 = (__ICFEDIT_region_ERAM2_start__ != 0x0 || __ICFEDIT_region_ERAM2_end__ != 0x0);
define symbol use_ERAM3 = (__ICFEDIT_region_ERAM3_start__ != 0x0 || __ICFEDIT_region_ERAM3_end__ != 0x0);

if (use_IROM1)
{
  define region IROM1_region = mem:[from __ICFEDIT_region_IROM1_start__ to __ICFEDIT_region_IROM1_end__];
}
else
{
  define region IROM1_region = [];
}

if (use_IROM2)
{
  define region IROM2_region = mem:[from __ICFEDIT_region_IROM2_start__ to __ICFEDIT_region_IROM2_end__];
}
else
{
  define region IROM2_region = [];
}
define region IROM_region = IROM1_region | IROM2_region;

if (use_EROM1)
{
  define region EROM1_region = mem:[from __ICFEDIT_region_EROM1_start__ to __ICFEDIT_region_EROM1_end__];
}
else
{
  define region EROM1_region = [];
}
if (use_EROM2)
{
  define region EROM2_region = mem:[from __ICFEDIT_region_EROM2_start__ to __ICFEDIT_region_EROM2_end__];
}
else
{
  define region EROM2_region = [];
}
if (use_EROM3)
{
  define region EROM3_region = mem:[from __ICFEDIT_region_EROM3_start__ to __ICFEDIT_region_EROM3_end__];
}
else
{
  define region EROM3_region = [];
}
define region EROM_region = EROM1_region | EROM2_region | EROM3_region;

if (use_RAM_intvec)
{
  define region RAM_region_intvec = mem:[from __ICFEDIT_region_IRAM_intvec_start__ to __ICFEDIT_region_IRAM_intvec_end__];
}
else
{
  define region IRAM1_region_intvec = [];
}

if (use_IRAM1)
{
  define region IRAM1_region = mem:[from __ICFEDIT_region_IRAM1_start__ to __ICFEDIT_region_IRAM1_end__];
}
else
{
  define region IRAM1_region = [];
}
if (use_IRAM2)
{
  define region IRAM2_region = mem:[from __ICFEDIT_region_IRAM2_start__ to __ICFEDIT_region_IRAM2_end__];
}
else
{
  define region IRAM2_region = [];
}
define region IRAM_region = IRAM1_region | IRAM2_region;

if (use_ERAM1)
{
  define region ERAM1_region = mem:[from __ICFEDIT_region_ERAM1_start__ to __ICFEDIT_region_ERAM1_end__];
}
else
{
  define region ERAM1_region = [];
}
if (use_ERAM2)
{
  define region ERAM2_region = mem:[from __ICFEDIT_region_ERAM2_start__ to __ICFEDIT_region_ERAM2_end__];
}
else
{
  define region ERAM2_region = [];
}
if (use_ERAM3)
{
  define region ERAM3_region = mem:[from __ICFEDIT_region_ERAM3_start__ to __ICFEDIT_region_ERAM3_end__];
}
else
{
  define region ERAM3_region = [];
}
define region ERAM_region = ERAM1_region | ERAM2_region | ERAM3_region;

do not initialize  { section .noinit };
initialize by copy { readwrite };

                        
if (isdefinedsymbol(__USE_DLIB_PERTHREAD))
{
  // Required in a multi-threaded application.o
  initialize by copy with packing = none { section __DLIB_PERTHREAD };
}

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
// place at address mem:__ICFEDIT_region_IRAM_intvec_start__ { section .intvec_init };

//initialize by copy { object utils.o };
initialize by copy { object stm32g0xx_hal_flash.o };
initialize by copy { object stm32g0xx_hal_flash_ex.o };
//initialize by copy { object stm32g0xx_it.o };
//initialize by copy { 
//                      object stm32g0xx_hal.o        ,
//                      object stm32g0xx_hal_cortex.o ,
//                      object stm32g0xx_hal_flash.o  ,
//                      object stm32g0xx_hal_gpio.o   ,
//                      object stm32g0xx_hal_tim.o    ,
//                      object stm32g0xx_hal_tim_ex.o ,
//                      object stm32g0xx_ll_rcc.o     ,
//                      object stm32g0xx_ll_usart.o   ,
//                      object stm32g0xx_ll_utils.o,
//                      object ABImemcpy.o ,
//                      object I32DivModFast.o,
//                      object uread4.o,
//                      object lz77_init.o,
//                      object system_stm32g0xx.o,
//                      section .intvec
//                    };

initialize by copy {  readwrite };


if (!isempty(IROM_region))
{
  place in IROM_region  { readonly };
}


if (!isempty(EROM_region))
{
  place in EROM_region  { readonly section application_specific_ro };
}

//if (!isempty(RAM_region_intvec))
//{
//    define block RAM_INTVEC    { section .intvec_rw };
//    place in RAM_region_intvec { block RAM_INTVEC };
//
//}

if (!isempty(IRAM_region))
{
  define block CSTACK     with alignment = 8, size = __ICFEDIT_size_cstack__     { };
  define block PROC_STACK with alignment = 8, size = __ICFEDIT_size_proc_stack__ { };
  define block HEAP       with alignment = 8, size = __ICFEDIT_size_heap__       { };
  place in IRAM_region { readwrite, block CSTACK, block PROC_STACK, block HEAP };
  
}

if (!isempty(ERAM_region))
{
  place in ERAM_region  { readwrite section application_specific_rw };
}

 

1 reply

Pavel A.
September 17, 2026

IIRC “initialize by copy” just copies without relocation.  This works for data but not for position-dependent code.

All the involved code should be *located* at the address in RAM.

Please refer to the IAR docum how to do this in the icf script  (I don’t have IAR currently, cannot validate what my AI says).

But even better, write your own compact code for flashing (and locate it in the RAM) because the HAL code is fluffy and the RAM of TM32G070 is quite small.