25 May 2012

Tutorial 18: Finishing the UART Transceiver

This last tutorial in this series will be fairly short, because there's very little to be done! If we combine tutorial 16f and tutorial 17, we're nearly done building a full-duplex UART transceiver.  There are a few little details that need to be explained in order to get it to work properly, however.

  • A bit counter will be needed for both transmitting and receiving, if you're to be able to do them simultaneously.  This takes another 8 bytes of memory, of course.
  • While not necessary for the UART aspect, this code uses interrupts on two pins of P1. Any output on GPIO, even if interrupts are disabled for the pin, will set the corresponding bit of P1IFG on a rising or falling edge, depending on the setting of the corresponding bit in P1IES. Because the two LEDs are being used, any time the LED is turned on we have a rising edge on that GPIO, which sets the bit in P1IFG. The method used in this code to deal with P1 interrupts fails in those cases, since P1IFG would not be exactly P1RX or BTN1.  To fix this, a mask is introduced so the switch statement in the P1 ISR only considers the bits for P1RX and BTN1, ignoring any others set bits of P1IFG.  There is one disadvantage to this particular scheme: if the UART receives a start bit at the same time as a button press occurs, one or both will be ignored (depending on the order and timing of the two events).
  • A new function is introduced to encapsulate sending a string of characters over UART.  This function makes use of a pointer, allowing us to write new values to the variable message. Be aware that other values in RAM could be overwritten if you're not careful.  Also, the function assumes a message length of exactly 16 characters, and will print garbage (or remnants of the last message) if you write a shorter message.  A longer message will be truncated.
  • Because the DCO is executing commands at a faster rate than the transmission, a short delay of bit_time is added to tx_byte().  This delay lets the transmission start before returning control to the main() function. Without it, the code could call tx_byte() again before transmitting actually starts, changing the value of TXBuffer before it has a chance to get sent.  
The transceiver code can be found in uartTXCVRG2231.c.  I've added a few features to demonstrate the full-duplex capability of the transceiver.  The commands 'r', 'g', and 'z' are retained from the receiver tutorial. To this has been added 'c', which prints a continuous message until another command (eg. 'z' to sleep) is sent.  Note that the command can be sent in the midst of a byte transmission and still work, since the receiver is operating on a separate timer/interrupt configuration.  I verified this to be the case using my logic analyzer, and found that a command was correctly received even while starting in the middle of a transmission.

In addition to the 'c' command, another command is set from a button press (using a non-keyboard ASCII character 0xAF), and can be done at any time, showing that the code can also work with physical interface interrupts as well as the serial transmission of commands.  The button will also stop the continual printing of a 'c' command as well, as it also resets the command variable to 'z'.

Remember to use 9600 baud transmission and to configure CCS to build and link to the header file with the UART calibration, as well as not erase the information memory segment containing the UART DCO calibration.

And with that, we've reached the conclusion of what I'll term as the "basic" tutorials for the MSP430.  A big "Thank you!" to all of you; I've received numerous notes of encouragement from many of my readers, and it's been very helpful.  This project and blog have been a great deal of fun, and wer a key addition to the training I received as a Ph.D. student. This isn't the end of the blog, of course.  I'll be back with more advanced tutorials, and, more importantly, examples of scientific measurements and experiments done with the MSP430.  In fact, my next post will start describing a project I've had in mind for a while.  In the mean time, I will start recompiling these first 18 tutorials into a single volume.  I have as-yet to decide just how it would be distributed, and exactly what form it would take. In any case, I hope all of you stay with me and enjoy exploring the MSP430.

22 May 2012

Tutorial 17: The Receiver

Once you've built a UART transmitter, the receiver is not much different!  The way we'll build the receiver here will be done in anticipation of putting both the transmitter and receiver on the same device, and we'll look at a few new things.

What's the Same

We'll use Timer_A to work with the timings, using the same bit_time value as the transmitter.  The timer will need an accurate clock, and we'll use the calibrated UART frequency from last time as well.  The interrupt service routine for the timer will handle all of the work for reading the serial data as it's transmitted to the device.

What's Different

There are a number of differences in how the receiver is handled, but most of them are quite minor.  We'll use interrupts on the GPIO to trigger receiving, for one.  Once we've seen a falling edge on the GPIO (signalling a start bit being received), we need to wait one half bit_time so that we're sampling in more or less the center of each bit, thus we need a definition for a half bit_time as well.  (We could just divide bit_time by 2, but that's actually kind of slow-- it's probably more conducive to just define another variable with the exact value we want.)  All of this will be handled by an interrupt service routine for the GPIO port.

In addition, we want to use TA1 instead of TA0 for the timing-- this will allow us to send and receive simultaneously, as each has its own independent timer.  TA1 has a slightly different way of handling the ISR, however.  It's worth noting that there's nothing special about TA0 for transmitting nor TA1 for receiving-- we could just as easily have reversed the two.  Which one you use depends on which pins you connect for transmit and receive.  On the LaunchPad (the earlier versions, anyway), Tx is connected to P1.1 and Rx to P1.2.  Looking at the datasheet for the devices that connect to the LaunchPad, P1.1 is connected to TA0.0, letting us use the output feature of Timer_A to change the bit automatically.  P1.5 can also be connected to the TA0.0 output, so that is another option.  P1.2, P1.6, and P2.6 can all be connected to the TA0.1 output, and are all possibilities for the transmit pin if you change from CCR0 to CCR1 for the transmitter's timer.  The receiver will be reading a GPIO, and could in principle be used with any GPIO pin.  (We'll look in a short while to how we can do transmitting on any GPIO as well.)

The Specifics

Alright, let's dig into the code.  First, we need to define our bit_time again, as well as a half_bit_time.  For 9600 baud at the UART calibrated frequency (7.3728 MHz), these correspond to 768 and 384 respectively.  We'll make use of the UART_FG flag variable again, leaving BIT0 for a transmitting flag and using BIT1 for a receiving flag.  The data will be loaded into a buffer again before being saved, using the int value RXBuffer.  The bit_count variable comes into play again, and will be used to count down the bits as they are received.  When we combine the transmitter with the receiver, we'll need one of these for each of the parts so they can count independently.  For now, I've just used the same variable name bit_count.

The DCO and Timer are initialized identically to the transmitter-- the differences in the code happen in the interrupt routines.  P1 is configured to read from our chosen receive pin (P1.2), enabling interrupts on a falling edge.  When the interrupt occurs (presumably at the start bit of a transmission), CCR1 is initialized to a half bit-time later, CCR interrupts are enabled, and P1 interrupts temporarily disabled until the data has been received.  This method precludes having to wait for the receive flag to clear before the next P1 interrupt, so no while loop is needed here.

The CCR1 interrupt is handled differently than the CCR0 interrupt.  For one, CCR0 triggers the interrupt flag TAIFG in the TACTL register.  All other capture/compare registers in a device will trigger flags in the TAIV register.  There is a single interrupt for this register, and so TAIV must be read to know which CCR caused the interrupt.  (Though in the LaunchPad devices there is only CCR1, the interrupt must be handled the same way as though there were further CCR's in the device.)  I've done this by using a C switch statement, looking specifically for a CCR1 flag, which is marked by bit 1 in TAIV.  TAIFG also appears in TAIV, but as the value 0xA rather than 0x2, so a case 2: is sufficient for identifying a CCR1 interrupt flag.  The flag is automatically cleared with the interrupt is serviced.  The bits are then read in bit_time intervals from the GPIO input.  When all 10 bits have been read, the timer interrupts are disabled and P1 interrupts re-enabled.

Now that we've covered essentially how the code works, you can test it out with uartRXG2231.c.  (Don't forget to configure it to not erase the information segments!)  Look at the main function here-- it's set up to look for single-character commands, recognizing the characters 'r' to toggle the red LED, 'g' to toggle the green LED, and 'z' to do nothing but go into a low power mode and wait for a command.  If an invalid command is sent, the code holds on to the current state of P1OUT and flashes the LEDs to signal an error and returns to the saved state.  After each command, the device returns to a sleep mode.  To use the code, be sure you have at least exited the debugger-- you may find that serial terminals don't like trying to communicate through the same port that is opened in CCS in debug mode; exiting debug mode releases the serial port for use. When connected to the proper port (at 9600 baud, of course), you should be able to send single character commands to toggle the red and green LEDs. Try sending an invalid character to see the error signal.

This is the simplest way of sending commands to the MSP430.  Obviously there are uses for multiple-character commands, or sending data directly.  We'll look at those techniques at some point in the future, but next time we'll combine the two parts into a full-duplex transceiver.

Reader Exercise: Add a command to clear both LEDs. See if you can come up with another function to add a command for.

19 May 2012

Tutorial 16f: The Transmitter

We now have all the tools to build a UART transmitter on the MSP430. We have an accurate clock, which operates at a frequency that gives us the best accuracy on standard transmission rates with the DCO. The best way to control the timing of our serial transmission will be to use the Timer_A peripheral, so let's look at how to configure it.

First, we need to ensure we have our DCO set to our custom calibration. The way I've chosen to do this is to use definitions in the header:
   #define CALDCO_UART  *(char *)0x10BE
   #define CALBC1_UART  *(char *)0x10BF
Then in our code, we can set the DCO just as we would for the 1 MHz calibration:
   BCSCTL1 = CALBC1_UART;
   DCOCTL = CALDCO_UART;
To make this even easier, you can put the #defines in a header file (I've called mine calibrations.h), and then include it in any program where you need to use the custom DCO calibration.

Now to set up our timer. First, we need to choose our transmission rate. The commonly selected rate is 9600 baud, and if you use only the LaunchPad's USB connection it may be the only rate that works.  (It's a little unclear still how the USB connection is set up-- the MSP430 UART connects to the MSP430 in the emulator, which has separate pins to forward the data to the TUSB chip interfacing with the USB port.)  This DCO frequency can reliably do transmission up to a rate of 921,600 baud. Any faster, and there may not be enough time to run the transmission code between bits.  The code you can download at the end of the tutorial is configured for 9600 baud.

The next thing we need is to know how many clock cycles occur during the time to transmit one bit. We'll transmit at 9600 bits per second, and our clock oscillates at 7,372,800 times per second, so there are 7,372,800/9600 = 768 clock cycles in each bit. (Note that this is exact; there's no fractional part being truncated in this division, which is why we chose this DCO frequency to start with.) This period is often called the bit time.
   bit_time = 24576;  // bit time for 300 baud
   bit_time = 768;    // bit time for 9600 baud
   bit_time = 64;     // bit time for 115,200 baud

The LaunchPad is set up to send the transmission over P1.1. Looking in the datasheet, we see that this pin can be used as the TA0.0 outputusing Timer_A, we can toggle this output when the TAR counter reaches the value stored in TACCR0. We have two options for this: we can use the timer's up-mode so that the counter resets after reaching TACCR0 of bit_time, or we can use continuous mode and reset TACCR0 to be bit_time cycles beyond the current value of TAR when it triggers an interrupt. (Doing this automatically accounts for roll-over.) The first would be an easy solution for our transmitter, but as we're working towards a full-duplex receiver/transmitter, and the receiver looks at P1.2 (using TA0.1, based on TACCR1 for timing, of course), it makes more sense to use the second method in anticipation of setting up the receiver next time so that we don't have conflicts in using the timer for both tasks.

The idle state for UART is logic high. When we configure the timer, we'll ensure that the TA0.0 defaults to setting P1.1. There's no need to start the timer until we're ready to transmit, but on the other hand there's no need to stop it unless you're concerned about power consumption. We'll go ahead and let the timer run for now, since as a peripheral it runs independently and won't interfere with any code running. We will, however, wait to enable interrupts until we're ready to transmit.

Once we're ready to transmit a character, we need to enable interrupts, and configure Timer_A to reset the TA0.0 output to signal the start of a character. TACCR0 is incremented to bit_time counts later, so the next interrupt occurs at the timing necessary for our chosen transmission rate. We then step through the bits being sent and tell the MSP430 whether the next bit should be set or reset, depending on our encoding. We'll use the standard 8N1, little-endian encoding, so it is determined by the lsb of the character we're sending. When all 8 bits have been sent, we then set TA0.0 to mark a stop bit, making a total of 10 bits for each character. Interrupts are then disabled until we have another character to send.

Take a look at the code in uartTXG2231.c. Note first of all the routine DCO_init(). This includes a trap–since we're accessing the flash memory directly, we run the risk of setting the DCO to its highest setting if we use a device that hasn't had the DCO calibration written to that memory address! This type of check will prevent that, and is not a bad thing to include even when using the factory calibrations. I've created an LED signal specifically to indicate a DCO calibration error: three flashes of LED1, repeated with a pause between sets. If you try this code with an uncalibrated G2231, it should immediately indicate this error. Note that it cannot tell if a written code is correct or not, only if the addresses we're accessing have been erased.

If you've jumped right in and tried to run the code after calibrating your DCO, you may still encounter the error.  CCS by default erases both the main memory and the information memory segments (except for INFO_A) when you program the chip; so your calibrations in INFO_B have been erased and the code won't run.  Rerun the UART calibration code, and then open the project properties.  (When uartTXG2231 is the [Active -Debug] project, you can find the properties in the File menu, or right-clicking the project name in the Project Explorer tab.)  In the menu on the left, select Debug.  In the window that comes up, select MSP430 Properties.  Here you'll see a list of Download Options; be sure to choose "Erase Main Memory Only" and close the properties window.  Now when you load this project into your device, it will only erase the Main Memory and leave the information memory segments alone.

This code is set up to demonstrate a few ways to transmit data.  Each loop is initiated by pressing the button on P1.3.  First, a string is stepped through and sent over UART character by character.  Individual characters are also sent, as is the value of a variable count, which is set to repeatedly count from 1 through 9.  Single digits can be sent as characters easily as they appear in order in ASCII-- the digit 0 is ascii code 48 = 0 + 48, 1 is 49 = 1 + 48, and so on.  A multiple digit number could be pushed through using code similar to what we used for the LCM.  These are some simple ways of putting data and messages through UART that take very little code space in your device.

The real magic happens in the tx_byte() and CCR0_ISR() routines.  When tx_byte is called, it first polls the UART_FG flag and waits for the TXbit to clear.  The byte being sent is loaded into a buffer and formatted to include the stop bit. The TXbit is set in UART_FG, an LED turned on to indicate transmission, and the timer is configured to reset at the next interrupt.  A character cannot be transmitted until at least bit_time after the previous transmission; since the MSP430 clock is so much faster than the data rate, you could potentially run into a problem of initiating a new character send microseconds after the last, rather than leaving at least one bit_time space between.  To prevent this, any present interrupt flag is cleared and the next interrupt is set for one bit_time after the current time.  This configuration leaves just slightly more than one bit time between characters.  The interrupts run the CCR0_ISR routine, which sets the next interrupt to be bit_time later, configures TA0.0 to the next bit state for the next interrupt, and shifts the transmission buffer down to pull the next bit to the front.

To see all of this happen, you'll need a serial terminal, such as RealTerm or PuTTY.  When your terminal is directed to watch the port your LaunchPad is on at the 9600 baud rate, you should see the message display every time you push the button.

Next time we'll use Timer_A to receive data, getting ready for a complete UART transceiver.

18 May 2012

Addendum to Tutorial 16c

As I've been reviewing what I've done so far, I started thinking about some way to test my claims in the tutorial discussing the need for accurate clocks in UART.  I recently acquired a logic analyzer, which is fast proving to be an extremely useful tool for me! I'll probably use it quite a bit in the coming months and years trying to understand and debug some of the designs I'm working through.

In any case, I thought it might be interesting to use it to show what happens when clocks are off slightly.  The four channels shown here are all measuring the same signal, with the Red channel clocking at the correct rate (9600 baud), Yellow at 3% Error (effectively 9888 baud), Green at 6% Error (the theoretical error from using two +/- 3% clocks, effectively 10,176 baud), and Blue at 10% Error (effectively 10,560 baud).



The second image zooms in to the first characters so you can see the frame errors more clearly.  The dots placed on each plot show where each channel is sampling the data stream.  At 6% error, the software is smart enough to decode the characters, but the stop bit on each is missed, making communication unreliable.  In practice, you need better than 5% combined error to have reliable communication in UART.  (Using identical systems, each needs a clock that is accurate to better than 2.5%.)

Note that this isn't really true in all cases; I'm using 8N1 encoding here.  If I were to use larger frames than the 10 bits used for 8N1, the smaller clock errors may eventually cause a frame error as well.  If you use a protocol that sends more than 10 bits, you'll need even more accuracy in your clocks.

Just an interesting little test I put together to try out my fancy logic analyzer.

07 May 2012

Dr. Olson

Boy, it's been a long time since I've worked on this blog. The good news is that, as of this month, I have finished my doctoral degree and will now (hopefully) have more time to dedicate to working on it! There are still many, many more ideas and projects I have in mind, so I hope those who have been here before will stick around, and those looking for new help will find it.

Thanks, everyone, for the patience and kind words that have consistently rolled in over the past few months. There are still a number of comments I have yet to moderate, mostly because I need to give them some thought before I can respond. I don't want to just post them, because I'm afraid I'll never respond if I do. =)

03 November 2011

Tutorial 16e: Programming the Flash Memory

When we call the calibration values CALDCO_1MHZ and CALBC1_1MHZ in the code for our MSP430, those values refer to the address in SegmentA where the values are stored. They're not located in a place that's easy to find, however; they're stored in the linker command file, specific to each device. (If you're curious, take a look at the file in ${base dir}/Texas Instruments/ccsv4/msp430/include/msp430g2231.cmd, where your base directory is wherever you've installed CCS (likely in C:\Program Files for Windows). Be careful not to change anything in this file, though; this file is essential for proper programming of the G2231 device, as each is to their respective devices.) We could make a copy of this file and use it in our linker when we program the MSP430, but that requires a number of steps that are difficult to remember. All we really need is a way to tell our program to look at the specific address where we've saved the calibration values for our UART. All we really need is a pointer.

Pointers
We've not dealt with pointers up to this tutorial, but they're not really a difficult concept. Let's say we have code that declares the following two items:
   int var;
   int *ptr;
The first is what we're used to seeing; we declare a variable of type int (16 bits in MSP430), which will store a signed integer value. The second is also a declaration of type int, but rather than a variable, it is a pointer. The stored number in ptr doesn't refer to the value of a variable, but rather the address where a variable of type int is stored. (The actual size of the pointer in an MSP430 is 16 bits, so char *ptr; would also be a 16 bit value, even though it points to memory where an 8 bit value is being stored.)

In the C language, we have a way to refer to the address of a specific variable by using the & character. So from this point, if we assign ptr = &var; then ptr now points to the address where we've stored the int value var. Similarly, we can reference the value stored in a pointer with the * character. int var2 = *ptr; would store the value at address ptr in the new variable var2. If we want to assign a specific address to a pointer, rather than reference the address of a variable, we can use a literal of the form (int *)0x1234.

In the MSP430, an int variable takes 16 bits, while a char variable take 8. When we want to reference a specific word, we'll use a pointer of type int. If we want to reference a specific byte, such as the calibration values for the DCO, we'll use a pointer of type char. To use the DCO values we'll program in SegmentB, we can use the following:
    char *CALBC1_UART = (char *) 0x10BE;
    char *CALDCO_UART = (char *) 0x10BF;
or, if we'd rather not use extra memory, define in the header:
    #define  CALBC1_UART    *(char *) 0x10BE
    #define  CALDCO_UART    *(char *) 0x10BF

The Flash Memory Controller
Ok, now we've got a handle on how to reference portions of the flash memory. Now it's time to learn how to actually write to it. The MSP430 has a peripheral designed specifically to handle managing the flash memory called the Flash Memory Controller. Since it would be dangerous to manipulate the flash memory willy-nilly, it's set up like the Watchdog Timer, so that a key is needed to change any of its four control registers. The key value is 0xA5, conveniently provided in the header files as the value FWKEY. Here are the portions we'll need to know about:

FCTL1

  • FWKEY (bits 15-8):  The key is read as the value 0x96. Each register has this.
  • BLKWRT (bit 7): control bit for block write mode. We will be writing word by word, so we'll save this function for a future tutorial.
  • WRT (bit 6): write mode enable. Before we can write to any flash segment, this bit must be enabled.
  • MERAS & ERASE (bits 2 and 1): Control the mode of erasure. You can erase a single segment, the entire main memory, or the main memory and information segments both. (Depending on whether SegA is unlocked.)
FCTL2
  • FSSELx (bits 7-6): These bits select which clock source to use for the programming.
  • FNx (bits 5-0): These bits allow you to divide the source clock by any factor up to 64. (Divide by FNx + 1)
FCTL3
  • FAIL (bit 7): We don't want to see this bit set! For our purposes, it could mean the clock source has failed for some reason. If this happens, it needs to be reset by software before anything else can be done.
  • LOCKA (bit 6): I won't go into how this works; this bit controls whether SegA can be erased/written. If you find you absolutely must change something in this segment, you can read in the Family User's Guide to learn how to use this bit.
  • LOCK (bit 4): When this bit is set, the flash memory is completely locked, and cannot be erased or written.
  • WAIT (bit 3): Indicates when the flash memory is being erased or written.
FCTL4
  • This register is not available on all devices; it controls the 'marginal read mode'. We won't be using it here.
To do a successful programming of the Information Segment, we first set the clock for the controller. The actual frequency isn't terribly important, as long as it falls between 257 and 476 kHz. The default DCO setting of the MSP430 is about 1.1 MHz, and so a division of 3 (FNx = 2) works well, giving us roughly 370 kHz. We'll calibrate the DCO to 7.3728 MHz, so a division of 20 (FNx = 19) will give us about the same.

If we have anything we want to save in the segment, then the entire contents would need to be saved to a buffer. Likely, your SegB is blank, so we'll just proceed forward. Next, we set the controller to erase mode. We don't want to erase the main memory segments, so we only need the ERASE bit. We then clear the LOCK bit to allow changing the flash memory. When the controller is configured this way, we initiate the erase cycle by writing to any address within the segment. There's nothing magic about what value we write, but it is absolutely crucial that you have your address pointer pointing to somewhere in the segment you actually want to erase!

Once it has erased, we reconfigure the controller to write mode (not block write), and then proceed to write the values we need, either as bytes or words. If you preserved the prior contents, a better method is to change the contents to the new values and use block write mode. For this tutorial, we'll keep it simple.

Finally, when everything is written, we clean up, clearing the write mode bit and locking the flash memory.


The code I wrote for writing the UART DCO calibration to Segment B using the TLV format is found in uartcalG2231.c. Remember, if you run this, it requires the watch crystal. If there is anything already stored in SegB, it will be lost. If you'd rather store it in Segment C (0x1040 to 0x107F) or Segment D (0x1000 to 0x103F), change the address in the assignment instructions accordingly. If you choose to put in in Segment A (0x10C0 to 0x10FF), look in the Family User's Guide for instructions on unlocking the Segment. I do not recommend this, however, since we're calibrating a non-standard DCO frequency. Wherever you choose to store it, you'll need to remember the address. If you use my method here, that address is 0x10BE for the CALBC1 value and 0x10BF for the CALDCO value. Next time we'll write code that pulls these calibration values from memory and configures the DCO and TimerA to start setting up our software UART.


This tool will be very useful to you; keep in mind that though the Value Line devices only have one DCO calibration and don't appear to have any calibrations for the ADC, there is space for them! This process is not too difficult, you can upgrade your devices to have better calibrations, essential for accurate scientific work. For more information on the ADC calibration values that are often included in MSP430 devices, see the TLV chapter of the Family User's Guide.

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.