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.

MSP430FR2433: how to write/read LONG value to FRAM

Part Number: MSP430FR2433

Hi Experts,

Currently i am working with MSP430FR2433 to make  a device like oximeter, i want to detect interrupt and increase the increment and store the value to FRAM, here i have completed to detect interrupt an enter to Low power mode but i can't write/read the data to FRAM, 

i am newbie for the FRAM low power microcontrollers

i have followed below example 

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/720929/ccs-msp430fr2433-how-to-write-to-and-read-from-fram

the above link i can't understand why they are run the below for loop

for (i = 0; i < 128; i++)
    {
        *FRAM_write_ptr++ = data;
    }

and why they are declared the long variable as a bits like
data += 0x00010001;

My request is very simple, i have increment the long variable when interrupt is triggered..
then i store that value to the FRAM to avoid the interrupt counter values then i read the FRAM to routine increment and store
this method will help me to start the interrupt counter from old value when my controller restarted due to power or other failure..

regards
surya
  • Hi Surya,

    This is the best example to look at for your application so I'll assist with some more information. I don't know which part of the loop you're confused on so I'll explain each line. First some background information, the MSP430 is a 16-bit device which means that a word is 2 bytes and a long word is 4 bytes. The example program is made to write 512 bytes of data, which is equal to 128 long words. The loop is the process that writes to the FRAM.

    for(i = 0; i < 128; i++) // loops through 128 longs, which is 512 bytes
    {
        */ 
        *   assign the value of data to the current location of
        *   FRAM_write_ptr then increment the pointer
        *   because the ptr is a long, the increment will move
        *   the pointer over by the length of a long.
        /*
        *FRAM_write_ptr++ = data; /
    }
    
    //Increment data by hex 0x10001, or decimal 65,537. Completely arbitary choice.
    //data is a long variable so it is 4 bytes.
    data += 0x00010001; 

    Regards,

    Luke

  • Hi 

    Thanks for the quick response and detailed explanation,

    ok now i have changed variable as int so Here i have explained my doubts,

     i have write int value like 

    #define FRAM_ADD_1 0x1800

    unsigned int *pointer;

    unsigned int *FRAM_write_ptr;

    FRAM_write_ptr = (unsigned int *)FRAM_ADD_1;

    unsigned int data=2147483647,data1=0;


    SYSCFG0 = FRWPPW | PFWP;
    *FRAM_write_ptr = data;
    SYSCFG0 = FRWPPW | PFWP | DFWP;

    to read i use this 

    pointer = (unsigned int *)FRAM_ADD_1; // address to read
    data1 = *pointer; // data to read

    here i am getting wrong value,  please guide me to write above long value to the FRAM and how to retrieve as a long value..

    if there is any guidance to split the long value to 4byte(high byte and low byte ) which is used for MODBUS communication to store that 4byte to FRAM and retrieve that 4byte and manipulate the variable to convert to long like below code..

    below code is just assumption not tested..

    unsigned int data=2147483647,

    int test[4];

    int* pointer;

    here i just split int value as a 4byte 

    test[0]=(data&0xFF000000) >> 24

    test[1]=(data&0x00FF0000) >> 16;

    test[2]=(data&0xFF00) >> 8;

    test[3]=(data&0xFF);

    store bytes in separate location 

    SYSCFG0 = FRWPPW | PFWP;


    *FRAM_write_ptr= test[0];

    *FRAM_write_ptr++= test[1];

    *FRAM_write_ptr++= test[2];

    *FRAM_write_ptr++= test[3];


    SYSCFG0 = FRWPPW | PFWP | DFWP;

    here i just read every byte  from stored adddress

    pointer= ( int *)FRAM_ADD_1; // address to read

    DATA1[0]=*pointer; // data to read

     pointer= ( int *)FRAM_ADD_1++; // address to read

    DATA1[1]=*pointer; // data to read

     pointer= ( int *)FRAM_ADD_1++; // address to read

    DATA1[2]=*pointer; // data to read

    pointer= ( int *)FRAM_ADD_1++; // address to read

    DATA1[3] =*pointer; // data to read

    here i manipulate the value as a decimal

    long data =(((unsigned long)DATA1[0]) << 24) | (((unsigned long)DATA1[1]) << 16) | (((unsigned long)DATA1[2]) << 8) | ((unsigned long)DATA1[3]);

    regards

    Surya

  • Hi Surya,

    I would suggest to use the debugger option and place a breakpoint at your first expected write. While you're debugging you can go to view -> memory browser. Here you can input your memory address where you are expecting data to be written too. If you do view -> expressions, you can look at the variables themselves and see the values that are in there and their memory address. 

    Pointers require a lot of attention to when something is being referenced or dereferenced, I'm expecting there is some mismatch here. So, the memory browser and expression views should help with the mismatch.

    Another note is the

    *FRAM_write_ptr= test[0];

    *FRAM_write_ptr++= test[1];

    *FRAM_write_ptr++= test[2];

    *FRAM_write_ptr++= test[3];

    Will assign the value THEN increment. The first 2 lines are writing to the same place. If you change the first line to *FRAM_write_ptr++= test[0]; it will work.

    Another thing, even though I think your byte shifts would work it would be better to do:

    test[0]=(data >> 24) & 0xFF;

    test[1]=(data >> 16) & 0xFF;

    test[2]=(data >> 8) & 0xFF;

    test[3]=data & 0xFF;

    Regards,

    Luke

  • If you want to read and write a long, then use a pointer to a long:

    unsigned long *FRAM_write_ptr;

    This:  pointer= ( int *)FRAM_ADD_1++; // address to read

    will not work. In fact the compiler should complain about needing an lvalue.

  • Hi  and 

    Thanks for the answers, now i can write my decimal to the FRAM..

  • Hi  and 

    i have one doubt in the MSP430fr2433 has 512byte information memory here my doubt is how can i write multiple values to that information memory like

    #define FRAM_ADD_1 0x1800

    unsigned long *pointer;

    unsigned long  *FRAM_write_ptr;

    FRAM_write_ptr = (unsigned int *)FRAM_ADD_1;

    long DATA1=1234567890,VALUE1=0;

    long DATA2=9876543210,VALUE2=0;

    long DATA3=6543278901,VALUE3=0

    i want to store/read the above three values to FRAM, what changes i need to do with the below code 

    SYSCFG0 = FRWPPW | PFWP;
    *FRAM_write_ptr = DATA1;
    SYSCFG0 = FRWPPW | PFWP | DFWP;

    to read i use this 

    pointer = (unsigned long *)FRAM_ADD_1; // address to read
    VALUE1 = *pointer; // data to read

    regards

    Surya

  • Hi Surya,

    I'll detail each line's purpose below

    SYSCFG0 = FRWPPW | PFWP; //Unlock the Data section, lock the rest of FRAM
    *FRAM_write_ptr++ = DATA1; //write data to the FRAM location specified by the pointer
    SYSCFG0 = FRWPPW | PFWP | DFWP; //Lock the FRAM to prevent unexpected writes

    So there are a couple ways you could do this, you could hard code and just add the other addresses and data so you have 

    SYSCFG0 = FRWPPW | PFWP;
    *FRAM_write_ptr++ = DATA1;
    *FRAM_write_ptr++ = DATA2;
    *FRAM_write_ptr = DATA3;
    SYSCFG0 = FRWPPW | PFWP | DFWP;

    But I personally believe it would be better to create a new function then pass your required values.

    void FRAMLongWrite (long* FRAM_write_ptr, long data)
    {
        SYSCFG0 = FRWPPW | PFWP;
        *FRAM_write_ptr++ = data;
        SYSCFG0 = FRWPPW | PFWP | DFWP;
    }

    Hope this helps!

    Regards,

    Luke

  • Hi

    Thanks for the quick reply, yes the below code must work to write the data 

    void FRAMLongWrite (long* FRAM_write_ptr, long data)
    {
    SYSCFG0 = FRWPPW | PFWP;
    *FRAM_write_ptr++ = data;
    SYSCFG0 = FRWPPW | PFWP | DFWP;
    }

    but how can i retrieve/read those data from the memory????

    As per advice, the blow code shows an error,

    unsigned long *FRAM_write_ptr;

    This:  pointer= ( int *)FRAM_ADD_1++; // address to read

    will not work. In fact, the compiler should complain about needing an lvalue.

    In this situation how can i read the data from FRAM,

    regards

    Surya

  •  Hi Surya,

    I went ahead and put this in my CCS and I didn't get any issues.

    #define FRAM_ADD_1 (0x1800)
    unsigned char count = 0;
    unsigned long *pointer;
    unsigned long *FRAM_write_ptr;
    unsigned long data;
    
    #define FRAM_TEST_START 0x1800
    
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;               // Stop watchdog timer
    
        P1OUT &= ~BIT0;                         // Clear P1.0 output latch for a defined power-on state
        P1DIR |= BIT0;                          // Set P1.0 to output directionOUT
    
        PM5CTL0 &= ~LOCKLPM5;                   // Disable the GPIO power-on default high-impedance mode
                                                // to activate previously configured port settings
        data = 0x11111111;                      // Initialize dummy data
    
        FRAM_write_ptr = (unsigned long *)FRAM_ADD_1;
    
        volatile long DATA1=1234567890,VALUE1=0;
    
        volatile long DATA2=9876543210,VALUE2=0;
    
        volatile long DATA3=6543278901,VALUE3=0;
    
        SYSCFG0 &= ~DFWP;
        *FRAM_write_ptr = DATA1;
        SYSCFG0 |= DFWP;
    
        pointer = (unsigned long *)FRAM_ADD_1; // address to read
        VALUE1 = *pointer; // data to read

    I believe the Ivalue is just complaining because of the type mismatch between a long and the unsigned int. Here is the memory view to show that the value of Data1 was correctly written to the address listed.

    Regards,

    Luke

  • No. The lvalue problem is from post incrementing a constant:

    pointer= ( int *)FRAM_ADD_1++; // address to read

  • You're right, I misread the FRAM_ADD as the FRAM_write_ptr. The original assignment should set FRAM_write_ptr to FRAM_ADD_1, you can then increment FRAM_write_ptr since it is a variable with a valid memory address. 

  • Hi and

    thanks for the reply, As per the datasheet 

    01800h to 019FFh is data memory, here i want to write 3 different values to different memory addresses so may i define the 3 different memory addresses as follows

    FRAM_TEST_START 0x1800

    FRAM_TEST_MID 0x1809

    FRAM_TEST_FINAL 0x1812

    it will work or not??

  • Perhaps, but not in the way you are expecting.

    If you try to access an integer or long at 0x1809, it will not be stored there. While some CPUs can handle unaligned access, the MSP430 isn't one of them. It will quietly ignore the lsb of the address and use 0x1808. If that location is not used for anything else, no problem.

  • To expand on David's comment.

    I highly recommend doing even addresses on MSP430 when hardcoding addresses.  Here is a fun view of what will happen if you use 0x1809 for your address. Below is the code slightly modified from the example code framwrite.c

    #include <msp430.h>
    
    void FRAMWrite(void);
    
    unsigned char count = 0;
    unsigned long *FRAM_write_ptr;
    unsigned long data;
    volatile unsigned long test;
    #define FRAM_TEST_START 0x1809
    
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;               // Stop watchdog timer
    
        P1OUT &= ~BIT0;                         // Clear P1.0 output latch for a defined power-on state
        P1DIR |= BIT0;                          // Set P1.0 to output directionOUT
    
        PM5CTL0 &= ~LOCKLPM5;                   // Disable the GPIO power-on default high-impedance mode
                                                // to activate previously configured port settings
        data = 0x0;                      // Initialize dummy data
    
        while(1)
        {
            data += 0xAA;
            FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
            FRAMWrite();
            count++;
            if (count > 100)
            {
                P1OUT ^= 0x01;                  // Toggle LED to show 512K bytes
                count = 0;                      // ..have been written
                data = 0x00;
                FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
                test = *FRAM_write_ptr;
            }
        }
    }

    I placed a breakpoint at test = *FRAM_write_ptr; and stepped through so I can see the value of what test becomes. Below are the values of FRAM_write_ptr and the value of test.

    This looks to be how you want, but if we look at the memory browser we can see what is actually happening.

    The value is actually stored at 0x1808. So even though we set the address and pointer to be at 0x1809, the stored and read value was in 0x1808. This is because the MSP430 needs an aligned address. This will cause issues if you have data that is packed next to each other as you can be overwriting data if you aren't careful.

  • Hi and

    Thanks for the suggestion, i am out of my workspace so i can't check the code with my board..

    So Please check the below code and if i made any mistakes please point them out..

    unsigned long *pointer;
    unsigned long *FRAM_write_ptr;

    #define FRAM_TEST_START 0x1800

    #define FRAM_TEST_MID 0x1808

    #define FRAM_TEST_FINAL 0x1812


    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

    P1OUT &= ~BIT0; // Clear P1.0 output latch for a defined power-on state
    P1DIR |= BIT0; // Set P1.0 to output directionOUT

    PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
    // to activate previously configured port settings

    FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;

    volatile long DATA1=1234567890,VALUE1=0;

    volatile long DATA2=9876543210,VALUE2=0;

    volatile long DATA3=6543278901,VALUE3=0;

    FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;

    SYSCFG0 &= ~DFWP;
    *FRAM_write_ptr = DATA1;
    SYSCFG0 |= DFWP;

    pointer = (unsigned long *)FRAM_TEST_START; // address to read
    VALUE1 = *pointer; // data to read

    P1OUT ^= BIT0;         //toggle led

    FRAM_write_ptr = (unsigned long *)FRAM_TEST_MID;

    SYSCFG0 &= ~DFWP;
    *FRAM_write_ptr = DATA2;
    SYSCFG0 |= DFWP;

    pointer = (unsigned long *)FRAM_TEST_MID; // address to read
    VALUE2 = *FRAM_write_ptr; // data to read

    P1OUT ^= BIT0;         //toggle led

    FRAM_write_ptr = (unsigned long *)FRAM_TEST_FINAL;

    SYSCFG0 &= ~DFWP;
    *FRAM_write_ptr = DATA3;
    SYSCFG0 |= DFWP;

    pointer = (unsigned long *)FRAM_TEST_FINAL; // address to read
    VALUE3 = *pointer; // data to read

    P1OUT ^= BIT0;         //toggle led

    }

    regards

    Surya

**Attention** This is a public forum