02 November 2011

Tutorial 16d: Flash Memory and TLV

I've used a number of resources in preparing this tutorial; in addition to the Family User's Guide and the device datasheets, one of the most helpful was an application report titled MSP430 Flash Memory Characteristics.

We'd really like to hold onto our DCO calibration for two reasons. We'd like to be able to use it later, but we'd also like to do so without using up our limited code space with self-calibration. In addition, we may need it in an application where we don't have a crystal connected to the device. (Rather, we could program the calibrations in our LaunchPad with a crystal connected, and then transfer the chip to our intended application while retaining the calibration values in memory.) Programming the flash memory in the MSP430 is not difficult, but there are a few things that have to be done properly to protect your device. The steps done in programming make more sense when we understand how flash memory works.

The Science in Flash
A NOR flash bit is a transistor with a little pocket for storing charge.
The flash memory inside the MSP430 is what we call NOR flash (as opposed to the NAND flash that makes up your typical USB flash drive, for example). It works by trapping charge in an isolated region called a floating gate. The charge in the floating gate changes the transistor's threshold, and determines what value is read from the bit. Acting much like a switch, a positive charge in the floating gate makes it so the read voltage "closes" the switch, and we read a logic 1. A negative charge keeps the switch open, and we read a logic 0.

When we erase flash memory, each bit is put in a state where the floating gate is positively charged. Thus, a "blank" bit will always read 1; a byte of erased flash will read 0xFF. We can program the bit to a 0 by applying a high voltage to the control gate, which allows the floating gate to push charges through the drain. The resulting negative charge in the floating gate is retained, barring physical effects like quantum tunneling that take 100's of years to de-program the bit. (At 25°C, the typical lifetime of a NOR flash bit is on the order of 1,000 years!) Fortunately, the ability to generate this high voltage is built into the Flash Controller peripheral of the MSP430, so we are able to program the flash memory as long as the operating voltage on our microcontroller is at least 2.2 V.

The flash memory in the MSP430 is organized in chunks called segments. The Main Memory portion is divided into segments of 512 bytes. (That means there are 4 segments in the main memory of both the G2211 and G2231, which each have 2 kB available.) Each segment is further subdivided into blocks of 64 bytes. Additionally, an extra 512 bytes is included in each MSP430 device, divided into segments of either 64 or 128 bytes (one or two blocks, respectively). These segments make up the Information Memory portion of the device. The Value Line devices that come with the LaunchPad have four information memory segments of 64 bytes each, called Segment A–D.

The physical structure of the flash cells is important to us, as it has direct bearing on how we deal with it. First of all, when we erase flash memory, we can only erase an entire segment at a time! This means any time we need to change a 0 in a single cell to a 1, every cell in the segment has to be erased. When we program flash memory, the high voltage is applied across an entire block at a time, even if we are only programming one cell. This voltage causes stress to the flash cells, and so we cannot exceed a specified "cumulative programming time", typically 10 ms. Erasing releases the stress, and essentially resets our cumulative timer to 0. These stipulations affect our programming speeds and how often the block needs to be erased.

At the typical speeds we can use (between 257 and 476 kHz), we can program an entire block twice. (Note that in this case, "program" doesn't mean we can write any value-- we can change 1's to 0's twice. To change 0's to 1's, we are forced to erase the entire segment.) We cannot, however, program the same byte multiple times, even if we don't program any other bytes in the block. The rule of thumb, then, is if you reach 10 ms of programming time or write to the same byte twice, the block (and thus the entire segment for main memory) must be erased. This is a real pain, especially if we want to use main memory to store our calibrations. Because of this, I would recommend using the Information segments for storing anything you want to retain outside of the actual program in the device. The process you would use would be to read the entire contents of the block to a buffer (in RAM), erase the Information Segment, change anything necessary in the buffer value, and re-write the buffer to the segment. (It seems like a lot more to do than you're used to when using a flash drive, but in reality the same thing is happening there. Your computer just does a fantastic job of hiding it so you don't have to worry about it.)

Information Memory
A quick word about the various segments: segments B–D are each alike in dignity. However, SegmentA is set aside specifically by TI to store information that should be retained regardless of any programming changes. The factory calibrations, for example, are stored in this segment. As a result, this segment is locked, and you will have to set a particular bit before any instructions erasing or programming within this segment. In addition, to ensure integrity of the data stored in SegA, one word (two bytes) of it is set aside as a checksum, which I'll explain shortly. If you change anything in the segment, a checksum calculation will fail. Some programs rely on this, so if you really must change something in this segment, be prepared to deal with the consequences. Well, at least be prepared to recalculate what the checksum value will be. For our purposes in this tutorial, we'll use SegmentB instead, but we will program it in much the same way that SegmentA is structured. That way, if you choose, you can use SegA to store your calibrations, since that is where they are intended to be.

Memory Save
Button
Let's take a look at how SegA is put together. Fire up the debugger in CCS; it doesn't matter what code you're using, as we won't even be running the program. We just want to enter the debug mode. Once there, the default view has a panel on the right side with tabs for the code disassembly and memory; the memory tab shows the contents of the flash memory of the device. (If this window is not visible for you, you can find it by selecting Window → Show View → Memory.) The information memory is located (as specified in the datasheet) from address 0x1000 to 0x10FF. SegA starts at 0x10C0 and ends at 0x10FF. You can use this window to browse that region, or you can save a particular region of memory to a text file. To do this, click the save button, navigate to a file you want to save the data to, and enter a Start Address of 0x10C0 and a length of 0x20. (Note it specifies to give the length in words; a word is 16 bits in the MSP430, so there are 0x20 (32) words in the 64-byte segment.)

An example of the output from my G2231 device is here. The first line specifies where in the memory the dump comes from. The first line has one word–it comes from the two bytes at addresses 0x10C0 and 0x10C1. Take note that the lower address of the word refers to the least significant byte (LSB, as opposed to lower case lsb for least significant bit), while the higher address refers to the most significant byte (MSB). The last line has the 32nd word–from addresses 0x10FE (LSB) and 0x10FF (MSB). Most of the memory in SegA is obviously blank, as most of the entries are 0xFFFF. (Remember, when flash is erased it reads logic 1.) There are a few programmed words, however, so let's see what each one means. In the x2xx Family User's Guide (current revision as of this writing is slau144h), turn to the chapter on TLV, chapter 24. TLV stands for Tag-Length-Value. This is the format TI uses in SegA to store information. Basically, one word is dedicated to specifying the length of memory allocated to a specific type of data and what type of data is stored there. Table 24-1 gives an example of how this is done. The first word in the segment stores a checksum value. Note that it specifies the checksum as the two's complement of the bitwise XOR. If you start with the next word and XOR it with the third word, that result with the fourth word, and so on, then add it to the checksum value, it will add up to zero. Something like this:


int chksum = 0;
char passed;
int *i;
for (i=(int *)0x10C2; i<(int *)0x1100; i++) {
    chksum ^= *i;
}
if (chksum + *(int *)0x10C0 == 0)
    passed = 1;
else
    passed = 0;


Note: I'm not completely familiar with pointers just yet; I'm working that out in preparation for the next tutorial. If there's an error in this code, I'll correct it then. For now, think of it more as pseudocode.


Now that we understand how the segment memory is organized, let's look at what's inside it. Using my device, I have a checksum value of 0xB22C. The next word is 0x26FE. This means that the next 0x26 entries (38 bytes) are of type 0xFE. Looking in Table 24-2, we see that 0xFE refers to "TAG_EMPTY", meaning the next 38 bytes (or 19 words) are unused. Sure enough, the next 19 lines are all 0xFFFF. The next line gives the next Tag-Length entry: 0x1010. The next 0x10 entries (16 bytes or 8 words) are of type 0x10, which isn't specified in the Family User's Guide. I've submitted a question to TI support to find out about this. In any case, each entry is blank. The next Tag-Length listed is 0x0201, which means there's one word of type "TAG_DCO_30". Here we have the DCO calibration values at room temperature and 3 V. (Note that the Vcc value of the LaunchPad itself is 3.3 V, and remember that different voltage has a significant impact on the DCO!) There's only one entry, which we know has the values for CALBC1_1MHZ (0x86 on mine) and CALDCO_1MHZ (0xC4 on mine) as per the G2231 datasheet.


Reader Exercise: Using either your memory dump or mine, calculate the checksum of SegA and compare it to the value at address 0x10C0. Hint: xor'ing 0xFFFF twice has no effect; an even number of these lines can be ignored. When added to the stored checksum value, do you get zero? Calculate the two's complement by ~chksum + 1 and compare it to the stored value.


Preparing the Custom DCO Calibration
Here's the plan for our code: we'll find a custom calibration value for 7.3278 MHz and store it in SegB using the standard TLV coding set by TI. (You could do this in SegA if you wish, but since we're using a non-standard DCO frequency, I've opted to keep it out for now.) SegB is found in the memory range 0x1080 to 0x10BF. The organization of what we'll be writing will then be like this:
There's a typo here.. should be 0x38FE. I will fix the image soon.


We use the crystal to find the calibration value for 7.3278 MHz. This value is put into the above table to calculate the checksum: 
chksum = 0x38FE ^ 0x0201 ^ {calibration values}
       = 0x3AFF ^ {calibration values}
The value stored at 0x1080 is then ~chksum + 1.


Next, we erase SegB, and write in the following addresses:

  • 0x1080: two's complement of chksum
  • 0x1082: 0x37FE
  • 0x10BC: 0x0201
  • 0x10BE: 0x{CALBC1}{CALDCO}
This tutorial has ended up pretty long, so we'll end the discussion here. The next tutorial will review the registers in the MSP430 Flash Memory controller and describe how to program this information to the Information Memory.

Reader Exercise: The Value Line devices do not come with the other standard calibrations: 8 MHz, 12 MHz, and 16 MHz. In the chapter on TLV of the Family User's Guide, we see that the locations of these calibrations are standardized for SegA to appear in the order TLV Tag, CAL_16MHz, CAL_12MHz, CAL_8MHz, CAL_1MHz. The data in SegA for the Value Line devices doesn't leave room for these with the other three calibrations left blank, so the entire segment structure needs to be shifted. If we want to add these without loosing any of the remaining structure, how will the segment be set up? Draw up a table similar to that used in this tutorial to map out the segment structure, and show how to calculate the new checksum value based on this table.

6 comments:

deekazoid said...

Hi,

I found this tutorial very useful. Thanks. However, I have a question that I hope you can help me with.

How do I protect the values stored in the Information memory from being erased during power cycle?

That is, I want to store the data in InfoB and be able to read them after power off - power on.

Unknown said...

Excellent question!

Fortunately, it's very easy: you don't need to do anything! The memory in the MSP430 is flash technology (much like a thumb drive, or sd card), and so it will retain all of the information even after long periods of time without power.

The only time the info segments are erased is in using the debugger-- if you load a program into the MSP430 without being careful, it will erase the main and info memories before programming. In CCS, you have to specify explicitly that only the main memory should be wiped. (Unfortunately, I have yet to find a way to make this the default behavior, as I think it should be.)

There is not, however, a way to lock any of the other segments the way InfoA is locked. You just need to be careful to load new code correctly, and have the original programming on hand to restore your custom Info segments if need be.

deekazoid said...

Thank you very much. I notice that while using debugger to load the code the contents are erased. but otherwise the data is stored and i can retrieve it later.

Mattias said...

Hi David! Nice tutorial! I'm a bit interested if there are any particular reasons why you elected to store the SegB data in a TLV format with checksum? It is a bit more work to read out the data from a TLV structure instead of, say, just writing them into the first two bytes.

Of course, it's possible to just ignore the TLV info altogether and just read the specific calibration bytes, but then using a TLV structure just adds complexity.

Unknown said...

Mattias, that's a great question. I chose to do it mostly to illustrate how TLV works. It's entirely optional, of course. It does have advantages when you need to store multiple, unrelated values as a quick way to ensure the memory isn't corrupted in any way. Some may choose to go ahead and use SegA, and in that case TLV is a good idea to include. I opted for SegB to have a different demonstration of writing to flash, as the other tutorials I had seen all used SegA for this purpose.

Mattias said...

David: I think it's a good idea to store your own calibration in SegB to decrease the risk of trashing the SegA data. The TLV structure I'm not so sure of. BUT it had the distinct advantage that you got the opportunity to mention it in a tutorial! :-)