cancel
Showing results for 
Search instead for 
Did you mean: 

Crossworks Implementation of In-Application Bootloader for STM32 High-Density Devices

mcgilvra2
Associate II
Posted on August 30, 2012 at 20:31

ST's AN2557 app note explains In-Application Programming using a USART.  Unfortunately, the example software that comes with the app note does not include a Crossworks implementation.  Many good lessons have been learned in creating this one, with much help from Michael Johnson of Rowley Associates.  I hope you can benefit from it.

  1. Pertinent Items:

    1. Properties - To set a property, right-click on the Project name (not Solution) and select Properties.

      1. Load Offset - under Debugger

      2. Load Offset Symbol Limit - under Debugger

      3. Emit Relocations - under Linker

      4. Additional Output Format - under Linker

      5. Memory Map File - under Build

      6. Section Placement File - under Build

    2. Memory-Map file

      1. This defines the SRAM and Flash segment addresses.

      2. Default location is ''C:\Users\Albert\AppData\Local\Rowley Associates Limited\CrossWorks for ARM\packages\targets\ST_STM32F10x\ST_STM32F103VE_MemoryMap.xml''  

      3. You can make a copy of the default file in your project directory, edit it, and point to it with the Memory Map File property.

    3. Section-Placement file

      1. This defines what program sections (.text, .data, etc.) get put in what segments defined in the Memory-Map file. 

      2. Default location is ''C:\Program Files (x86)\Rowley Associates Limited\CrossWorks for ARM 2.1\targets\flash_placement.xml''

      3.  You should not need to edit this file but if you do, make a copy in your project folder and point to it with the Section Placement property.

  2. Relocation.  In order to implement a bootloader you will have to place the bootloader at a different memory location than the target app (that which the bootloader will load).  

    1. It's arbitrary weather the bootloader is below or above the target app in memory.  But above seems better to me because then an existing app can be downloaded as is with the bootloader.  Also, on power-up or reset you would usually want your target app to run.  By default code location begins at 0x08000000, the bottom of flash, so a power-on or reset will go there and execute your target app instead of your bootloader.

    2. To relocate code you have two options:

    3. Option 1 (Preferred) - Edit the Memory-Map file, err... a copy of it.  Use NotePad++ or similar to edit.

      1. At the bottom of the file you will see:  <MemorySegment size=''0x80000'' access=''ReadOnly'' name=''FLASH'' start=''0x08000000''/>

      2. Change to:  <MemorySegment size=''0x70000'' access=''ReadOnly'' name=''FLASH'' start=''0x08010000''/> if you want to relocate at 0x08010000.  Note that ''start'' must be a multiple of 0x800 because that's the flash page size.

      3. Note, you must reduce ''size'' by whatever you have added to ''start''.

      4. This is the preferred method because it also puts the relocation info in the .bin output file which is the file that will get downloaded with the bootloader.

    4. Option 2 - Set the Load Offset related properties

      1. Set the Load Offset property to the desired load address offset, so if you want to load 0x10000 above beginning of flash, set it to 0x10000.  Note that Load Offset must be a multiple of 0x800 because that's the flash page size.

      2. Set the Load Offset Symbol Limit to 0x08080000, i.e., top of flash.  This limits the offsetting to within flash.  If you don't set this, the offsetting will also be applied to SRAM addresses which start at 0x20000000.  With only 64K of SRAM an offset approaching 0x10000 will relocate SRAM accesses outside the 64K limit and a bus-fault / hard-fault will be generated. 

      3. Set Emit Relocations property to Yes.  This tells the linker to pay attention to the Load Offset properties.

      4. This is not the preferred method because the .bin file will not contain the relocation info.  You can capture a .bin with the relocation info by loading the program area into a Memory window in Crossworks, the right-click Save to Binary.  The size can be determined from the generated .bin file with HexEdit or similar.

  3. Generating the target app.  

    1. Assuming your target app will be loaded into the bottom of flash, no project changes are needed other than to set the Additional Output Format property to bin.  

    2. If your target app will go into higher memory then certain things must be done:

      1. Relocation of target app by one of the above methods.

      2. ApplicationAddress in bootloader common.h will have to be changed from 0x08000000 to the higher place you want the target app loaded to.

      3. ST's application note AN2557 also says you should relocate the vector table at the target app load address using the ''NVIC_SetVectorTable''function or the VECT_TAB_OFFSET definition inside the ''system_stm32f10x.c''.  I have not found this to be necessary and don't understand enough to know why.

  4. Examples  

    1. ETM IAP is the example bootloader.

    2. ETM Base is the example target app.  This target app jumps back to the bootloader after a few seconds so you can play around without continually resetting.

  5. Notes

    1. When the IAP code wants to jump to the downloaded target code, it must add 0x235 to the target's load address.  The entry point is actually 0x234 from the beginning but only odd jump addresses are allowed in ARM so you must add one.  It will resolve to 0x234 and jump correctly.

    2. The simplest way is to allow your target app to load at the default zero offset (0x08000000), then you don't need to worry about relocating it.  Now for the IAP bootloader, relocate it someplace well above the end of your target app (look at target app.bin to see how far it goes in flash).

    3. If you load only the example IAP bootloader, then power-cycle or reset with no code down at 0x08000000 then nothing will happen.  The bootloader will not run because the power-on/reset vector defaults to the bottom of flash.  You must load some code at the bottom that will jump to the bootloader.  Normally the target app would have some sort of Hyperterminal user interface that would allow the user to select Re-Flash, then the target would jump to the bootloader.  Alternatively, you could use the state of a GPIO connected to a (pushbutton or jumper) in your target app to control whether it runs or jumps to bootloader on startup.

6 REPLIES 6
Posted on August 30, 2012 at 21:27

''It's arbitrary weather the bootloader is below or above the target app in memory.  But above seems better to me because then an existing app can be downloaded as is with the bootloader.  Also, on power-up or reset you would usually want your target app to run.  By default code location begins at 0x08000000, the bottom of flash, so a power-on or reset will go there and execute your target app instead of your bootloader.''

 

 

Putting the boot loader on top increases the chances you'll brick your product. The front sectors are also smaller in the F2 and F4 designs, and lockable. It also allows the boot loader to validate the user application before blindly jumping into it. So I'm not convinced whether the choice is arbitrary.   

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mcgilvra2
Associate II
Posted on August 30, 2012 at 22:55

I guess it depends on what your trying to do.  I was trying to minimize changes to a target app that is mature, large, and complex.  I don't want to move that pig.   Plus I put the bootloader very high so I'm not worried about bricking the target app in.  But I agree, a general-purpose bootloader might be better down low, just depends on your situation.

Long live the clive!

Posted on August 30, 2012 at 23:21

Things must be simpler in Keil, you'd pretty much click a dialog and define the application region in ROM/RAM. I've been using the linker to handle the vector table symbol, and program the NVIC explicitly with that value. At that point it's agnostic to location, and RAM vs FLASH, provided you keep a 512 byte alignment.

There is the scatter file method too, or the linker script in GNU/GCC.

The linker should resolved everything, if it doesn't you've got bigger problems to worry about.

A power or process fail during the erase/flash phase of a front loaded application just scares me a lot.

System_Init()

extern void * __Vectors;

    NVIC_SetVectorTable((u32)(&__Vectors), 0x0); // Smart Base Location

STARTUP.S

; Vector Table Mapped to Address 0 at Reset

                AREA    RESET, DATA, READONLY

                EXPORT  __Vectors

                EXPORT  __Vectors_End

                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp               ; Top of Stack

                DCD     Reset_Handler              ; Reset Handler

                DCD     NMI_Handler                ; NMI Handler

                DCD     HardFault_Handler          ; Hard Fault Handler

                DCD     MemManage_Handler          ; MPU Fault Handler

                DCD     BusFault_Handler           ; Bus Fault Handler

                DCD     UsageFault_Handler         ; Usage Fault Handler

...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on August 31, 2012 at 01:02

Fantastic summary by the way, I'd +1 the parent but the forum software assumes everything is a question, amongst it's other failures.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mcgilvra2
Associate II
Posted on September 17, 2012 at 17:47

  1. Update: Must disable Systick before jumping to bootloader (IAP) from target application (i.e., when your ready to re-flash) if target app ever enabled SysTick:
    1. SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (0<<SYSTICK_ENABLE) | (0<<SYSTICK_TICKINT); //Disable SysTick IRQ and counter
    2. Reason:  Flash erase/write disable all interrupts external to the ARM core but not Systick, NMI, exceptions, etc.  If you do not disable Systick, it continues to execute its ISR back in the target app.  As soon as the target area flash is erased in IAP, the Systick ISR is gone and attempting to execute it generates an exception.

mcgilvra2
Associate II
Posted on September 17, 2012 at 18:25

Wish I could edit my posts...

Turns out TIM4 ISR causes a problem too.  So final solution was to

  __disable_irq();   //disables interrupts

in target app just before jumping to IAP bootloater.  Then, in IAP:

NVIC_SystemReset(void);  //force a reset, will execute target app loaded at 0x08000000