cancel
Showing results for 
Search instead for 
Did you mean: 

Costum Bootloader gives hard fault when deleting main program

Jacob L
Associate II
Posted on January 26, 2013 at 09:50

Hi 🙂

I have a problem which I have been trying to solve my self for the last weeks. I am building a custom bootloader which has to work over CAN bus. Bootloader is located at 0x0800000 to 0x08002000 and all function that are used in the bootloader have been declared in this memory area. Upon startup, the bootloader executes and then calls a second main2 function where the main program (which will be deleted and replaced) is located. All this works at startup, I can enter the bootloader and execute the program. So far so good. Now, if the bootloader deletes the flash from 0x08002000 to 0x08010000 then I can verify that this has been deleted ok and that the bootloader itself has not been changed, but when I reset the processor I immediately get a hardfault. It happens before entering the bootloader, so must be in the startup code, but I have not had success to see where. Did I forget to place other parts of the code in the bootloader section? I am using crossworks and my flash_placement file looks like this:

<!DOCTYPE Linker_Placement_File>
<
Root
name
=
''Flash Section Placement''
>
<
MemorySegment
name
=
''$(FLASH_NAME:BOOTLOADER)''
>
<
ProgramSection
alignment
=
''0x100''
load
=
''Yes''
name
=
''.vectors''
start
=
''$(BOOTLOADER_START:)''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.init''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.text3''
/>
<
ProgramSection
alignment
=
''4''
start
=
''0x08001FF0''
size
=
''0x0010''
load
=
''Yes''
inputsections
=
''KEEP (*(.VersionNumBootloader .VersionNumBootloader.*))''
name
=
''.VersionNumBootloader''
/>
</
MemorySegment
>
<
MemorySegment
name
=
''$(FLASH_NAME:FLASH)''
>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
inputsections
=
''KEEP (*(.VersionNum .VersionNum.*))''
name
=
''.VersionNum''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.text''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.dtors''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.ctors''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.rodata''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.ARM.exidx''
address_symbol
=
''__exidx_start''
end_symbol
=
''__exidx_end''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
runin
=
''.fast_run''
name
=
''.fast''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
runin
=
''.data_run''
name
=
''.data''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
runin
=
''.tdata_run''
name
=
''.tdata''
/>
</
MemorySegment
>
<
MemorySegment
name
=
''$(RAM_NAME:RAM);SRAM''
>
<
ProgramSection
alignment
=
''0x100''
load
=
''No''
name
=
''.vectors_ram''
start
=
''$(RAM_START:$(SRAM_START:))''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.fast_run''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.data_run''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.bss''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.non_init''
/>
<
ProgramSection
alignment
=
''4''
size
=
''__HEAPSIZE__''
load
=
''No''
name
=
''.heap''
/>
<
ProgramSection
alignment
=
''4''
size
=
''__STACKSIZE__''
load
=
''No''
name
=
''.stack''
/>
<
ProgramSection
alignment
=
''4''
size
=
''__STACKSIZE_PROCESS__''
load
=
''No''
name
=
''.stack_process''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.tbss''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.tdata_run''
/>
</
MemorySegment
>
<
MemorySegment
name
=
''$(FLASH2_NAME:FLASH2)''
>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.text2''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.rodata2''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
runin
=
''.data2_run''
name
=
''.data2''
/>
</
MemorySegment
>
<
MemorySegment
name
=
''$(RAM2_NAME:RAM2)''
>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.data2_run''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.bss2''
/>
</
MemorySegment
>
</
Root
>

This is part of my map file:

Name Origin Length Attributes
UNPLACED_SECTIONS 0xffffffff 0x00000000 xw
BOOTLOADER 0x08000000 0x00002000 xr
FLASH 0x08002000 0x0000e000 xr
RAM 0x20000000 0x00005000 xw
USB_CAN_RAM 0x40006000 0x00000200 xw
CM3_System_Control_Space 0xe000e000 0x00001000 xw
*default* 0x00000000 0xffffffff
Linker script and memory map
0x0800845c __do_debug_operation = __do_debug_operation_mempoll
0x08008024 __vfprintf = __vfprintf_int_nwp
0x08000000 __BOOTLOADER_segment_start__ = 0x8000000
0x08002000 __BOOTLOADER_segment_end__ = 0x8002000
0x08002000 __FLASH_segment_start__ = 0x8002000
0x08010000 __FLASH_segment_end__ = 0x8010000
0x20000000 __RAM_segment_start__ = 0x20000000
0x20005000 __RAM_segment_end__ = 0x20005000
0x40006000 __USB_CAN_RAM_segment_start__ = 0x40006000
0x40006200 __USB_CAN_RAM_segment_end__ = 0x40006200
0xe000e000 __CM3_System_Control_Space_segment_start__ = 0xe000e000
0xe000f000 __CM3_System_Control_Space_segment_end__ = 0xe000f000
0x00000100 __STACKSIZE__ = 0x100
0x00000000 __STACKSIZE_PROCESS__ = 0x0
0x00000000 __STACKSIZE_IRQ__ = 0x0
0x00000000 __STACKSIZE_FIQ__ = 0x0
0x00000000 __STACKSIZE_SVC__ = 0x0
0x00000000 __STACKSIZE_ABT__ = 0x0
0x00000000 __STACKSIZE_UND__ = 0x0
0x00000080 __HEAPSIZE__ = 0x80
0x20000000 __vectors_ram_load_start__ = ALIGN (__RAM_segment_start__, 0x100)
.vectors_ram 0x20000000 0x0
0x20000000 __vectors_ram_start__ = .
*(.vectors_ram .vectors_ram.*)
0x20000000 __vectors_ram_end__ = (__vectors_ram_start__ + SIZEOF (.vectors_ram))
0x20000000 __vectors_ram_load_end__ = __vectors_ram_end__
0x00000001 . = ASSERT (((__vectors_ram_end__ >= __RAM_segment_start__) && (__vectors_ram_end__ <= __RAM_segment_end__)), error: .vectors_ram is too large to fit in RAM memory segment)
0x08002000 __VersionNum_load_start__ = ALIGN (__FLASH_segment_start__, 0x4)
.VersionNum 0x08002000 0x10
0x08002000 __VersionNum_start__ = .
*(.VersionNum .VersionNum.*)
.VersionNum 0x08002000 0x10 THUMB Release/main.o
0x08002000 Program_Consts
0x08002010 __VersionNum_end__ = (__VersionNum_start__ + SIZEOF (.VersionNum))
0x08002010 __VersionNum_load_end__ = __VersionNum_end__
0x00000001 . = ASSERT (((__VersionNum_end__ >= __FLASH_segment_start__) && (__VersionNum_end__ <= __FLASH_segment_end__)), error: .VersionNum is too large to fit in FLASH memory segment)
0x08002010 __text_load_start__ = ALIGN (__VersionNum_end__, 0x4)
.text 0x08002010 0x64e8
0x08002010 __text_start__ = .
*(.text .text.* .glue_7t .glue_7 .gnu.linkonce.t.* .gcc_except_table .ARM.extab* .gnu.linkonce.armextab.*)
.glue_7 0x00000000 0x0 linker stubs
.glue_7t 0x00000000 0x0 linker stubs

I'm not really an expert in map files and the memory placement files, and this is my first bootloader. This is how the startup works.

int main(void) //Enter Bootloader
{
InitBootloaderHardware_BL();
uint32_t res = 0,res1 = 0;
// Check if a newer image on SPI flash is available.
res = CheckSPIFlashImages_BL(GetSPIFlashImagesProgramversion);
if( Program_Consts.ProgramVersion < res ) 
{
//Check if SPI FLASH image is intact
res = CheckSPIFlashImages_BL(CalculateSPIFlashImagesProgramCRC);
//Compare SPI FLASH CRC value with calculated value
res1 = CheckSPIFlashImages_BL(GetSPIFlashImagesProgramCRC);
if( res == res1 ) 
{
EraseFlashCopyDataFromSPIFlashProgramFlash_BL();
}
}
else
{
main2(); //Main program
}
}

Any help would be very much appreciated. Thank you in advance. Jacob #bootloader-flash_placement.xml
6 REPLIES 6
Posted on January 26, 2013 at 13:13

It looks to be applying the 0x100 alignment to you version number so it isn't place where you want.

You also look to have a debug/printf routine outside the scope of the boot loader.

You could always do some debugging. Add some routines to output progress via the serial port or LEDs, and have a reasonable Hard Fault routine to locate the address of the faulting instruction.

You could have a problem with vectors, or erasing code it depends on.

You could erase the entire memory prior to writing the boot loader and then read back a memory image to compare. You could look at a hex file and determine if it is writing to other regions.

Perhaps you should sanity check the application, or that main2() doesn't contain 0xFFFF, before you jump there?
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Jacob L
Associate II
Posted on January 27, 2013 at 16:26

Hi Clive,

Thanks for your reply. I think I know what is happening now. The problem is not entering main2, the problem was starting up in main() - before it reached main() it would hardfault.

So now I have deleted all code, so there is just an empty main2, and I can see that all the interrupt vectors are still placed outside the boot loader section. Stupid mistake, I am deleting the interrupt vectors when I erase the flash.

My idea was to compile one piece of code including bootloader and main program, then extract the program section and send this for the bootloader to update...

Or would it be better to make two seperate programs; one bootloader and one program? What would I have to do about the interrupt vectors then?

If anyone has suggestions to a nice approach for a bootloader please let me know.

Thanks again.

Jacob

Posted on January 27, 2013 at 16:46

I'd build them as two separate freestanding pieces, and have the application relocate the vector base address using SCB->VTOR (512 byte boundary required)

The SystemInit() in the application could be removed as the chip is already set up in an operating condition by the boot loader.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Jacob L
Associate II
Posted on January 27, 2013 at 17:04

Thanks again Clive, I will try that and post when I run into trouble.

Cheers.

Jacob L
Associate II
Posted on February 03, 2013 at 07:42

I have now made two project, one bootloader and one main application.

I have made a small program to merge the bootloader bin and the program bin to one file, then downloading to stm32 and attaching the debugger. However, I have not been so successful in getting the program to run correctly. I did manage to jump to the program and troggle some LED but the systick interrupt was not working, even if i set the SCB->VTOR. Now it is not working again, so I guess I need to understand the process better. The bootloader calls the main application but I am stuck. I have tried now for some days to find out what kind of startup code that I still need in the main application. So far I have deleted the SystemInit() as suggested by Clive, but what about the interrupt vectors and other initializing done at startup? Does these have to be initialized and then after this I set the VTOR? There is also some stack initializing that I suspect the bootloader will do for me and if I do this again in the startup file then it will hardfault. So my question is: What should the startup sequence in the main program do, once it is called from the bootloader? My flash is still setup like this:

<
MemorySegment
name
=
''$(FLASH_NAME:FLASH)''
>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.vectors''
start
=
''$(FLASH_START:)''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.init''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.text''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.dtors''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.ctors''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.rodata''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
name
=
''.ARM.exidx''
address_symbol
=
''__exidx_start''
end_symbol
=
''__exidx_end''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
runin
=
''.fast_run''
name
=
''.fast''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
runin
=
''.data_run''
name
=
''.data''
/>
<
ProgramSection
alignment
=
''4''
load
=
''Yes''
runin
=
''.tdata_run''
name
=
''.tdata''
/>
<
ProgramSection
alignment
=
''4''
start
=
''0x0800FFF0''
size
=
''0x0010''
load
=
''Yes''
inputsections
=
''KEEP (*(.VersionNum .VersionNum.*))''
name
=
''.VersionNum''
/>
</
MemorySegment
>
<
MemorySegment
name
=
''$(RAM_NAME:RAM);SRAM''
>
<
ProgramSection
alignment
=
''0x100''
load
=
''No''
name
=
''.vectors_ram''
start
=
''$(RAM_START:$(SRAM_START:))''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.fast_run''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.data_run''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.bss''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.non_init''
/>
<
ProgramSection
alignment
=
''4''
size
=
''__HEAPSIZE__''
load
=
''No''
name
=
''.heap''
/>
<
ProgramSection
alignment
=
''4''
size
=
''__STACKSIZE__''
load
=
''No''
name
=
''.stack''
/>
<
ProgramSection
alignment
=
''4''
size
=
''__STACKSIZE_PROCESS__''
load
=
''No''
name
=
''.stack_process''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.tbss''
/>
<
ProgramSection
alignment
=
''4''
load
=
''No''
name
=
''.tdata_run''
/>
</
MemorySegment
>

Anything I need to omit? What do I need to change in my startup file? I have tried to jump from the bootloader to different places in the code, in order to avoid some startup processes, and my only luck was jumping to the __ctors_start__. If someone could explain what I should do next I would be very happy. This is my startup file - I am using Crossworks

.macro ISR_HANDLER name=
.section .vectors, 
''ax''
.word 
ame
.section .init, 
''ax''
.thumb_func
.weak 
ame

ame:
1: b 1b 
// endless loop
.endm
.macro ISR_RESERVED
.section .vectors, 
''ax''
.word 0
.endm
.syntax unified
.global reset_handler
.section .vectors, 
''ax''
.code 16 
.global _vectors 
_vectors:
.word __stack_end__
#ifdef STARTUP_FROM_RESET
.word reset_handler
#else
.word reset_wait
#endif /* STARTUP_FROM_RESET */
ISR_HANDLER NMI_Handler
ISR_HANDLER HardFault_Handler
ISR_HANDLER MemManage_Handler 
ISR_HANDLER BusFault_Handler
ISR_HANDLER UsageFault_Handler
ISR_RESERVED
ISR_RESERVED
ISR_RESERVED
ISR_RESERVED
ISR_HANDLER SVC_Handler
ISR_HANDLER DebugMon_Handler
ISR_RESERVED
ISR_HANDLER PendSV_Handler
ISR_HANDLER SysTick_Handler 
#if defined(__TARGET_LD)
#include ''STM32F10X_LD.vec''
#elif defined(__TARGET_MD)
#include ''STM32F10X_MD.vec''
#elif defined(__TARGET_HD)
#include ''STM32F10X_HD.vec''
#elif defined(__TARGET_XL)
#include ''STM32F10X_XL.vec''
#elif defined(__TARGET_CL)
#include ''STM32F10X_CL.vec''
#elif defined(__TARGET_LD_VL)
#include ''STM32F10X_LD_VL.vec''
#elif defined(__TARGET_MD_VL)
#include ''STM32F10X_MD_VL.vec''
#elif defined(__TARGET_HD_VL)
#include ''STM32F10X_HD_VL.vec''
#elif defined(__TARGET_MD_ULP) || defined(__TARGET_MDP_ULP) || defined(__TARGET_HD_ULP)
#include ''STM32L1XX.vec''
#elif defined(__TARGET_F2XX) || defined(__TARGET_F4XX)
#include ''STM32F2XX.vec''
#if defined(__TARGET_F4XX)
ISR_HANDLER FPU_IRQHandler
#endif
#elif defined(__TARGET_F0XX)
#include ''STM32F0XX.vec''
#elif defined(__TARGET_F30X)
#include ''STM32F30X.vec''
#elif defined(__TARGET_F37X)
#include ''STM32F37X.vec''
#elif defined(__TARGET_W108)
#include ''STM32Wvec''
#else 
#error __TARGET_XX not defined
#endif
.section .vectors, 
''ax''
_vectors_end:
#ifdef VECTORS_IN_RAM
.section .vectors_ram, 
''ax''
_vectors_ram:
.space _vectors_end-_vectors, 0
#endif
.section .init, 
''ax''
.thumb_func
reset_handler:
#ifndef __NO_SYSTEM_INIT
ldr r0, =__RAM_segment_end__
mov sp, r0
bl SystemInit
#endif
#ifdef VECTORS_IN_RAM
ldr r0, =__vectors_load_start__
ldr r1, =__vectors_load_end__
ldr r2, =_vectors_ram
l0:
cmp r0, r1
beq l1
ldr r3, [r0], #4
str r3, [r2], #4
b l0
l1:
#endif
#if defined(__TARGET_F4XX) || defined(__TARGET_F30X) || defined(__TARGET_F37X)
#ifndef __NO_FPU
// Enable CP11 and CP10 with CPACR |= (0xf<<20)
movw r0, 0xED88
movt r0, 0xE000
ldr r1, [r0]
orrs r1, r1, #(0xf << 20)
str r1, [r0]
#ifndef __NO_RUNFAST_MODE
nop
nop
nop 
vmrs r0, fpscr
orrs r0, r0, #(0x3 << 24) 
// FZ and DN
vmsr fpscr, r0
// clear the CONTROL.FPCA bit
mov r0, #0
msr control, r0 
// FPDSCR similarly
movw r1, 0xEF3C
movt r1, 0xE000
ldr r0, [r1]
orrs r0, r0, #(0x3 << 24) 
// FZ and DN
str r0, [r1]
#endif
#endif
#endif
#ifndef __TARGET_F0XX
/* Configure vector table offset register */
ldr r0, =0xE000ED08
#ifdef VECTORS_IN_RAM
ldr r1, =_vectors_ram
#else
ldr r1, =_vectors
#endif
str r1, [r0]
#endif
b _start
#ifndef __NO_SYSTEM_INIT
.thumb_func
.weak SystemInit
SystemInit:
bx lr
#endif
#ifndef STARTUP_FROM_RESET
.thumb_func
reset_wait:
1: b 1b 
/* endless loop */
#endif /* STARTUP_FROM_RESET */

Posted on February 03, 2013 at 14:27

I would enter via the primary SP/PC as defined by the linker, rather than try to pick arbitrary points within the application. The C start up code needs to copy initialized RAM variables and clear other statics. Without this the application will start in a somewhat determinant state.

Perhaps review the IAP application note.

You could just modify the SystemInit() to just do the VTOR setting, as it's the clock and PLL code that is not designed to run a second time. If the boot loader is setting the clock and PLL to maximal/ideal values there isn't any point in doing so again.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..