The TI E2E™ design support forums will undergo maintenance from Sept. 28 to Oct. 2. If you need design support during this time, contact your TI representative or open a new support request with our customer support center.

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.

MSP430FR58471: Self update mechanism using I2C running out of RAM

Part Number: MSP430FR58471


I couldn't find another thread on the forum regarding this topic so I figured I'd make one. I'm currently working on developing a self update mechanism using I2C running out of RAM. I need to run this code from RAM in order to receive and flash a complete TI-TXT firmware image on a running target. For reference I'm using the MSP430-GCC compiler.

So far I have been able to get this code onto the device, load itself into RAM, and begin executing from RAM. My problems arise however when I attempt to send I2C to the device. For some reason my I2C isr is not being called correctly. I've gone through numerous sections of the user guide and one thing I found interesting was using the RAM based interrupt vectors via SYSRIVECT.  Maybe that is required to run ISR's out of RAM? Any help in finding out why my isr isn't being called properly would be great, overall suggestions are welcome too.

I've included my code that I jump to. Before this executes I program this "updater" code to a section of main flash then set my SP and PC to jump.

#include <msp430fr58471.h>

#define str(s) #s
#define ENQUOTE(s) str(s)
#define DO_PRAGMA(x) _Pragma (#x)
#define location(var_name,address) DO_PRAGMA(LOCATION(var_name, address))
#define attribute_section(x) __attribute((section(x)))

#define RAM_BASE              0x1c00
#define RAM_END               0x1ffe
  asm("mov #"ENQUOTE(RAM_END)", r1"); \
  asm("br #"ENQUOTE(RAM_BASE))
#define CODE_BASE             0x8000
#define MAIN_CODE_OFFSET      0x0400
#define BEGIN_ROM_EXECUTION() asm("br #0x8400")
#define I2C_INT_VECTOR        0xffee

#define SCL     (1 << 7)
#define SDA     (1 << 6)
#define MCU_IRQ (1 << 4)

#define XT1_LF_MODE (LFXTDRIVE_0 + 0x0100)

#endif //defined(__MSP430FR58471__)

register unsigned int i2c_byte asm ("R4");
register unsigned int i2c_temp asm ("R5");
register unsigned int address asm ("R10"); // Needs to match jmp main_entrance check in main

/* Standard #defines */
#define GSC_STAGE2_PUC      0x1
#define GSC_STAGE2_ADDR     0x2
#define GSC_STAGE2_ERASE    0x3
#define GSC_STAGE2_WORD     0x4
#define GSC_STAGE2_PROG     0x5

void attribute_section(".text") __attribute__((optimize("Os"))) main( void ) {

  /* Copying ourself from main ROM to RAM */
  asm("mov #2, r5");                   // Store number 2
  asm("mov #main_entrance, r7");       // Store main_entrance location
  asm("mov #the_end, r8");             // Store the_end location
  asm("mov #"ENQUOTE(RAM_BASE)", r9"); // Store RAM_BASE location
  asm("memcpy:");                      // memcpy label (copying loop begins here)
  asm("mov @r7, 0(r9)");               // Move content of flash to RAM
  asm("add r5, r7");                   // Increment flash pointer by 2
  asm("add r5, r9");                   // Increment RAM pointer by 2

  asm("cmp r7, r8");                   // Check if we have reached the_end location
  asm("jne memcpy");                   // If not, repeat loop

  /* Write out the I2C interrupt vector address to vector table (0xffee) */
  asm("mov #main_entrance, r7");             // Store main_entrance location
  asm("mov #i2c_isr, r8");                   // Store i2c_isr location
  asm("sub r7, r8");                         // subtract main_entrance addr from i2c_isr addr, r8 has offset
  asm("add #"ENQUOTE(RAM_BASE)", r8");       // Add value of RAM_BASE to get new location of i2c_isr
  asm("mov #"ENQUOTE(I2C_INT_VECTOR)", r9"); // Store location of i2c interrupt vector
  asm("mov r8, 0(r9)");                      // Write out the I2C isr address to vector table

  /* Jump to RAM and execute */

  while(1); // Loop here so the I2C ISR has somewhere harmless to return to

void attribute_section(".text") __attribute__((optimize("O0"))) i2c_isr(void) {
  switch(__even_in_range(UCB0IV,0x1e)) {
    case 0x06:        // Vector 6: STTIFG   (Start Condition)
    ... // The rest of the UCB0IFG cases here

void attribute_section(".text") the_end(){

  • Hi Robert,

    Thank you for posting the question.
    I am looking into this for you and will get back to you as soon as possible.

    Best Regards,
  • Thank you for the response Ling, please let me know if you would like further detail.
  • Hi Robert,

    Where did you set SYSRIVECT? Didn't saw that in your code.

    Another option is using I2C polling instead of using interrupt.

  • I actually did switch to a I2C polling method and have successfully completed an update.
    * A word of warning for anyone trying to do this, make sure your DCO/clock divider settings are giving you a fast enough clock otherwise you'll miss the timings.

    The only problem I am running into now is doing an erase of main memory for the purposes of calculating CRC. My intention is to erase the section of memory between 0x8000-0xF7FF. However regardless of my method, setting those memory addresses to 0x00 fails. It successfully gets through the first 0xa00 bytes or so before failing to respond to further I2C calls presumably because of a reset. I have not enabled the MPU, those addresses do not lie in vacant memory, and I have set my FRAM wait states to 1 for a 12MHz clock so I'm not sure what could be causing this.

  • I was able to successfully "erase" flash by writing 0xff instead of 0x00, and just changing my crc function to account for that.
    I know that the non FRAM mcu's use 0xff to erase which led me to attempt it, but I can't explain why that was necessary for a FRAM part.

**Attention** This is a public forum