Introduction

I previously made a post on the MSP430FR2000 but decided to expand it into a more general series on the MSP430FR2xx family of microcontrollers.  I will aim this at people with microcontroller experience who may not be familiar with the MSP430 microcontrollers and FRAM (Ferromagnetic RAM).  In this post I will show how FRAM can retain the contents of a variable in memory for future use, even if power is lost.

 

The FR2xx series is a relatively low cost line with memory sizes of 0.5 to 4KB of FRAM.  Currently I am working with the following 3 variants:

MicrocontrollerFRAM (Kbytes)SRAM (Bytes)
MSP430FR20000.5512
MSP430FR21113.751024
MSP430FR243315.36 + 0.54096

All can run at supply voltages from 1.8 to 3.6 V with clock frequency up to 16 MHz.  The MSP430 family is known for low power but my primary interest is in the persistent nature and shared space offered by FRAM.  FRAM is fully unified memory and can be used for program code, constants, arrays, or any other kind of storage.  Storage can be made persistent - that is it can be retained even when powered off and used again when powered on.

 

The FR2433 is only available in VQFN and BGA packages while the other two can be obtained in TSSOP.  I guess I might have to get a toaster oven and learn to solder VQFN if I keep working with the FR2433.

 

New MSP-EXP430FR2433 LaunchPad

As stated in my last post, the FR2000 does not have enough memory for the project I have in mind.  Texas instruments has recently come out with the MSP-EXP430FR2433, a new LaunchPad that contains the FR2433 and I purchased one.  I like the changes that TI has made to the newer LaunchPads.  This one has buttons on the side which should be easier to reach when there is a BoosterPack (daughterboard) on top as well as female headers on the bottom of the board that the original G2 LaunchPads did not have.  It also has eZ-FET debug onboard which makes it easy to program and debug (and is a huge improvement over the emulation provided on the G2 LaunchPads).  The ez-FET can be used to program custom boards and I do that regularly.  The kit contains everything needed to get started, including a USB cable.

Storing Variables in FRAM

The following example demonstrates persistent storage of a variable using the FR2433 LaunchPad and TI Code Composer Studio (CCS) with the TI compiler.

/*
 * Test_FRAM demonstrates the persistent nature of FRAM by storing a variable
 * that controls the number of LED flashes.  An endless loop counts from 1
 * to 10 and starts over again.  Each time through the loop it flashes the
 * current count and then increments until 10 is reached.  If powered down
 * after displaying say 5 flashes it will flash 6 times when powered up again.
 *
 * Frank Milburn     18 Nov 2017
 * Tested on MSP-EXP430FR2433 with CCS V7.2.0.00013
 *           compiler ti-cgt-msp430_17.9.0.STS
 */
#include "driverlib.h"
#define  RED_LED               GPIO_PORT_P1,GPIO_PIN0
#define  FRAM_enableWrite()    SYSCFG0=FRWPPW
#define  FRAM_disableWrite()   SYSCFG0=FRWPPW|PFWP
#pragma  PERSISTENT(i)
int i = 1;
//--------------------------------  m a i n  -----------------------------------
void main(void)
{
    WDT_A_hold(WDT_A_BASE);                   // stop watchdog timer
    PMM_unlockLPM5();                         // Activate port settings
    GPIO_setAsOutputPin(RED_LED);             // set red LED to output direction
    while (1){
        int j;
        for (j = 1; j <= i; j++) {
           GPIO_setOutputHighOnPin(RED_LED);
           _delay_cycles(300000);
           GPIO_setOutputLowOnPin(RED_LED);
           _delay_cycles(30000);
        }
        _delay_cycles(1045000);
        FRAM_enableWrite();
        i++;
        if (i > 9){
            i = 1;
        }
        FRAM_disableWrite();
    }
}

As stated in the comment at the top of the code, the program counts endlessly from 1 to 10 and starts over again.  At each count it blinks out the current count on the red LED on the LaunchPad.  If power is removed at any point, the count has been saved and it starts up again at the same count when power is regained.  Here is a description of the code:

 

  • Line 12:  DriverLib is a library provided by TI for accessing peripherals.  They are mostly written in C, are reasonably efficient, and much easier to understand than direct register access.  I tend to use them when possible.
  • Line 13:  I like to give the pins a name that describes what they are doing and put them in a #define
  • Lines 14, 15:  When using FRAM on the FR2xx and FR4xx microcontrollers it is necessary to twiddle bits before writing.  This is unnecessary on some of the higher end FRAM microcontrollers when using PERSISTENT due to the capabilities of their Memory Protection Unit which is in hardware.  While not too much bother, I wish TI would have included the same capability on the FR2xx and FR4xx.  Here I have created the macros FRAMenableWrite and FRAMdisableWrite that  are more human readable than the direct register writes to the write protection bits.
  • Lines 16, 17: #pragma  PERSISTENT() contains the magic words.  It instructs the compiler and the linker to place whatever variable, array, struct, etc. contained in the parenthesis in FRAM and make it persistent.  That is, it will be available after power loss or low power modes where SRAM is lost, and will be in memory instead of the value initialized at compile time.  In this case it is a counter variable named "i".  The variable is defined to be an int on the next line and must be initialized, in this case to one. (1)
  • Line 21: The watchdog timer must be explicitly turned off or petted.  Here I turn it off.
  • Line 22: When some of the more recent microcontrollers in the MSP430 family come out of the low power state LPM5 the ports must be unlocked before they can be used.  Just stick this line in and it will do it.
  • Line 23: A good example of a DriverLib API and how it improves code readability
  • Lines 24 - 31:  Some inefficient code that blinks the red LED the same number of times as the current contents of the FRAM variable "i".
  • Lines 33 - 38:  This is important code.  As stated earlier, before writing to FRAM it is necessary to set the write bits that control access.  The macro FRAMenableWrite() does this and then the counter "i" is incremented.  When the counter gets to 10 it is reset to 1.  To maintain some sort of control over willy-nilly writing to memory that is also used for program space it is then protected again with the macro FRAMdisableWrite().

 

Conclusion

Try it out by letting it run for a while and watch the LED blink out the current value of "i".  When it gets to 4 or 5 blinks unplug it.  When it starts back up again it will be where it left off at 6 blinks or so instead of starting over at one.

 

There is no protection in this code.  For example, if the power is lost during a write to FRAM the value could be in error.  In my project I intend to use a ring buffer with a check after writing data.  Data points with errors can then be flagged.

 

By necessity this has been a relatively short post and there are other APIs, examples, and options for FRAM in the TI documentation.  If there are other features or matters you think important, please comment.  As well, I am a intermediate level self taught programmer as is probably evident.  If you see errors please point them out.  Thanks for reading...

 

Frank

 

Note (1):  The CCS compiler and linker take care of memory when PERSISTENT is used.  To see things are placed, open up the Debug folder in CCS and look for the .map file.  In the Section Allocation Map look for .TI.persistent and you should see the origin and length of whatever has been placed there.