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: storing variables

Part Number: MSPM0G3507
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hi,

I would like to ask how best to save data to flash memory. 
I need to use, for example, the serial number, version and other variables, etc. to specific memory adress.
But I want certain values ​​to be read only and others also R/W.
These changes could not subsequently be overwritten by code, for example.
Could someone advise?

Thank you.
Jan



  • Others have more experience with this, but here is what I did.

    First change your linker file to set aside some memory. The lower part of flash has more read/write endurance:

    (This is my mspm0G3507.cmd file. USERCONFIG is the memory I am setting aside for my variables.)

    Modified for persistant flash storage: Keith Barkley Feb 2024
    *****************************************************************************/
    -uinterruptVectors
    --stack_size=512
    
    MEMORY
    {
        IntVectors      (RW)  : origin = 0x00000000, length = 0x00000400
        USERCONFIG      (RW)  : origin = 0x00000400, length = 0x00000400
        FLASH           (RX)  : origin = 0x00000800, length = 0x0001F800
        SRAM            (RWX) : origin = 0x20200000, length = 0x00008000
        BCR_CONFIG      (R)   : origin = 0x41C00000, length = 0x00000080
        BSL_CONFIG      (R)   : origin = 0x41C00100, length = 0x00000080
    
    }
    
    SECTIONS
    {
        .intvecs:   > 0x00000000
        .text   : palign(8) {} > FLASH
        .const  : palign(8) {} > FLASH
        .cinit  : palign(8) {} > FLASH
        .pinit  : palign(8) {} > FLASH
        .rodata : palign(8) {} > FLASH
        .ARM.exidx    : palign(8) {} > FLASH
        .init_array   : palign(8) {} > FLASH
        .binit        : palign(8) {} > FLASH
        .TI.ramfunc   : load = FLASH, palign(8), run=SRAM, table(BINIT)
    
        .vtable :   > SRAM
        .args   :   > SRAM
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
        .stack  :   > SRAM (HIGH)
    
        .BCRConfig  : {} > BCR_CONFIG
        .BSLConfig  : {} > BSL_CONFIG
    }

    Next define your memory addresses:

    // Mark Flash Addresses
    #define MAIN_BASE_ADDRESS (0x00000400)
    #define MAGIC_ADDRESS (MAIN_BASE_ADDRESS)
    #define MARK0_ADDRESS (MAIN_BASE_ADDRESS + 8)
    #define MARK1_ADDRESS (MAIN_BASE_ADDRESS + 16)
    #define MARK2_ADDRESS (MAIN_BASE_ADDRESS + 24)
    
    #define MAGIC_VALUE (0xDEADBEEF)
    
    int32_t Mark[3] = {MARK0_ADDRESS, MARK1_ADDRESS, MARK2_ADDRESS};

    In the main init code, set initial values if we have been reprogrammed - which erases any saved values:

    // If necessary, init the mark flash values
      // Note if there are problems writing to flash, we may trigger an ECC error
      // and NMI.
      tmp = *(uint32_t *)MAGIC_ADDRESS;
    
      if (tmp != MAGIC_VALUE) {
        // initial setup of flash, set the marks to zero.
        // First erase our sector
        /* 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 */
        cmdstatus = DL_FlashCTL_eraseMemoryFromRAM(FLASHCTL, MAIN_BASE_ADDRESS,
                                                   DL_FLASHCTL_COMMAND_SIZE_SECTOR);
    
        // Write Magic
        tmp = MAGIC_VALUE;
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
            FLASHCTL, MAGIC_ADDRESS, &tmp);
    
        // Write Mark0
        tmp = 0;
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
            FLASHCTL, MARK0_ADDRESS, &tmp);
    
        // Write Mark1
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
            FLASHCTL, MARK1_ADDRESS, &tmp);
    
        // Write Mark2
        DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                    DL_FLASHCTL_REGION_SELECT_MAIN);
        cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
            FLASHCTL, MARK2_ADDRESS, &tmp);
      }

    Finally, if you need to, write new info to flash. Note that I always write *everything* to flash, but you may not need to

    void WriteMarkToFlash() {
      bool done;
      DL_FLASHCTL_COMMAND_STATUS cmdstatus;
      int32_t position = GetPosition();
    
      // since we have to erase the flash to write it, stash all the flash
      // note if the flash has gone bad, we may get an NMI...
      uint32_t magic = *(uint32_t *)MAGIC_ADDRESS;
      int32_t mark0 = (CurrentMark == 0) ? (position) : (*(int32_t *)MARK0_ADDRESS);
      int32_t mark1 = (CurrentMark == 1) ? (position) : (*(int32_t *)MARK1_ADDRESS);
      int32_t mark2 = (CurrentMark == 2) ? (position) : (*(int32_t *)MARK2_ADDRESS);
    
      /* 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 */
      cmdstatus = DL_FlashCTL_eraseMemoryFromRAM(FLASHCTL, MAIN_BASE_ADDRESS,
                                                 DL_FLASHCTL_COMMAND_SIZE_SECTOR);
    
      // Write Magic
      DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                  DL_FLASHCTL_REGION_SELECT_MAIN);
      cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
          FLASHCTL, MAGIC_ADDRESS, &magic);
    
      // Write Mark0
    
      DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                  DL_FLASHCTL_REGION_SELECT_MAIN);
      cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
          FLASHCTL, MARK0_ADDRESS, (uint32_t *)&mark0);
    
      // Write Mark1
      DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                  DL_FLASHCTL_REGION_SELECT_MAIN);
      cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
          FLASHCTL, MARK1_ADDRESS, (uint32_t *)&mark1);
    
      // Write Mark2
      DL_FlashCTL_unprotectSector(FLASHCTL, MAIN_BASE_ADDRESS,
                                  DL_FLASHCTL_REGION_SELECT_MAIN);
      cmdstatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
          FLASHCTL, MARK2_ADDRESS, (uint32_t *)&mark2);
    }

    Accessing the flash is easy:

    void GoToMark(int mark) { GoPosition(*(int32_t *)Mark[mark]); }

    I think you have to do something to the preferences to use your .cmd file, but I can't find it at the moment.

  • Hi Jan, Hi Keith,

    This process pretty much covers it.

    To make sure that you are using your custom .cmd file instead of the one that sysconfig auto generates for you, you can go to the sysconfig file, go to the project configuration tab, then disable linker file generation. Then you'll need to manually add your linker to the top level project directory. What is easiest is to generate your linker, then disable generation and copy the generated one to the top level directory before building again. Then save your changes and rebuild.

    If you want to go a step further you could static write protect the region of memory that contains the version number and other information, but based on your description it sounds like you just want to ensure that you dont accidentally flash over your this memory, so the above process should be fine.

  • Thank you very much for your reply. Keith, could you still send what the GoPosition() and GetPosition() functions look like? Thank you

  • I can, but it is really specific to my stepper motor driven application, the point was to simply show you how to access the flash:

    int32_t GetPosition() {
      int32_t tmp;
      /// Safe way to get position even while running
    
      NVIC_DisableIRQ(TIMER_0_INST_INT_IRQN);
      tmp = StepCount;
      NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
    
      return tmp;
    }
    void GoPosition(int pos) {
      int32_t distance;
    
      Stop();
    
      // Find out how far
      distance = pos - StepCount;
    
      DoAccel = true;
      CurrentSpeed = SLOWSPEED;
    
      if (distance > 0) {
        StepDir = FWD_DIR;
        DL_GPIO_clearPins(GPIO_STEPPER_PORT, GPIO_STEPPER_PIN_DIR_PIN);
        CurrentStep = 0;
        NumSteps = distance;
    
      } else if (distance < 0) {
        StepDir = REV_DIR;
        DL_GPIO_setPins(GPIO_STEPPER_PORT, GPIO_STEPPER_PIN_DIR_PIN);
        CurrentStep = 0;
        NumSteps = -distance;
      }
    
      DisplayPos();
    }

    int32_t GetPosition() {
      int32_t tmp;
      /// Safe way to get position even while running
    
      NVIC_DisableIRQ(TIMER_0_INST_INT_IRQN);
      tmp = StepCount;
      NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
    
      return tmp;
    }