Malloc is interrupted by an unexpected interrupt - c

I met a strange problem. I use Eclipse Oxygen.2, windows 10, J-linker, STM32L4R5ZI, STM32CubeMX V1.0 ver 4.26.0, arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 227977]
The problem: whenever I want to use the malloc function, I end up in WWDG_IRQHandler() (Default_Handler: Infinit_Loop) and never go back from malloc.
The Linker script:
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 640K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
}
the main function:
int main(void)
{
HAL_Init();
SystemClock_Config();
uint8_t *tab = malloc(100);
MX_GPIO_Init();
MX_TIM1_Init();
HAL_TIM_OC_Start_IT(&htim1, TIM_CHANNEL_1);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);
while (1)
{
}
}
The _sbrk:
_sbrk(int incr)
{
extern char _Heap_Begin; // Defined by the linker.
extern char _Heap_Limit; // Defined by the linker.
static char* current_heap_end;
char* current_block_address;
if (current_heap_end == 0)
{
current_heap_end = &_Heap_Begin;
}
current_block_address = current_heap_end;
// Need to align heap to word boundary, else will get
// hard faults on Cortex-M0. So we assume that heap starts on
// word boundary, hence make sure we always add a multiple of
// 4 to it.
incr = (incr + 3) & (~3); // align value to 4
if (current_heap_end + incr > &_Heap_Limit)
{
// Some of the libstdc++-v3 tests rely upon detecting
// out of memory errors, so do not abort here.
#if 0
extern void abort (void);
_write (1, "_sbrk: Heap and stack collision\n", 32);
abort ();
#else
// Heap has overflowed
errno = ENOMEM;
return (caddr_t) - 1;
#endif
}
current_heap_end += incr;
return (caddr_t) current_block_address;
}
Scripts:
Sections.ld
/*
* Default linker script for Cortex-M (it includes specifics for STM32F[34]xx).
*
* To make use of the multi-region initialisations, define
* OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS for the _startup.c file.
*/
/*
* The '__stack' definition is required by crt0, do not remove it.
*/
__stack = ORIGIN(RAM) + LENGTH(RAM);
_estack = __stack; /* STM specific definition */
/*
* Default stack sizes.
* These are used by the startup in order to allocate stacks
* for the different modes.
*/
__Main_Stack_Size = 1024 ;
PROVIDE ( _Main_Stack_Size = __Main_Stack_Size ) ;
__Main_Stack_Limit = __stack - __Main_Stack_Size ;
/* "PROVIDE" allows to easily override these values from an
* object file or the command line. */
PROVIDE ( _Main_Stack_Limit = __Main_Stack_Limit ) ;
/*
* There will be a link error if there is not this amount of
* RAM free at the end.
*/
_Minimum_Stack_Size = 256 ;
/*
* Default heap definitions.
* The heap start immediately after the last statically allocated
* .sbss/.noinit section, and extends up to the main stack limit.
*/
PROVIDE ( _Heap_Begin = _end_noinit ) ;
PROVIDE ( _Heap_Limit = __stack - __Main_Stack_Size ) ;
/*
* The entry point is informative, for debuggers and simulators,
* since the Cortex-M vector points to it anyway.
*/
ENTRY(_start)
/* Sections Definitions */
SECTIONS
{
/*
* For Cortex-M devices, the beginning of the startup code is stored in
* the .isr_vector section, which goes to FLASH.
*/
.isr_vector : ALIGN(4)
{
FILL(0xFF)
__vectors_start = ABSOLUTE(.) ;
__vectors_start__ = ABSOLUTE(.) ; /* STM specific definition */
KEEP(*(.isr_vector)) /* Interrupt vectors */
KEEP(*(.cfmconfig)) /* Freescale configuration words */
/*
* This section is here for convenience, to store the
* startup code at the beginning of the flash area, hoping that
* this will increase the readability of the listing.
*/
*(.after_vectors .after_vectors.*) /* Startup code and ISR */
} >FLASH
.inits : ALIGN(4)
{
/*
* Memory regions initialisation arrays.
*
* Thee are two kinds of arrays for each RAM region, one for
* data and one for bss. Each is iterated at startup and the
* region initialisation is performed.
*
* The data array includes:
* - from (LOADADDR())
* - region_begin (ADDR())
* - region_end (ADDR()+SIZEOF())
*
* The bss array includes:
* - region_begin (ADDR())
* - region_end (ADDR()+SIZEOF())
*
* WARNING: It is mandatory that the regions are word aligned,
* since the initialisation code works only on words.
*/
__data_regions_array_start = .;
LONG(LOADADDR(.data));
LONG(ADDR(.data));
LONG(ADDR(.data)+SIZEOF(.data));
LONG(LOADADDR(.data_CCMRAM));
LONG(ADDR(.data_CCMRAM));
LONG(ADDR(.data_CCMRAM)+SIZEOF(.data_CCMRAM));
__data_regions_array_end = .;
__bss_regions_array_start = .;
LONG(ADDR(.bss));
LONG(ADDR(.bss)+SIZEOF(.bss));
LONG(ADDR(.bss_CCMRAM));
LONG(ADDR(.bss_CCMRAM)+SIZEOF(.bss_CCMRAM));
__bss_regions_array_end = .;
/* End of memory regions initialisation arrays. */
/*
* These are the old initialisation sections, intended to contain
* naked code, with the prologue/epilogue added by crti.o/crtn.o
* when linking with startup files. The standalone startup code
* currently does not run these, better use the init arrays below.
*/
KEEP(*(.init))
KEEP(*(.fini))
. = ALIGN(4);
/*
* The preinit code, i.e. an array of pointers to initialisation
* functions to be performed before constructors.
*/
PROVIDE_HIDDEN (__preinit_array_start = .);
/*
* Used to run the SystemInit() before anything else.
*/
KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))
/*
* Used for other platform inits.
*/
KEEP(*(.preinit_array_platform .preinit_array_platform.*))
/*
* The application inits. If you need to enforce some order in
* execution, create new sections, as before.
*/
KEEP(*(.preinit_array .preinit_array.*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/*
* The init code, i.e. an array of pointers to static constructors.
*/
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/*
* The fini code, i.e. an array of pointers to static destructors.
*/
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/*
* For some STRx devices, the beginning of the startup code
* is stored in the .flashtext section, which goes to FLASH.
*/
.flashtext : ALIGN(4)
{
*(.flashtext .flashtext.*) /* Startup code */
} >FLASH
/*
* The program code is stored in the .text section,
* which goes to FLASH.
*/
.text : ALIGN(4)
{
*(.text .text.*) /* all remaining code */
/* read-only data (constants) */
*(.rodata .rodata.* .constdata .constdata.*)
*(vtable) /* C++ virtual tables */
KEEP(*(.eh_frame*))
/*
* Stub sections generated by the linker, to glue together
* ARM and Thumb code. .glue_7 is used for ARM code calling
* Thumb code, and .glue_7t is used for Thumb code calling
* ARM code. Apparently always generated by the linker, for some
* architectures, so better leave them here.
*/
*(.glue_7)
*(.glue_7t)
} >FLASH
/* ARM magic sections */
.ARM.extab : ALIGN(4)
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
. = ALIGN(4);
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
. = ALIGN(4);
_etext = .;
__etext = .;
/* MEMORY_ARRAY */
/*
.ROarraySection :
{
*(.ROarraySection .ROarraySection.*)
} >MEMORY_ARRAY
*/
/*
* The secondary initialised data section.
*/
.data_CCMRAM : ALIGN(4)
{
FILL(0xFF)
*(.data.CCMRAM .data.CCMRAM.*)
. = ALIGN(4) ;
} > CCMRAM AT>FLASH
/*
* This address is used by the startup code to
* initialise the .data section.
*/
_sidata = LOADADDR(.data);
/*
* The initialised data section.
*
* The program executes knowing that the data is in the RAM
* but the loader puts the initial values in the FLASH (inidata).
* It is one task of the startup to copy the initial values from
* FLASH to RAM.
*/
.data : ALIGN(4)
{
FILL(0xFF)
/* This is used by the startup code to initialise the .data section */
_sdata = . ; /* STM specific definition */
__data_start__ = . ;
*(.data_begin .data_begin.*)
*(.data .data.*)
*(.data_end .data_end.*)
. = ALIGN(4);
/* This is used by the startup code to initialise the .data section */
_edata = . ; /* STM specific definition */
__data_end__ = . ;
} >RAM AT>FLASH
/*
* The uninitialised data sections. NOLOAD is used to avoid
* the "section `.bss' type changed to PROGBITS" warning
*/
/* The secondary uninitialised data section. */
.bss_CCMRAM (NOLOAD) : ALIGN(4)
{
*(.bss.CCMRAM .bss.CCMRAM.*)
} > CCMRAM
/* The primary uninitialised data section. */
.bss (NOLOAD) : ALIGN(4)
{
__bss_start__ = .; /* standard newlib definition */
_sbss = .; /* STM specific definition */
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .; /* standard newlib definition */
_ebss = . ; /* STM specific definition */
} >RAM
.noinit_CCMRAM (NOLOAD) : ALIGN(4)
{
*(.noinit.CCMRAM .noinit.CCMRAM.*)
} > CCMRAM
.noinit (NOLOAD) : ALIGN(4)
{
_noinit = .;
*(.noinit .noinit.*)
. = ALIGN(4) ;
_end_noinit = .;
} > RAM
/* Mandatory to be word aligned, _sbrk assumes this */
PROVIDE ( end = _end_noinit ); /* was _ebss */
PROVIDE ( _end = _end_noinit );
PROVIDE ( __end = _end_noinit );
PROVIDE ( __end__ = _end_noinit );
/*
* Used for validation only, do not allocate anything here!
*
* This is just to check that there is enough RAM left for the Main
* stack. It should generate an error if it's full.
*/
._check_stack : ALIGN(4)
{
. = . + _Minimum_Stack_Size ;
} >RAM
/*
* The FLASH Bank1.
* The C or assembly source must explicitly place the code
* or data there using the "section" attribute.
*/
.b1text : ALIGN(4)
{
*(.b1text) /* remaining code */
*(.b1rodata) /* read-only data (constants) */
*(.b1rodata.*)
} >FLASHB1
/*
* The EXTMEM.
* The C or assembly source must explicitly place the code or data there
* using the "section" attribute.
*/
/* EXTMEM Bank0 */
.eb0text : ALIGN(4)
{
*(.eb0text) /* remaining code */
*(.eb0rodata) /* read-only data (constants) */
*(.eb0rodata.*)
} >EXTMEMB0
/* EXTMEM Bank1 */
.eb1text : ALIGN(4)
{
*(.eb1text) /* remaining code */
*(.eb1rodata) /* read-only data (constants) */
*(.eb1rodata.*)
} >EXTMEMB1
/* EXTMEM Bank2 */
.eb2text : ALIGN(4)
{
*(.eb2text) /* remaining code */
*(.eb2rodata) /* read-only data (constants) */
*(.eb2rodata.*)
} >EXTMEMB2
/* EXTMEM Bank0 */
.eb3text : ALIGN(4)
{
*(.eb3text) /* remaining code */
*(.eb3rodata) /* read-only data (constants) */
*(.eb3rodata.*)
} >EXTMEMB3
/* After that there are only debugging sections. */
/* This can remove the debugging information from the standard libraries */
/*
DISCARD :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
*/
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/*
* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0.
*/
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}
STM32L4R5ZI Flash.ld
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L4R5ZITx Device with
** 2048KByte FLASH, 640KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x200A0000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x800; /* required amount of heap */
_Min_Stack_Size = 0x860; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 640K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(8);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(8);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

You are not necessarily ending up in the WWDG_IRQ function. You are ending up in the default interrupt handler function which is the infinite loop. This function is the destination for many of the processor exceptions set up by STMCubeMX. You will end up in the same place if you get a bus fault interrupt due to accessing a non existent memory location. I have seen on a number of debuggers that they will say that you are in the WWDG_IRQ function regardless of which interrupt/exception actually took you there.
I would expect that in your malloc function you are attempting to access an illegal address and generating a processor exception. Single step through the function and you can localise the problem.

I had to change the STM32L4R5ZI_Flash script and remove the sections script (so I use only one script now).
Unfortunately, _Heap_Begin and _Heap_Limit take valuses which I cannot explain, but at least it works.
The changed script:
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L4R5ZITx Device with
** 2048KByte FLASH, 640KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x200A0000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x2000; /* required amount of heap */
_Min_Stack_Size = 0x4000; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 640K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(8);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(8);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
_Heap_Begin = __bss_end__ ;
_Heap_Limit = _Heap_Begin + _Min_Heap_Size;
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

Related

ARM does not branch properly from FLASH to RAM

I have an STM32H750 ARM Cortex M7 processor and am compiling C code using STM32CubeIDE. I want to have default code in FLASH that is able to run the application by itself but which can also load an updated application to RAM and run the update from RAM. Eventually the update will have different initialized variables and jump tables so my thinking is that it would make sense for the branch from FLASH to RAM to be in the startup code before that initialization takes place. However, for the moment, the default and update source code are identical except for the update branch-to address (more on that later). Eventually this has to work with RDP2 security, but for the moment RDP2 is not set.
The startup code looks for a magic cookie set by successfully loading the update and branches to the ContinueInit address in the update. I have not included the reset and interrupt vectors.
Reset_Handler:
ldr sp, =_estack /* set stack pointer */
ldr r1, =0x580244dc
ldr r2, =0xe0000000
str r2, [r1] /* turn on the RAM1-3 clocks - this is essential! */
ldr r0, =0x580244d0
ldr r1, [r0] /* get the value in the reset status register */
ldr r2, =0x00460000
cmp r2, r1 /* compare reset status to external reset value */
ldr r2, =0x00010000
str r2, [r0] /* clear the reset status register */
bne ContinueInit /* use default code if not from external reset */
ldr r0, =magic_cookie
ldr r1, [r0] /* get the value in the magic cookie */
ldr r2, =0x12345678
cmp r2, r1 /* compare magic cookie to update value */
bne ContinueInit /* use default code if no cookie match */
ldr r2, =0x00100010
str r2, [r0] /* clear the magic cookie */
b UpdateContinueInit
ContinueInit:
/* Copy the data segment initializers from code to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* branch to the default main program */
bl main
bx lr
Separate .ld files govern the linking of default and update. The FLASH Continue_Init address appears in the update .ld file to maintain similarity between default and update.
/\* Default Entry Point \*/
ENTRY(Reset_Handler)
/\* Highest address of the user mode stack */
\_estack = 0x20020000; /* end of DTCMRAM */
/* Generate a link error if heap and stack don't fit into RAM */
\_Min_Heap_Size = 0x400; /* required amount of heap */
\_Min_Stack_Size = 0x800; /* required amount of stack \*/
/\* 1mS counter location used by ISR \*/
uwTick = 0x20000000;
magic_cookie = 0x20000004;
UpdateContinueInit = 0x24014572;
/\* Specify the memory areas \*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
DTCMRAM (xrw) : ORIGIN = 0x20000008, LENGTH = 0x1fff8
RAM123 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
}
/\* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /\* Startup code \*/
. = ALIGN(4);
} \>FLASH
/\* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
(.text) /* .text sections (code) */
(.text*) / .text sections (code) \*/
*(.glue_7) /* glue arm to thumb code \*/
*(.glue_7t) /* glue thumb to arm code \*/
\*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} \>FLASH
/\* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
(.rodata) /* .rodata sections (constants, strings, etc.) */
(.rodata*) / .rodata sections (constants, strings, etc.) \*/
. = ALIGN(4);
} \>FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.\*) } \>FLASH
.ARM : {
\__exidx_start = .;
*(.ARM.exidx*)
\__exidx_end = .;
} \>FLASH
.preinit_array :
{
PROVIDE_HIDDEN (\__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (\__preinit_array_end = .);
} \>FLASH
.init_array :
{
PROVIDE_HIDDEN (\__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (\__init_array_end = .);
} \>FLASH
.fini_array :
{
PROVIDE_HIDDEN (\__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (\__fini_array_end = .);
} \>FLASH
/\* used by the startup to initialize data \*/
\_sidata = LOADADDR(.data);
/\* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
\_sdata = .; /* create a global symbol at data start */
(.data) /* .data sections */
(.data*) / .data sections \*/
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} \>DTCMRAM AT\> FLASH
/\* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
\_sbss = .; /* define a global symbol at bss start \*/
__bss_start__ = \_sbss;
\*(.bss)
*(.bss*)
\*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} \>RAM123
/\* User_heap_stack section, used to check that there is enough RAM left \*/
.\_user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( \_end = . );
. = . + \_Min_Heap_Size;
. = . + \_Min_Stack_Size;
. = ALIGN(8);
} \>DTCMRAM
/\* Remove information from the standard libraries \*/
/DISCARD/ :
{
libc.a ( \* )
libm.a ( \* )
libgcc.a ( \* )
}
.ARM.attributes 0 : { \*(.ARM.attributes) }
}
/* Update Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20020000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x400; /* required amount of heap */
_Min_Stack_Size = 0x800; /* required amount of stack */
/* 1mS counter location used by ISR */
uwTick = 0x20000000;
magic_cookie 0= 0x20000004;
UpdateContinueInit = 0x08014572;
/* Specify the memory areas */
MEMORY
{
DTCMRAM (xrw) : ORIGIN = 0x2000008, LENGTH = 0x1fff8
AXIRAM (xrw) : ORIGIN = 0x24000000, LENGTH = 0x80000
RAM123 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into RSTRAM */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >AXIRAM
/* The program code and other data goes into AXIRAM */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >AXIRAM
/* Constant data goes into AXIRAM */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >AXIRAM
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >AXIRAM
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >AXIRAM
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >AXIRAM
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >AXIRAM
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >AXIRAM
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >DTCMRAM AT> AXIRAM
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM123
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >DTCMRAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
(It looks like stackoverflow has added some backward slashes.)
Not only does the update code always lock up - it locks up in different places. By setting different bits in the magic cookie and examining them after the next reset I have seen it lock up on the branch to UpdateContinueInit, before it finished with the update's .bss, on the branch to or inside the update's __libc_init_array, and sometime after branching to the update's main.
When running the default's main I have tried a long branch to a small subroutine in the the update and that works. I have checked the list files and setting the vector table offset register in SystemInit is correct in both cases. Trying to examine the the fault registers starting at 0xe000dc28 hasn't indicated anything.
The default in FLASH runs fine by itself when not trying to branch to the update. I am confident that the default loads the update into RAM properly. The update runs properly if I set the boot address register to the update's isr_vector, write the update to RAM via JTAG, and reset the processor.
I am hoping that someone has successfully done this before and can point me to the nuance of this processor that I am missing.
Thanks.

Locating the ROM address of a RAM variable

I'm wondering if there's a way to obtain the ROM address used to seed the initial value of a RAM variable? Given a statement static uint32_t foo = 0x12345678; the initial value 0x12345678 is present as ROM somewhere to serve as the initial value at &foo. At some point in time I'd like to be able to reset the value of foo to it's initial state.
I could create a second variable const static uint32_t initial_foo = 0x12345678; to use but that will then double the ROM data space needed to store variables for this use case.
Can the offset &foo from the beginning of RAM (or more specifically &_srelocate, see the linker script below) be reliably correlated with one of the symbols in ROM space?
Selected parts of the ARM/GNU C linker v 6.3.1 script are below.
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00100000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000;
__ram_end__ = ORIGIN(ram) + LENGTH(ram) - 4;
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
/* .bss and stack sections removed */
. = ALIGN(4);
_end = . ;
}
Instead of having one RAM variable type foo = value;, simply make one variable const type foo = value; and ensure it is allocated in ROM (should be the case if the variable has static storage duration). Then manually copy it to RAM as needed. This way the value is only stored once in ROM; initializers of ROM variables are not stored separately.
Then you won't be wasting any memory and you won't have to worry about somehow searching through .rodata for the initializer value, which would be rather questionable practice.

Adding a fixed value to an address using the linker file

I have an embedded system that I am designing using a GNU toolchain. One of the requirements is that it needs to calculate the checksum of the executable code (ROM) at runtime, and compare it to a known value. Depending on weather the calculated value is equal to the known value it will throw an error or not. I need to place the known value in flash memory( where my executable code is stored) in a way that won't change the executable code. AKA I cannot write the value to the flash in my executable code.
I know there are tools that can modify output files to place a checksum in a known address, but for IT reasons external tools are not an option. I decided to use the SHORT() command in the linker and just edit the linker to place the known checksum in a known address at write time. It is not working, and I do not know why.
Relevent Portions of the Linker Script I have:
MEMORY {
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400
m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
m_interrupts_ram (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00000400
m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x000FFBE0
m_data (RX) : ORIGIN = 0x1FFF0400, LENGTH = 0x0000FC00
m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}
SECTIONS
{
.text :
{
. = ALIGN(4);
*(.fill)
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
} > m_text
.... More similar sections
....down at the bottom right before stack/heap definition
__ChecksumStart = 0xFFFE0;
.checksum : AT(__ChecksumStart)
{
. = ALIGN (0x4);
SHORT(0xABCD)
} > m_text
__ChecksumSize = SIZEOF(.checksum);
.heap :
{
. = ALIGN(8);
__end__ = .;
PROVIDE(end = .);
__HeapBase = .;
. += HEAP_SIZE;
__HeapLimit = .;
} > m_data_2
.stack :
{
. = ALIGN(8);
. += STACK_SIZE;
} > m_data_2
__StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2);
__StackLimit = __StackTop - STACK_SIZE;
PROVIDE(__stack = __StackTop);
.ARM.attributes 0 : { *(.ARM.attributes) }
} //end of SECTIONS block here
I should be able to look at location 0xFFFE0 in my executable code and see 0xABCD. I do not. I see 0xFFFFFFFF the default value. What do I need to change to make this work? I have looked at this tutorial to get this far

Placing variables at specific address generates large binary file

I have to place array at specific address in memory. I'm using GCC.
I declare variable like this:
uint8_t __attribute__((section (".mySection"))) buffer[1234];
And in linker script I've got:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 145K
MYSEC (x) : ORIGIN = 0x20025000, LENGTH = 155K
}
and later:
.mySection :
{
*(.mySection);
} > MYSEC
It's of course code for embedded system (ARM). Normally my program takes 22 KB, with this modification it takes 384 MB (!).
I don't understand why. If I remove __attribute__ it takes 22 KB again.
What am I missing?
Code used:
#inculde (...)
uint8_t __attribute__((section (".mySection"))) buffer = 5;
int main(void){
buffer = 10;
}
Full linker script (default, not written by me, parts are shortened:
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20050000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 145K
MYSEC (x) : ORIGIN = 0x20025000, LENGTH = 155K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
(...)
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
(...)
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
(...)
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
(...)
} >FLASH
.preinit_array :
{
(...)
} >FLASH
.init_array :
{
(...)
} >FLASH
.fini_array :
{
(...)
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
(...)
} >RAM AT> FLASH
.mySection :
{
*(.mySection);
} > MYSEC
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
(...)
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
(...)
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
(...)
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
I assume your output file is a pure binary format, not an ELF so you don't have ELF bootloader. In that case, placing initialized data at high address obviously will create a big output file. This is because in the binary format you don't have any mechanism to provide specific address, so the file is mapped 1:1 into memory. It means the whole address space up to your custom initialized variable needs to be included in the output file.
This is the same situation as with .data section and this is why the .data section is explicitly copied from Flash into RAM area at the startup.
p.s. You can find my article helpful (this issue is described there).

STM32F103x_XL FLASH bank 2 stays BUSY

I am using an STM32F103ZG with the STM32F10x_StdPeriph Library. I started the development of the project with Keil ARM-MDK but now moved over to GCC.
The switch over has gone pretty smooth until now. I use the last page of FLASH as a configuration page to store product specific parameters. This is page is obviously situated in bank 2. In certain instances these configuration parameters need to be updated at runtime, but now that I have moved over to GCC, the second memory bank goes into a busy state as soon as I try to write to it and then it stays busy until I cycle the power. Erase works fine, but writing fails.
I do unlock all the FLASH and make sure that all the clocks are initialized to access the FLASH. Some other posts on several forums suggest a problem with my linker file, but all the examples I use make no difference.
If anyone can tell me what I am doing wrong I will be very grateful.
Thanks,
H
_Min_Heap_Size = 0x800; /* required amount of heap */
_Min_Stack_Size = 0x800; /* required amount of stack */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x10000
FLASH_CFG (rx) : ORIGIN = 0x080FF800, LENGTH = 0x80
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x18000
}
SECTIONS
{
.text :
{
_stext = .; /* Provide the name for the start of this section */
CREATE_OBJECT_SYMBOLS
KEEP(*(.vectors))
*(.text)
*(.text.*)
. = ALIGN(4); /* Align the start of the rodata part */
*(.rodata)
*(.rodata.*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4); /* Align the end of the section */
} > FLASH
_etext = .; /* Provide the name for the end of this section */
.data : AT (_etext)
{
. = ALIGN(4); /* Align the start of the section */
_sdata = .; /* Provide the name for the start of this section */
*(.data)
*(.data.*)
. = ALIGN(4); /* Align the start of the fastrun part */
*(.fastrun)
*(.fastrun.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_edata = .; /* Provide the name for the end of this section */
.bss :
{
. = ALIGN(4); /* Align the start of the section */
_sbss = .; /* Provide the name for the start of this section */
*(.bss)
*(.bss.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_ebss = .; /* Provide the name for the end of this section */
._user_heap_stack :
{
. = ALIGN(4);
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
_estack = ORIGIN(RAM) + LENGTH(RAM);
.static_cfg :
{
. = ALIGN(4);
*(.static_cfg)
*(.static_cfg.*)
. = ALIGN(4);
} > FLASH_CFG
_estatic_cfg = .;
_end = .;
PROVIDE (end = .);
}
Well I managed to solve my problem.
When I moved over to GCC, I obviously had to recompile the STM32F10x Peripheral library and I lef the optimization setting to -O3. This was not allowed initially as the __STREXH and __STREXL core functions needed to be changed in order to build for the selected optimization. I found the following solution on a forum:
change __ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) ); to
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
Several comments related to this solution specified that this solution does not cause any errors.
When I use the original code and set the optimization to -O0, everything works just fine. The access to the on-chip FLASH interface is 16bit and therefore if you screw up the above mentioned functions, all 16bit write accesses will be screwed up.
As I don't need optimization at this stage, I will stay without it.
Any suggestions about how to update these functions correctly for use with optimization will be appreciated.
Enjoy,
H

Resources