Self updating firmware on an Xmega

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Having a bootloader, and that upgrading the firmware is one solution. But then the bootloader can never change.

Instead I have the following idea:

 

What if I split the flash in half, and while running from the first half, it writes the second half. And when all is well, i switch to second half.

 

Something like this:

00000 interrupt vectors
00200 application code 1
10000 unused area
10200 application code 2
20000 bootloader area, functions having SPM instructions

 

So when updating from area 1 to area 2, first i fill from 10200 to 20000

Then change interrupt vectors as atomic as possible, to point to area 2 (this is where it can go wrong)

After reboot area 2 will be active.

 

(about changing interrupt vectors, i think the best way is to store the interrupt vector table in SRAM.

And then write those pages to flash in one loop, aligning application start to 200 helps, because that way i can update only the vectors, and not the code.)

 

What do you think, can it work?

As far as I understand only interrupt vectors and SPM instructions are not movable. Is this correct?

 

 

 

This topic has a solution.
Last Edited: Sun. Aug 11, 2019 - 06:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Someone submitted a Pull Request for Optiboot to allow this sort of thing to happen.

The general strategy is to have the application download the new image "however", storing it in flash one page at a time as already allowed by the Optiboot v8 feature.

Then, use the newly provided feature vector to tell the bootloader to copy the whole region from the new image to the default location, and restart.

 

I haven't decided whether it will make it into optiboot (it's sort-of big, and I don't want too much feature-creep in that "function vector dispatch table"), but it might serve as an interesting model...

 

https://github.com/Optiboot/optiboot/pull/269

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


There are various downsides to the approach. One is that you effectively half the application space available. Another you already mentioned is the fact that you actually have a three way split - there's the two apps but then their is a common core of vector redirectors which, as you say, likely use function pointers in SRAM to allow one or other app to redirect the vectors. Not only (MISRA would tell you!) is it a dangerous strategy to using non-const function pointers but there's the overhead in redirecting.

 

The strategy is not unknown however. These things for example:

 

contain two app copies. One upside is that it makes it easy to "roll back" if newly delivered code is found later to have some serious flaw. You also have the protection that you should never face a "failed update" scenario - there's always at least one complete, validated and runnable image in the box (even if the other half contains a part delivered image that was interrupted during delivery (satellite signals can be a bit like that!).

 

PS I'm not entirely sure I follow your argument for doing this:

jsaak wrote:
But then the bootloader can never change.

How does the "two app" thing actually make it any easy to replace the bootloader? Remember that for a bootloader to be replaceable you need room for 2 bootloaders in the bootloader area of the chip. The fact that you split the app section doesn't help.

 

In 15 odd years of reading Freaks I have only ever encountered two successful attempts to do the bootloader update thing - it is very tricky as you need room for two small bootloaders probably in one large bootloader section (situation may be a bit different for Xmega as I know they have a fixed size BLS that is separate from the main application flash space).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jsaak wrote:
What if I split the flash in half, and while running from the first half, it writes the second half.
A possible issue with XMEGA.

Bootloader. Revision 2.0

...

Revision history:

...

 

1.6 - ...

...

Workaround is introduced for the following problem with xMega:
"Writing EEPROM or Flash while reading any of them will not work".

 

...

via AN_8390 AVR2054: SerialBootloader User Guide

 

Attachment(s): 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
The strategy is not unknown however.

PIC32MZ2064DAS176 - 32-bit Microcontrollers

...

Dual Panel Flash for live update support

...

edit :

dsPIC33CK | Microchip Technology

...

  • Live update of firmware for high-availability systems

...

via New Digital Signal Controller (DSC) Accelerates DSP Performance for Time-Critical Control Applications | Microchip Technology

 

"Dare to be naïve." - Buckminster Fuller

Last Edited: Wed. Jul 31, 2019 - 12:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you all!

 

@westfw It is really close to what I had in mind. Updating the interrupt vector table while running may not be the best idea ever.

 

@clawson I wanted to change the interrupt vectors, not redirecting them.

Replacing the code in the bootloader section is indeed tricky - if at all possible - without a programmer.

But i did not plan to do that. My plan was to only have functions that write to flash live there.

(As far as i understand the SPM instruction limitation is based on where the PC is, not where the app started to run)

And never running a "bootloader application" at all. Only call function which are in the bootloader area.

 

@gchapman Thank you for the warning. For reference here is the app note that describes the problem: https://www.microchip.com/wwwApp... . I am not sure my boards are affected or not.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Thank you for your input!

 

I went with writing the new firmware to second half of the flash, and then rebooting to bootloader, which copies the new firmware to 0x0.

 

The bootloader turned out to be really simple, i hope we will not find any bugs in it:

 

static inline void jump_to_application(void) {
  EIND = 0x00;  //disable extended adressing
  void(* startAddress)(void) =(void(*)(void))0;
  startAddress();
}

int main() {
  if (eeprom_read_byte(EEADDR_BOOTFLAG) != '\xaa') {
    jump_to_application();
  }

  uint8_t pagecount = eeprom_read_byte(EEADDR_PAGECOUNT);

  int p;
  int i;
  for (p = 0; p < pagecount; p++) {
    for (i = 0; i < 512; i+=2) { //PAGE_SIZE
      uint32_t address = (p*512)+i;
      SP_LoadFlashWord(address, SP_ReadWord(address+0x10000));
    }

    SP_EraseWriteApplicationPage(p*512);
    SP_WaitForSPM();
  }

  eeprom_write_byte(EEADDR_BOOTFLAG,0);
  eeprom_busy_wait();
  jump_to_application();
}

 

The trick was, that i linked the SP functions to both the bootloader, and the application:

 

LDFLAGS += -Wl,--section-start=.selfprogram=0x020e00

 

Last Edited: Sun. Aug 11, 2019 - 06:34 AM