12 July 2010

Tutorial 02: The MSP430 Township and Registers

Most places I've found to learn how an MSP430 actually works inevitably start talking about architecture, addressing, buses, and varied other technical ideas.  Unfortunately, they all seem to require some electrical engineering experience as well.  Today we're going to attempt to explain what's needed to be able to use the MSP430 without having to understand the physical properties of bipolar junctions or anything else like that.  The technical knowledge is very helpful in fine-tuning a design or in programming in assembly, but a rudimentary knowledge is sufficient to start working in C.

One of the distinguishing characteristics of the MSP430 over other microcontrollers is its von Neumann architecture; all of the memory and information available to the processor is available in one place.  Other mcu's will treat different types of memory separately, which makes for some nice efficiencies, but complicates the design somewhat.  A simple way to view this is to picture an mcu as a town (or in the case of the Harvard architecture, a collection of towns).  For von Neumann systems like the MSP430, everybody lives together in the same town, each with their own unique address.  For Harvard systems, addresses may be duplicated, and so the particular town must also be specified.

Memory
The memory space in an MSP430 includes room for the program, room to store data, memory (RAM), and other important information that we'll get to later.  Today our primary interest is in a particular collection of addresses called registers.  These addresses essentially are the community services in our MSP430 town; things like the post office, power company, and so forth.  For the MSP430, the registers control the functions of various parts of the processor and its peripherals.  You can think of them as houses with switches and circuit breakers in them.  The setting of the switches determines if a particular event happens, what job a particular pin takes, how a particular peripheral behaves, and so on.  The registers are grouped into three sections: the special function registers (SFR), 8-bit peripherals (parts that need only 8-bits to read instructions), and 16-bit peripherals (obviously those needing a full 16-bits to read instructions).  As an example, lets look at the smallest of the MSP430's: the MSP430G2001.  Open up copies of the x2xx family guide and the G2x01 datasheet.


Please note that the above links may break on occasion, if TI updates either of these documents to a new revision.  The easiest way to find these is to go to TI's website, and use the "Search by Part Number" box.  For a G2x01 device, search for anything that falls in that category, such as the msp430g2001.  The family guide can be found on the pages for any of the x2xx family of devices.

Page 1-4 of the family guide shows a map of the x2xx family "towns".  You can see that the addresses for the SFRs are anywhere from 0h to Fh (the h denotes the value is in hexadecimal; in decimal you'd see these addresses as 0 to 15).  Next come the 8-bit peripherals; from 10h to FFh (16 to 255).  Note there is a large gap in the addresses between the RAM and the Flash memory.  The family guide shows a map for the entire x2xx family-- to see the values for our particular chip, we need to look at the datasheet.

Page 13 in the datasheet gives a table for all of the G2x01 and G2x11 device memory maps.  For the G2001, we have the peripheral registers, then 128B of RAM.  Addresses from 0201h to 10FEh are empty, and then we see a 256 byte portion called "information memory".  (This region stores calibration values and other important numbers that needed to be held when the power is gone.  Usually these won't be available to write to, but could be if necessary; but that's another post.)  Finally, we have the 512B for code, including at the very top of everything the interrupt vectors (again, that's another post).

Registers
Now that we can see what the G2001 town looks like, let's turn to how to use the switch houses we discussed.  The registers of the MSP430 are special sections of memory that configure the device and tell us when something important happens.  Page 12 of the datasheet shows the SFRs available in the G2001.  This device only lists 4 of them, in addresses 0h to 3h: Interrupt Enable 1 (IE1) and 2 (IE2), and Interrupt Flag Register 1 (IFG1) and 2 (IFG2).  Each address points to 1 byte of memory, so there are 8 bits (switches/breakers/etc.) in each register.  Page 12 shows which ones are usable for the G2001.

In this case, IE1 only has bits 0, 1, 4, and 5 available.  Likewise, IFG1 has bits 0-4.  The datasheet tells you the name of each of those bits and describes what they do.  For example, bit 0 in IE1 is named WDTIE, or the Watchdog Timer Interrupt Enable.  This bit is normally a 0, but if we configure the device to use the watchdog timer as an interval timer, then setting this bit to 1 allows the watchdog timer to raise a flag (IFG1 bit 0 to be precise) causing an interrupt (we'll get to that later too) under particular circumstances.  Essentially, this bit tells the MSP430 if the watchdog timer can signal the processor to do something special or not when it's used in a particular mode.

Now turn to page 17 of the datasheet.  This table gives the peripheral file map, or the addresses and names of the registers that affect the various peripherals in the device.  Note at the bottom it lists the SFRs we just discussed.  Any time you need to use a peripheral, this page will give you a starting point for knowing which switch houses you need to visit to be certain everything is configured properly.  We'll look at the registers for each peripheral specifically in their own posts.  Today, let's look at the registers for Port P1 and Port P2, as these are the most straight-forward.

The ports are the general input/output pins available on the device.  The pinout diagram on page 3 shows that the G2001 has all 8 pins for P1 (P1.0 through P1.7), and 2 pins for P2 (P2.6 and P2.7).  Each register for a port has bits that correspond to each of the pins; for example, P1.4 is controlled by bit 4 in each of the registers.  Let's go through each of the registers available for a port now.

PxIN
The input register for a port is a read-only value.  When a pin is selected to be an input, reading the value of the bit tells you the voltage currently on that pin.  The entire byte PxIN reads the value of all of the inputs on that port at once.  Keep in mind this is a digital system, so there are only two values that can be read; a 0 or a 1.  These values correspond to the voltages on Vss (0) and Vcc (1), which are generaly 0 V and between 1.8 and 3.6 V respectively.  There is a particular threshold built into the device such that any voltage over that value is read as a 1 and any voltage read below is read as a 0.  To prevent any damage to the chip, you should certainly never try to read any voltages outside the range between Vss and Vcc directly.

PxOUT
The output register for a port is writeable.  When a pin is selected to be an output, we can change the voltage on that pin by writing a 0 or a 1 to its corresponding bit in PxOUT.  Like the input, a 0 corresponds to the voltage on Vss, and a 1 corresponds to the voltage on Vcc.

PxDIR
The direction register determines whether a pin is an input (bit is low, or 0) or an output (bit is high, or 1).  At the beginning of your program, you should configure the port pins to their values as inputs or outputs.  That's not to say you can't change a pin's behavior in the middle of your program, of course.

PxIE, PxIES, and PxIFG
These three registers are the interrupt enable, interrupt edge select, and interrupt flag registers for the ports.  We'll look at these three registers together, as they work together.  You can use the port pins as a way to flag special circumstances to the processor and trigger an interrupt.  For now, think of an interrupt as a message to the CPU to hold on what it's currently doing and take care of the special circumstance.  Once the interrupt has been satisfied, the CPU returns to where it was before.  You enable this behavior by setting the PxIE bit for the pin being used to 1.  PxIES bits determine if the flag is triggered by the pin going from 0 to 1 (IES bit set to 0) or from 1 to 0 (IES bit set to 1).  In other words, a flag is triggered when it detects a positively sloped, rising edge or a negatively sloped, falling edge.  When the interrupt is triggered, it sets the corresponding bit in PxIFG.

PxSEL
Looking back at the pinout diagram on page 3, you can see that most of the port pins have multiple functions. The selection register determines what function a pin takes on.  The default function is listed first, so P1 defaults to general I/O pins, whereas the P2 pins default to connections to a crystal oscillator.  Changing the bits in PxSEL changes the behavior of the pins.  We'll look at the particular settings later; for now, plan on using the default values in PxSEL.

PxREN
The resistor enable register is a very useful feature for the ports.  Sometimes it is helpful to pull the voltage up to Vcc or down to Vss, such as when you attach a push button to a pin.  The resistor enable register lets you turn on that ability.  When a PxREN bit is enabled, you can select it as a pull-up or pull-down resistor by setting the corresponding bit in PxOUT, 1 for up, 0 for down.

Now that we've identified some of the switches we have to use, in the next post we'll take a look at how to actually set them in the software we write to the device.

18 comments:

Anonymous said...

Awesome tutorial so far. Just purchased the kit. Only question is, where do you find the C syntax for the MSP430? Ie PxSEL, PcREN etc... is there a document somewhere describing all the syntax available to the chip with examples on the uses of them?

David said...

Syntax, yes; the Family User's Guide and the Device Datasheets are invaluable for that. Examples? Well, there are code examples you can download from TI, and others are starting to post them up. This area of documentation, making what's in the guides more accessible, is where things are lacking right now. As the community grows, though, more examples, explanations, and tutorials like what I've been trying to put together should start showing up!

Jon said...

When we initialize the P1OUT = 0 we are basically setting all the pins to inputs. My first question is what does that make P1IN look like. Is P1OUT = 0 the same as P1IN = 0b11111111? I understand setting an output is the opposite of setting an input since they both come from the same pin. Does this mean I could initialize P1IN to equal all inputs and have the same result as P1OUT = 0?

Second when we initialize P1OUT = 0, does that set P1DIR = 0, or does P1DIR = 0 by default? I ask the question since when using inputs and outputs in the examples in this tutorial series we set P1OUT = 0 and then adjust the outputs as necessary. However we say that by default the bits in P1DIR are set as inputs.

Thanks,

Jon

David said...

Good questions; I think it clears up if you realize that P1OUT and P1IN are not the same thing.

First of all, P1DIR is a completely separate register. If we assign a value to a particular bit in P1OUT, it sets the voltage on the corresponding pin if (and only if) the equivalent bit in P1DIR is set (1). If the bit in P1DIR is cleared (0), then setting the bit in P1OUT has no effect on the MSP430.

P1IN simply reads the values set on the P1 pins. If P1DIR bits are cleared, it reads the voltage on the pin. If the bits are set in P1DIR, the P1IN bits will read whatever is currently set as the output on those pins (ie. it will be the same as the corresponding bit in P1OUT).

In the code, we will often initialize all outputs to 0, so we just say P1OUT = 0;. This has no effect on any inputs, and so it's just much easier to write than clearing each output bit specifically. It does not change the bits in P1DIR at all; when the chip first powers, the P1DIR bits are all cleared, and you must set any bits for outputs you plan to use yourself.

Hope that helps; let me know if there's anything else we can try to clear up.

Jon said...

I believe that all makes sense. I think my confusion was with the fact that P1IN bits are read only. If I understand correctly all the bits in P1IN are 0 until the pin corresponding to the bit receives a voltage and the pin goes high (or to 1). That seems to make the most sense to me. If I think about the P1OUT bits it makes sense that I have the ability to change the bit to a 1 or 0 since I can write to it. Writing to it changes it like when toggling an LED. Also writing setting the bit in the P1DIR to an output gives the pin the ability to be written to which makes sense why if it is not set to 1 changing the P1OUT bit in code does nothing.

If you could clarify my thinking I would appreciate it. Thank you for all the help. It's great to get the speedy responses this blog delivers.

Take care,

Jon

David said...

That sounds about right to me. Perhaps one more way to put it (hope I'm not beating the dead horse here) would be that P1IN tells you what's currently on the P1 pins. P1OUT lets you control what's on the P1 pins, assuming you're able to (they're set as outputs). P1DIR lets you choose whether you can write to the pins or not.

I do keep the responses as quick as I can, which is a function of how soon I see my email and how well I understand the answer to the question. =) Hopefully some day soon I can spend some time re-formatting the web interface to make the whole thing more accessible too.

billabott said...

The location of the "x2xx family guide" http://focus.ti.com/lit/ug/slau144e/slau144e.pdf has changed to http://focus.ti.com/lit/ug/slau144f/slau144f.pdf

billabott said...

me again. I looked on the TI site for revision e of the family guide. It is no longer there; only revision f seems to be available - even from the link that they say points to rev. e. I don't know what the policy is on this but it seems that this is going to make a little trouble for you and your blog readers. sorry to bear bad news. :( probably the document is still on the server but pushed into an archive directory. good luck.

David said...

Shouldn't be too much of a problem; the current revision is probably the best to be working from anyway. I'll change the post's wording to be more indicative of finding the most recent revision.

Coinbird said...

Guide is now at rev g.
http://focus.ti.com/lit/ug/slau144g/slau144g.pdf

treflip said...

http://focus.ti.com/lit/ug/slau144h/slau144h.pdf

newest x2xx family guide as of 6/18/11

Anonymous said...

I was just starting to muddle my way thru with the MSP430 when I found your blog. Really clears up some basic questions I had. Thanks!

Suggestion - instead of referencing page #'s, which change, try referencing Table/Figure #'s or titles. e.g. Table 8 referenced as being on p. 13 is now on p.11.

aeozyalcin said...

Hello
This is a great tutorial! Thank you for this.

But I have a major problem. After following the tutorial, I noticed that the LEDs blinked even when the button was not pressed. I also noticed that when I touch the pin of port 1.3(SW 2 port) and vcc pin at the same time, the circuit starts behaving properly. Do I need to enable pullup/pulldown resistors for the button pin? Can you tell me what I should do to avoid this?

Thanks

David said...

If you're using a LaunchPad, it should work, since it has an external resistor on the board to pull up P1.3. If not, enabling the internal resistor will definitely solve the issue. You can do that by P1REN |= BIT3; and P1OUT |= BIT3;

That's about the best I can do without more information on what you've got, I'm afraid. Have you modified the code at all? Using LaunchPad with CCS? Hopefully some of the above will be helpful, and you can find the issue!

reparaciĆ³n sintetizadores said...

Thanks

hanishkvc said...

The address space mentioned has free above should start from 0x280 rather than 0x201 has there is the 128 Byte RAM. Please fix this oversight.

And you have a wonderful blog related to MSP430 here.

hanishkvc said...

Also adding to my previous comment the end of free space is 0xFFE(word address) rather than 0x10FE, because 0x1000 to 0x10FF is the 256 byte Information Memory.

Bruno said...

Thank you so much for your carefully chosen words. As a very beginner to microcontroller programming, i do appreciate a lot!