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.

MSPM0G3507: Persistent storage

Part Number: MSPM0G3507

I don't see an example, how do I set aside storage for settings I want to persist between power cycles?

  • Hey Keith,

    There is not an easy way to do this (unlike FRAM). You would most likely need to do this as a pointer in memory, then when you are ready to "save" the state of that variable, write to Flash at the pointer address. (Flash write example.) If you really need to do this often, you should consider using the EEPROM example and the lower 32kB of memory for increased write cycles. 

    Now there is a TI CLANG #persistent declaration that may help you as well as the variable is not re-initialized at reset with this attribute. You would still need to handle the copying to non-volatile memory separately. 

  • Thanks for this. The example stores things at

    MAIN_BASE_ADDRESS (0x00001000)

    How do I know this is "safe"?

  • Hey Keith,

    The flash write example doesn't guarantee that area is safe from a code aspect. The address was chosen as the compiled code should never reach that area of flash. So safe by knowing the nature of the program. If you want a more deterministic approach, I would suggest customizing the linker file to allocate an area of flash for your writing.

    So carve out a special section in the Memory portion of the linker file, and make sure the compiler doesn't place anything in it, by leaving it out of the Sections portion of the linker. 

  • I am new to this, and I tried to do it, but got Linker errors - which is a good thing. Is there a tutorial on how to do this?

    Also, is there a way in Theia to see how much flash is used?

    More details:

    I tried to carve out an 8 kB section, which is way more than I need (96 bytes) so I changed this:

    MEMORY
    {
        FLASH           (RX)  : origin = 0x00000000, length = 0x00020000
        SRAM            (RWX) : origin = 0x20200000, length = 0x00008000
        BCR_CONFIG      (R)   : origin = 0x41C00000, length = 0x00000080
        BSL_CONFIG      (R)   : origin = 0x41C00100, length = 0x00000080

    }

    to this:

    MEMORY
    {
        FLASH           (RX)  : origin = 0x00002000, length = 0x0001E000
        SRAM            (RWX) : origin = 0x20200000, length = 0x00008000
        BCR_CONFIG      (R)   : origin = 0x41C00000, length = 0x00000080
        BSL_CONFIG      (R)   : origin = 0x41C00100, length = 0x00000080

    }

    And the linker choked. Just what do I change?

  • Added:

    I even checked out the EEPROM example, which presumably does carve out a section of Flash, but saw no difference. in the linkder command file.

  • Keith,

    For the Linker adjustment, you would need to add your section as well to the memory. Keep in mind though that you may also need to fwd the interrupt table as those get loaded the beginning of memory.

    So something like this: (note I'm not accounting for ISr tables here.)

    MEMORY
    
    {
        App_Write       (RW)  : origin = 0x00000000, length = 0x00002000
        
        FLASH           (RX)  : origin = 0x00002000, length = 0x0001E000
    
        SRAM            (RWX) : origin = 0x20200000, length = 0x00008000
    
        BCR_CONFIG      (R)   : origin = 0x41C00000, length = 0x00000080
    
        BSL_CONFIG      (R)   : origin = 0x41C00100, length = 0x00000080
    
    
    
    }

    For the EEPROM example, I'll defer to  as he is more familiar with it. You would need to reference the user guides for Type A or B, to see how they are setting up the structure. 

    MSPM0 EEPROM Type A

    MSPM0 EEPROM Type B

  • OK, more weirdness, when I take the flashctl multiple size write example and add a 32 bit write in the loop, it goes off to never never land with

    DL_FlashCTL_programMemoryFromRAM32WithECCGenerated()

    returning a code of *3* which is not one of the enums.

    #include "ti_msp_dl_config.h"
    #include <stdio.h>
    #include <string.h>
    
    
    /* Address in main memory to write to */
    #define MAIN_BASE_ADDRESS (0x00001000)
    
    /* 8-bit data to write to flash */
    uint8_t gData8 = 0x11;
    
    /* 16-bit data to write to flash */
    uint16_t gData16 = 0x2222;
    
    /* 32-bit data to write to flash */
    uint32_t gData32 = 0x33333333;
    
    /* Array to write 64-bits to flash */
    uint32_t gDataArray64[] = {0xABCDEF00, 0x12345678};
    
    volatile DL_FLASHCTL_COMMAND_STATUS gCmdStatus;
    
    /* Codes to understand where error occured */
    #define NO_ERROR 0
    #define ERROR_ERASE 1
    #define ERROR_8BIT_W 2
    #define ERROR_16BIT_W 3
    #define ERROR_32BIT_W 4
    #define ERROR_64BIT_W 5
    
    volatile uint8_t gErrorType = NO_ERROR;
    
    // place to store the variables
    uint8_t Recall8;
    uint16_t Recall16;
    uint32_t Recall32;
    
    int main(void) {
    
      SYSCFG_DL_init();
    
      // Check the Memory
      Recall8 = *(uint8_t *)(MAIN_BASE_ADDRESS);
      Recall16 = *(uint16_t *)(MAIN_BASE_ADDRESS + 8);
      Recall32 = *(uint32_t *)(MAIN_BASE_ADDRESS + 16);
    
      /* Unprotect sector in main memory with ECC generated by hardware */
      DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                  DL_FLASHCTL_REGION_SELECT_MAIN);
      /* Erase sector in main memory */
      gCmdStatus = DL_FlashCTL_eraseMemoryFromRAM(FLASHCTL, MAIN_BASE_ADDRESS,
                                                  DL_FLASHCTL_COMMAND_SIZE_SECTOR);
      if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
        /* If command was not successful, set error flag */
        gErrorType = ERROR_ERASE;
      }
    
      if (gErrorType == NO_ERROR) {
        /* 8-bit write to flash in main memory */
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        gCmdStatus = DL_FlashCTL_programMemoryFromRAM8WithECCGenerated(
            FLASHCTL, MAIN_BASE_ADDRESS, &gData8);
        if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
          /* If command was not successful, set error flag */
          gErrorType = ERROR_8BIT_W;
        }
      }
    
      if (gErrorType == NO_ERROR) {
        /*
         * 16-bit write to flash in main memory with ECC generated by hardware.
         * The target program address must be a flash word address
         * (8-byte aligned), so we increase the address in increments of 8.
         */
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        gCmdStatus = DL_FlashCTL_programMemoryFromRAM16WithECCGenerated(
            FLASHCTL, (MAIN_BASE_ADDRESS + 8), &gData16);
        if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
          /* If command was not successful, set error flag */
          gErrorType = ERROR_16BIT_W;
        }
      }
    
      if (gErrorType == NO_ERROR) {
        /* 32-bit write to flash in main memory with ECC generated by hardware */
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        gCmdStatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
            FLASHCTL, (MAIN_BASE_ADDRESS + 16), &gData32);
        if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
          /* If command was not successful, set error flag */
          gErrorType = ERROR_32BIT_W;
        }
      }
    
      if (gErrorType == NO_ERROR) {
        /*
         * 64-bit write to flash in main memory with ECC generated by hardware.
         * Data must be loaded 32-bits at a time, but a single word program
         * is executed
         */
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        gCmdStatus = DL_FlashCTL_programMemoryFromRAM64WithECCGenerated(
            FLASHCTL, (MAIN_BASE_ADDRESS + 24), &gDataArray64[0]);
        if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
          /* If command was not successful, set error flag */
          gErrorType = ERROR_64BIT_W;
        }
      }
    
      /* After successful completion, toggle LED and USER_TEST pin */
      if (gErrorType == NO_ERROR) {
        /*
         * Check the contents of MAIN_BASE_ADDRESS at breakpoint:
         * FF FF FF 11
         * FF FF FF FF
         * FF FF 22 22
         * FF FF FF FF
         * 33 33 33 33
         * FF FF FF FF
         * AB CD EF 00
         * 12 34 56 78
         */
        while (1) {
          DL_GPIO_togglePins(GPIO_LEDS_PORT,
                             GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
    
          // Check the Memory
          Recall8 = *(uint8_t *)(MAIN_BASE_ADDRESS);
          Recall16 = *(uint16_t *)(MAIN_BASE_ADDRESS + 8);
          Recall32 = *(uint32_t *)(MAIN_BASE_ADDRESS + 16);
          delay_cycles(16000000);
    
          gData32 = 31;
    
    
          /* 32-bit write to flash in main memory with ECC generated by hardware */
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        gCmdStatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
            FLASHCTL, (MAIN_BASE_ADDRESS + 16), &gData32);
        if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
          /* If command was not successful, set error flag */
          gErrorType = ERROR_32BIT_W;
        }
        }
      }
      /* Unsuccessful example run */
      else {
        /* Check gErrorType value */
        __BKPT(0);
      }
    }