2013-07-17 01:43 AM
Hi,
I would like to add in-application programming (IAP) to my design. Of course, this is supported by the chip, with built in bootloader, etc. But in our system there are a number of chips distributed around the machine which communicate through a custom switched rs232 system and we need to be backwards compatible - we can't add wires. As I understand it, the built in IAP would only work with the chip physically wired to the PC USB port - and even then we would have to add something to control the boot pin.I have full control of messaging to all the cards in our program and could prepare a memory image of the new firmware in RAM. So all I would need would be a routine to erase the normal system flash and write the new image to it.Ideally this would be my own''boot'' program, that can work with our existing communications plan, fixed in a different (hopefully protected) area of flash.Can anyone point me in the right direction for this?Thanks #relocate #code-execute-sram #run-from-ram2013-07-17 03:02 AM
The ISP (In System) provided by the System Loader can use USART1 or USART3, the protocol is described in manuals, and source is available in the Flash Demonstrator. The protocol could be used on an embedded target and isn't that complicated.
The IAP (In Application) example use a simplified Y-Modem. Many other methods are viable. If you have the new image in RAM or other secondary storage, you can flash and execute from the device. Be aware that erasing the part is slow, and that both erase/write operations while running from flash are possible, but execution is stalled significantly. This will negatively effect system response, and can cause peripheral over/under run conditions when you miss their service window requirements.2013-07-17 03:36 AM
Thanks, I'm having a look at the Flash_Program example.
Just stepping through the first few lines, it has set StartSector to 16 and EndSector to 40, but checking the memory organisation section in the chip manual, it shows only sectors 0 to 11 for the stm32f40x??What's going on here?2013-07-17 03:41 AM
sorry, stepped into GetSector, the number is 8 times the sector number
2013-07-17 04:43 AM
Ok, the Flash_Program example works fine, that's great.
So I can get my new firmware into ram and erase and program the flash. But I need to run my old program while erasing / writing the program flash. Can I just copy my existing program to ram and jump to it there? Does it simply relocate? Of course, if there's a problem (crash / power) during the process I won't be able to recover without going through ST-Link but I think that's a reasonable compromise.Am I getting this right or do I need to do it a different way? Any examples about copying flash to ram and running it there?THanks2013-12-10 03:37 PM
I'm actually looking for a solution to this exact same problem: relocating code from flash to ram and then receiving a new image over the network and flashing it to the chip.
I already have a small bootloader in the first 128K of flash and the application lives in the rest of the flash. Currently, the bootloader is able to flash the application image since it's not running from the same flash sectors and then boot to it. So that works fine. However, a new requirement is forcing me to have to modify the bootloader so it's also field upgradable and due to legacy design, we can't use the built in system bootloader. So, I'm trying to relocate the code from flash into ram without success. I believe I have my vector table relocated successfully (map file shows it starting at 0x2000000) and the system boots. However, when I try to relocate the .text section into RAM, nothing comes up. I'm guessing that the stack pointer or program counter is not being set correctly./*
*****************************************************************************
**
** File : stm32_flash.ld
**
** Abstract : Linker script for STM32F207IGT6 Device with
** 1024KByte FLASH, 128KByte 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
**
** Environment : Atollic TrueSTUDIO(R)
**
** Distribution: The file is distributed �as is,� without any warranty
** of any kind.
**
** (c)Copyright Atollic AB.
** 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. Atollic AB permit registered Atollic TrueSTUDIO(R) 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 Atollic TrueSTUDIO(R) toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20020000; /* end of 128K RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 1024; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 127K
/* This value MUST match the FLASH_BOOTLDR_FW_VER_ADDRESS address in the bootloader_info.h */
BTLDRINFO(rx) : ORIGIN = 0x0801FC00, LENGTH = 1K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >RAM AT >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.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);
_etext = .; /* define a global symbols at end of code */
} >RAM AT >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM AT >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >RAM AT >FLASH
.ARM.attributes : { *(.ARM.attributes) } >RAM AT >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 (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
/* TODO: This is a hack, since . seems to be set to .ARM.attributes. */
/* Is this because of PROVIDE_HIDDEN above? Dunno! */
/* /TW */
_sidata = .;
/*_sidata = __fini_array_end;*/
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
/* *(.ramfunctions) .ramfunctions section */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM
/* 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
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
/* Bootloader version and date written to flash */
.btldrInfo :
{
. = ALIGN(4);
KEEP(*(.btldrInfo))
. = ALIGN(4);
} >BTLDRINFO
/* MEMORY_bank1 section, code must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (''.mb1text''))); */
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
}
If you look at the .text section, if I use ''>FLASH'' everything works fine but as soon as I change it to ''>RAM AT >FLASH'' or ''>RAM'', nothing boots. Any ideas?
I should specify:
I'm using CodeSourcery compiler on STM32F
2013-12-10 04:18 PM
If you look at the .text section, if I use ''>FLASH'' everything works fine but as soon as I change it to ''>RAM AT >FLASH'' or ''>RAM'', nothing boots. Any ideas?
Yeah, I'm hard pressed to get my head around what that's supposed to achieve. The processor is probably having similar problems.One critical problem is that the vector table has fixed addresses. If you just want to copy the exact same image into RAM and expect it to run, then perhaps consider building it for address ZERO instead of 0x08000000, and have the ''usable'' RAM up at 0x20010000, copy 64KB from 0x08000000 to 0x20000000 and change the mapping/shadowing going on at 0x00000000. If the code is already executing there changing the mapping will be like doing a fork()Consider also if you can payload the new loader in as something wrapped like a new app. ie flasher + new loaderThe last thing you want to do is erase the loader without a complete replacement ready to put there.2013-12-10 04:50 PM
Yeah, I'm hard pressed to get my head around what that's supposed to achieve. The processor is probably having similar problems.
My understanding is that tells the linker to flash to the FLASH address and then load it into RAM. That's what it seems to be doing with the .isr_vector section, which has the exact same directive. I am definitely remapping the vector table (and that's where it shows up in the map file). The image boots fine when with this directive on the isr_vector section. One critical problem is that the vector table has fixed addresses. If you just want to copy the exact same image into RAM and expect it to run, then perhaps consider building it for address ZERO instead of 0x08000000, and have the ''usable'' RAM up at 0x20010000, copy 64KB from 0x08000000 to 0x20000000 and change the mapping/shadowing going on at 0x00000000. If the code is already executing there changing the mapping will be like doing a fork() I think that's what's happening (at least that's what I'm trying to do). Here's the relevant section of my startup code:/**
******************************************************************************
* @file startup_stm32f2xx_cl.S
* @author MCD Application Team
* @version V3.4.0
* @date 10/15/2010
* @brief STM32F10x Connectivity line Devices vector table for Atollic
* toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR
* address.
* - Configure the clock system
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M3 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
*******************************************************************************
* @copy
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <
h2
><
center
>© COPYRIGHT 2010 STMicroelectronics</
center
></
h2
>
*/
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
.equ BootRAM, 0xF1E0F85F
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash 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
/* Call the application's entry point.*/
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* @param None
* @retval : None
*/
.section .text.Default_Handler,''ax'',%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,''a'',%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
....
Consider also if you can payload the new loader in as something wrapped like a new app. ie flasher + new loader. The last thing you want to do is erase the loader without a complete replacement ready to put there.
I realize that this is dangerous but this is not a safety critical device and management wants a fallback in case they ever need to upgrade bootloader. Worst case scenario, someone has to go out to a customer site and manually put on the new bootloader and this is what they do now so this would still be an improvement.
2013-12-10 05:52 PM
But I suspect it's not booting because the processor has some very specific requirements in order to get to the point where you can execute some other code in the C runtime's startup to actually do these copies and moves. You get some circular dependencies, or at very least things aren't where they need to be early enough for the scheme to succeed? To understand why the thing doesn't boot you need to disassemble what you've actually succeeded in building and step through it in your head. Look at the .MAP and .HEX
The processor always assumes you are booting from the words at ZERO, you get away with linking at 0x08000000 because the immediate effect is to jump into the real location from that of the shadow. Registers external to the core cause the same block of memory to be decoded at multiple locations in the memory map. Try linking your current loader at ZERO and observe that it still functions.2013-12-10 06:09 PM
Rule#1 for Boot Loaders is to make and test them completely enough so they don't need replacing, ever, this is a lot easier to enforce if they are committed to ROM, and someone has to sign a big check to make it happen, and someone else loses their job if they bugger it up.
FLASH makes it easier to break that rule, but my primary loader is only 16KB and has a very specific and narrow task. If it really has to change it's small enough to hold in RAM, or as a updateable resource within the application. The flashing code I copy to RAM is also very small.