cancel
Showing results for 
Search instead for 
Did you mean: 

stm8s flash entire new program - how?

papadeltasierra
Associate III

Let's assume I have a program that exposes a serial interface for commands and one such command is "load new program".  I upload the new program as hex strings and the old program writes this to flash and the resets.  Hopefully at this point the new program starts up.

Now the peripheral library gives three examples but they write either to EEPROM or just tiny bits of data to flash and it appears that only the calls to FLASH_ProgramBlock() and FLASH_EraseBlock() run from RAM.

Since I am rewriting up-to ALL the flash memory, do I need to wrap and entire method in RAM() so that the entire processing, from the UART receiving hex to the writing to flash gets run from RAM?  I assume I cannot risk any of the old program (or at least the update method) running from anything other than RAM because I might be overwriting the flash copy of the old program.

Is that correct?  Anyone point me at an example of this or some documentation beyond PM0051?

Thanks,

Paul DS.

4 REPLIES 4
Peter BENSCH
ST Employee

This is the old problem of overwriting the currently running programme code. It is exacerbated by the lack of caching of the new binary. Just imagine a sudden interruption of the update process, which bricks your system until a debugger is connected and everything being rewritten.

For this reason, procedures have been developed that are used, for example, in FOTA (Firmware Over The Air): a second memory block (memory bank) in e.g. STM32 MCUs or as external memory. One of at least two blocks is then the golden image, a second block receives the update. Only when everything has demonstrably arrived correctly in the second block (checksums, etc.) are the blocks swapped and the second block becomes a new golden image and is started immediately.

I don’t know of a similar code for an STM8 without external memory.

Regards
/Peter

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
papadeltasierra
Associate III

Peter, thanks for the heads-up; I've been a programmer for 30 years working on telecoms systems with 5/6-9s reliability so I am very familiar with such issues :-).

For the stm8, I am just looking at implementing an "it works 99% of the time" feature for very rare upgrade purposes without the need for an ST-Link.  There is a specific board, an HC-12, that uses an stm8s chip and has such an update option and I'm developing some custom firmware for it and wanted to emulate the same update feature.

Clearly there is the "it can fail and brick the device" danger but the HC-12 provides this feature so it is possible for this to work well enough to be worth doing.  I was hoping there was some guidance on how this might be achieved otherwise I'm going to be spending a lot of time resetting the "discovery" dev board I have coming to help me develop this firmware.

Realised that my original question was perhaps not clear enough.  I am not looking for a strategy for the update, rather an answer to the question "if I write some code that will do the update, how do I ensure it is running from RAM?"

I think there is a "RAM()" macro but if use this against my update method, will the method AND any library calls I use all be in RAM or do I have to explicitly mark every single call used?

mschn.17
Associate II

To run from ram you must guarantee that the function you wish to call and any functions it calls is also located in ram.

You will need to consult your compiler manual to figure out how this is done.

Cosmic and IAR have constructs for it. SDCC will require you to manually copy or initialize the code to ram.

In addition you must ensure that any resources the ram function uses. fi. eeprom data or crc lookup tables are availible when they are needed. i.e. not erased. not being overwritten.

The function code itself must use relative addressing, or be compiled specifically to function at the ram location it is loaded.

 

The A/B image approach described by Bensch will also work for stm8. Simply divide the available flash in 2 sections.  Since the reset handler is fixed at 0x8000 this will be the start of the application image.

interrupts should be disabled during the actual copy operation so that interrupts do not execute some half copied code.

Bellow is a naive but working implementation:

#define APP_BASE 0x8000
#define IMG_BASE 0xc000
#define APP_ADDR ((u8 *)APP_BASE)
#define IMG_ADDR ((u8 *)IMG_BASE)
#define APP_SIZE 0x4000
#define IMG_SIZE 0x4000

static void docopy(void) {
    // copy image area to application area
    for (u16 i = 0; i < APP_SIZE; i++) {
        APP_ADDR[i] = IMG_ADDR[i];
    }
    // trigger a real reset to launch the new application
    WWDG->CR = WWDG_CR_WDGA;
    // backup... trigger a soft reset
    // WWDG might be masked by SWIM
    __asm__("jpf    0x8000\n");
}

// activate the current fw image.
// This routine performs no checks of image validity.
// Execution is returned to the reset vector by way of reset or jump
static void activate(void) {
    __disable_interrupts();

    // unlock flash
    FLASH->PUKR = 0x56;
    FLASH->PUKR = 0xAE;

    // copy the copy function onto the stack
    u8 ramfunc[64]; // make sure this is large enough by inspecting the assembly listing
    for (u8 i = 0; i < sizeof(ramfunc); i++) {
        ramfunc[i] = ((u8 *)(&docopy))[i];
    }

    // execute
    ((void (*)(void))ramfunc)();
}

 

Executing from ram is not a strict requirement.

stm8 supports byte level read and write access to flash without switching to ram. The core will halt during program. It will be slow. But it will work.

If you are executing from flash and writing to flash simply make sure you do not modify the instructions you are about to execute.

 

If power-cycles are to be tolerated during fw upgrade; offset the two image areas by a boot-loader. The boot-loader should verify the application image and repeat the copy operation of the upgrade image if the application image is found to be corrupt.

To make the entire thing absolutely bulletproof you must lock the boot-loader. Since the IVT is fixed and located in the locked area; you must forward any interrupts the application uses.