This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Flashing MSP430 internally and executing the flashed code

Expert 1140 points
Other Parts Discussed in Thread: MSP430F5529

Hi,

I need to make my device based on MSP430F5529 (8kB of RAM, 128kB of flash) to be remotely upgradable but it needs to be safe and in case a faulty image is flashed the microcontroller reflashes agin. No external hardware shall be involved as I have only one GSM modem that is connected to the MSP that is going to be upgraded.

My idea is to have the "boot" application stored in the standard place in the flash (1st to be executed upon start) to check for the flash image on the webserver via GPRS and flash it onto the designated flash area of the MSP. Then upon completion it shall execute this newly flashed code. In case the newly flashed code is faulty, the watchdog resets the MSP and the firmware check and flash repeats so that I can upload the fixed firmare and let the device to self-fix.

I have a couple of questions:

  1. as far as I know the flash controller lets to execute the code from flash and at the same time erase/program the other flash area. This must be a separate 64kB bank if I understand correctly
  2. when the flashing of the new image is completed how can I execute some entry point of this new code (let's say a submain() function)
  3. what shall I do with the vector table? The booting code (the one that checks for the new image and programs it on the flash) shall have it's own ISR routines (for example for UART to handle GSM modem and maybe timers) while  the newly flashed code shall have it's own vector code (so that I can modify the main code and the ISRs) so how can I control that?
  4. what is the format of the flash image I should flash? The GSM modem can transmit only characters 0x00-0xFF so the flash image on the web server shall be in text format. How to convert from .elf to this byte format and shall I simply put these bytes one by one onto the flash?

I hope this isn't too much :)

Best Regards,

tml

  • TML,

    This is very do-able, in fact several of our products allow in-field upgrade of the application.

    We do this with a separate bootloader application that resides in upper memory (typically E800-FFFF).

    tml said:
    when the flashing of the new image is completed how can I execute some entry point of this new code (let's say a submain() function)

    Make your bootloader and your application two separate projects. Configure your linker file to place CSTART (for IAR. .cint_00 I think in CCS) at the beginning of FLASH. Then just execute a jump to the start of Flash.

    tml said:
    what shall I do with the vector table? The booting code (the one that checks for the new image and programs it on the flash) shall have it's own ISR routines (for example for UART to handle GSM modem and maybe timers) while  the newly flashed code shall have it's own vector code (so that I can modify the main code and the ISRs) so how can I control that?

    Use a RAMVECTOR table in RAM. Similar to installable drivers in the old PC/DOS days. The FLASH vector table is in the bootloader. Before enabling interrupts, fill the table in with RETI instructions (we use 6-bytes per vector). Develop a module that can be used by both bootloader and application that when you "install" the ISR during initialization in main() replaces the RETI with a BR 0xNNNN instruction to the real ISR address.

    tml said:
    what is the format of the flash image I should flash? The GSM modem can transmit only characters 0x00-0xFF so the flash image on the web server shall be in text format. How to convert from .elf to this byte format and shall I simply put these bytes one by one onto the flash?

    We use TI-TXT format. Both IAR and CCS can generate this output. File format is simple to parse.

    Make sure to add checks into your reprogramming routine to prevent overwriting the bootloader area in flash, especially since your app would contain a vector table at upper 64KB memory region.

  • tml said:

    ..  In case the newly flashed code is faulty, the watchdog resets the MSP and the firmware check and flash repeats so that I can upload the fixed firmware and let the device to self-fix....

    It is relatively easy to make sure that the downloading is carried out correctly. (That is, to verify that what are in the Flash Memory are indeed what you intended.) But once you start to run that downloaded code, it all depends on how skillful and how diligent you prepared that code. You can use the watchdog, but do not depend on it. You can pray to God, but do not depend on that either.

  • Brian,

    Thank you for your response! Would you be able to share some code allowing for a better understanding of the process?

    Brian Boorman said:
    This is very do-able, in fact several of our products allow in-field upgrade of the application.

    We do this with a separate bootloader application that resides in upper memory (typically E800-FFFF).

    I assumed the bootloader must be something that is fixed when flashed (i.e not upgradable) and with 100% guarantee to be executed by the microcontroller. This bootloader has to have the ablility to peform the flash image download and programming it onto flash. If I understand it correctly the initial address of the program that is executed is at 0xFFFE which is the highest priority interrupt vector that is sourced by power-up. Is that correct?

    In your case the given address range of E800-FFFF intersects with FFFE. This is not the coincidence, right? :)

    Brian Boorman said:
    Make your bootloader and your application two separate projects. Configure your linker file to place CSTART (for IAR. .cint_00 I think in CCS) at the beginning of FLASH. Then just execute a jump to the start of Flash.

    Could you please explain? Where is the bootloader and where is the application code? Does the microcontroller first executes the bootloader and does it jump to the bootloader's custom  address and then jumps again to the application code? Got confused.

    Brian Boorman said:
    Use a RAMVECTOR table in RAM. Similar to installable drivers in the old PC/DOS days. The FLASH vector table is in the bootloader. Before enabling interrupts, fill the table in with RETI instructions (we use 6-bytes per vector). Develop a module that can be used by both bootloader and application that when you "install" the ISR during initialization in main() replaces the RETI with a BR 0xNNNN instruction to the real ISR address.

    It's SYSRIVECT bit of SYSCTL register I guess. Not quite sure how that works: the interrupt vector contains a 16 bit address of the ISR code. At what stage of code preparation (compilation, linking or whatever) these addresses are assigned to vectors? Could you please explain why do we need this vectors filling with RETI and how to obtain a real ISR address to be able to replace vectors with these values?

    Best Regards,

    tml

  • tml said:
    Would you be able to share some code allowing for a better understanding of the process?

    Unfortunately I can't share actual source code, due to it's use in ITAR regulated products.

    tml said:
    Could you please explain? Where is the bootloader and where is the application code? Does the microcontroller first executes the bootloader and does it jump to the bootloader's custom  address and then jumps again to the application code? Got confused.

    In my case, the bootloader occupies 0xE800-0xFFFF, and the application is at (START_OF_FLASH)-0xE7FF. Bootloader always executes first, determining if new image download is being requested.

    tml said:
    It's SYSRIVECT bit of SYSCTL register I guess.

    We don't do it that way.

    tml said:
    At what stage of code preparation (compilation, linking or whatever) these addresses are assigned to vectors?

    During execution. Develop your ISRs with __interrupt (for IAR tools anyway) but don't assign them to a vector with #pragma. During initialization in main, each driver that uses ISRs calls your module that handles registering interrupts. That module replaces the RETI with the branch instruction. You have to pass the address of the ISR and the desired interrupt you are registering to that function. Something like this:

    void InitUsci(void)
    {
      SetInterruptVector(IV_USCI0RX, Usci0RxIrqHandler);
      SetInterruptVector(IV_USCI0TX, Usci0TxIrqHandler);
      SetInterruptVector(IV_USCI1RX, Usci1RxIrqHandler);
      SetInterruptVector(IV_USCI1TX, Usci1TxIrqHandler);
    }
    

    tml said:
    Could you please explain why do we need this vectors filling with RETI

    So when interrupts are enabled, an interrupt that occurs before handler has been registered, would just return and not end up at some garbage random address.

    tml said:
    and how to obtain a real ISR address to be able to replace vectors with these values?

    See example above.

  • Brian, the approach of registering handlers is nice if you dynamically load code from a mass storage. Or have an OS on top of the application, that requires some interrupts handled by the OS and then proceed to the user ISR.

    Or if you have more than one ISR for a module, and need to switch it dynamically (rather than switching code inside the ISR depending on current situation).

    In case of a simple application, it is easier and likely faster (but not necessarily smaller) to use a double-jump table:

    The linker script is changed so that the interrupt vector table is built at a different (fixed and known) location. Right beneath the bootloader. The real vector table points to a series of jump instructions insie the bootloader which do indirect jumps to the moved interrupt table. No vector management code needed in the application, no registering, and only a few clock cycles overhead at the interrupt event.

    Alternatively, copying the application table to ram in the bootloader and switching to ram is a good option too - if the code doesn't cause stack underflow. It also allows the bootloader to use interrupts too at will. As long as th ROM table is used, the vectors point to the bootloader ISRs,

    Remains the question whether this helps at all against code corruption. It could as well be the bootloader that is corrupted. Or the stored copy. The safety gain is not very large.

    So the main reason for this type of bootloader is to do field updates where the new firmware is received and stored by the currently running application in a backup area before it is copied and activated. Or if you have multiple firmwares for different jobs on an external storage and select them e.g. by config switches.

  • Jens-Michael Gross said:
    Brian, the approach of registering handlers is nice if you dynamically load code from a mass storage. Or have an OS on top of the application, that requires some interrupts handled by the OS and then proceed to the user ISR.

    Or you have a single vector table in flash that you want to point to ISRs in the bootloader, and later to ISRs in application code. You just reinitialize the RAM table as part of application startup.

    Jens-Michael Gross said:
    The real vector table points to a series of jump instructions insie the bootloader which do indirect jumps to the moved interrupt table.

    But if the bootloader requires interrupts (say for UART for downloading and programming new application file) then that other vector table gets erased in the middle of using the UART, not to mention that it points to ISRs in the application, not the bootloader. So now, you force your bootloader to only use peripherals in polled mode. Maybe you want that tradeoff, maybe you don't. I suppose it is end-application specific decision.

    Jens-Michael Gross said:
    where the new firmware is received and stored by the currently running application in a backup area before it is copied and activated.

    That's not how we do it. Key held pressed at poweron initiates an XModem reception in the bootloader where it emits NAK characters waiting for something on the other end to send the new application file to be programmed. This eliminates having to worry about having enough room in flash somewhere to store essentially a second copy of your application (what if your application already uses more than half the flash? Mine does due to stored font and graphics tables for the LCD screen).

  • Brian Boorman said:
    But if the bootloader requires interrupts (say for UART for downloading and programming new application file) then that other vector table gets erased in the middle of using the UART, not to mention that it points to ISRs in the application, not the bootloader. So now, you force your bootloader to only use peripherals in polled mode.

    That was the basic setup. You can as well point the ROM vector to your bootloader ISR, if required, and the very first instruction is to check whether you're running in bootloader mode and if not, perform the jump. 4 MCLK cycles. Consistent operation. No problems.

    Brian Boorman said:
    . I suppose it is end-application specific decision

    It almost always is :)

    Brian Boorman said:
    (what if your application already uses more than half the flash?

    Well, what if it requires more than the available flash? Pick a bigger MSP then. :)

    In our case, the update happens without even coming near the device (to reset it and touch a button at power-up). It just receives the new firmware during normal operation through wireless link. While it continues to work normally until the new firmware was received and verified. The HF stack is quite large and complex. And needs to be that complex, as the largest sensor network we have has 63 RF transmitters running continuously and collision-free on same frequency and in a close area. So no burst upload possible and shutting down sensor operation until a slow update is done is no option too.

    If you can touch the device for the update, you can as well use the standard BSL. :)

**Attention** This is a public forum