I intended to leave a comment but I cant because I'm rookie. So I will try an answer, be gentle.
The method I use for IAP is:
- Load the new firmware in a safe location (in eeprom, ext flash etc...)
- Check the integrity of the firmware against its hash for example
- Copy the routines for FLASH-programming the internal CPU flash into SRAM.
- Disable ALL interrupts
- Call the FLASH-programming routines.
- Trigger a software reset request to boot the new firmware
Now the above method works if you upgrading the entire firmware of the CPU. Also assumes that you dont need interrupts during the flash programming. If you do need to have interrupts during the flash programming things are a bit more complicated. You have to do some extra steps before you call the flash programming routines in order to copy all the interrupt related code into SRAM also.
- Load the new firmware in a safe location (in eeprom, ext flash etc...)
- Check the integrity of the firmware against its hash for example
- Copy the routines for FLASH-programming the internal CPU flash into SRAM.
- Disable ALL interrupts
- Allocate enough ram to fit the vectors in.
- Copy vectors to that address
- Enable the interrupts you need during the flash programming.
- Call the FLASH-programming routines.
- Trigger a software reset request to boot the new firmware
One important thing
This method has a very tricky part. It is the calls between the code you have in SRAM. The compiler associates the names of the functions to addresses in the 0x0800000 memory location (which is the flash). For example the function void flash_byte(uint32_t address, uint8_t byte);
lives somewhere in flash. When you copy this function to ram lets say to 0x20001000 you have to be specific in the function call. Remember you try to erase the entire flash and re-write it you can not call functions from flash. The method I use is a call via function pointers. For ex:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
/*
* Function pointers
*/
typedef void (*flash_write_ft) (void);
typedef void (*flash_sub_call_ft) (uint32_t lala);
flash_write_ft flash_write_pointer = (flash_write_ft)0;
flash_sub_call_ft flash_sub_call_pointer = (flash_sub_call_ft)0;
/*
* Helper functions
*/
size_t get_function_size (uint32_t *address) {
size_t s=0;
// ...
// s = calculate size;
return s;
}
int copy_function (uint32_t *from, uint32_t *to, size_t s) {
// ...
return 0; // OK!!
}
/*
* Flash programming functions
*/
void flash_sub_call (uint32_t lala) {
// lala tata
}
void flash_write (void) {
uint32_t foo;
// ...
flash_sub_call_pointer (foo); // call via pointer here
// ...
}
int main(void) {
size_t s;
uint32_t *add;
// Get firmware, check integrity etc...
// copy to ram
s = get_function_size ((uint32_t*)&flash_sub_call);
add = (uint32_t*)malloc (s);
copy_function ((uint32_t*)&flash_sub_call, add, s);
flash_sub_call_pointer = (flash_sub_call_ft)add;
s = get_function_size ((uint32_t*)&flash_write);
add = (uint32_t*)malloc (s);
copy_function ((uint32_t*)&flash_write, add, s);
flash_write_pointer = (flash_sub_call_ft)add;
// IAP
flash_write_pointer ();
return EXIT_SUCCESS;
}
In this example all the function calls are via pointers pointing into RAM, so when you copy them to RAM they will work.
For extra info:
1) flash programming manual
2) Cortex-m3 programming manual