In my plant-watering project, I need to control a relay switch to turn a water pump on and off. I chose this nice, inexpensive relay to do the job, and confirmed that 3V does indeed close the switch in the relay. If I connect the coil to the output of the MSP430 and set a high value on the pin, however, nothing happens.
The reason is that the MSP430 GPIO pins are limited in the amount of current they can source/sink. According to the G2x11 datasheet, the total output for P1 should not exceed +/- 48 mA. (This is also true for any of the Value Line devices.) Omron's datasheet for the G5LE shows that the power consumption of its coil is 400 mW, which means at 3.6 V provided by the LaunchPad, it draws 111 mA, well above what the MSP430 can do!
Fortunately, there's an easy way around this that requires just a few inexpensive components. A fellow ham, N1HFX, has an excellent write up on transistor switches that includes an example for a relay switch. I've borrowed his schematic image and changed the values to what I've used for my relay. Some external parts won't need the diode, but it's cheap insurance for any inductive circuits like a mechanical relay. I'm using the same power source as for the chip (from the USB port via the LaunchPad for testing, but eventually a couple of AA batteries), but it's also possible to use a different supply, and even (with some careful design) use a different voltage. Just be certain that your current draw from the MSP430 does not exceed its limits.
One thing to keep in mind with this circuit is that rather than the switch being on with logic high, it's on with logic low. Since I want the switch off by default, I need to be sure that I've initialized the output pin to a high value before setting it as an output.
(Thanks N1HFX, de KE7BFA!)
30 July 2010
29 July 2010
Tutorial 08-b: Configuring the DCO
The MSP430's Digitally Controlled Oscillator is one of the most important peripherals to be able to manage. It's the easiest of the clock sources to configure, as it requires no external parts and is controlled completely by software. The DCO (within the BCS+) is configured with two registers: DCOCTL and BCSCTL1. Look up the maps of these two registers in the x2xx Family User's Guide, page 5-14.
This image comes directly from the User's Guide, and explains how to select the different possible frequencies for the DCO. The total range of frequencies is divided into 16 overlapping ranges. So Range 7's low end overlaps Range 6's high end, and Range 7's high end overlaps Range 8's low end. Make sense? Ok, each range is further subdivided into 8 possible frequencies. If you plot all of these out, you get something similar to the above image, but with 16 lines instead of the three representative lines shown here. There are then 128 distinct frequencies available to the DCO, with some overlap of course.
Registers
We are able to select the frequency we use with the RSELx bits in BCSCTL1 (select range 0 to 15) and the DCOx bits in DCOCTL (select step 0 to 7). How do we know which pair we want? The device-specific datasheet should give you some help in that regard. For the G2x11, we see the DCO frequency table on page 26. For any device, this table will either list the typical value for a sample of selections, or a set of min/max values for the selection set. (Note: As of this writing, the current revision of the G2x11 datasheet (SLAS695B) is printed incorrectly, giving typical values for some selections and min/max values for others. In future revisions of the document it will likely be changed to only one or the other.) TI uses an ordered pair notation to describe the DCO setting, such as (8,2) for Range 8, Step 2 (or DCO 2 to use their term). We'll use that notation from now on to describe DCO settings with the convention DCO(r, s) where r is the range value and s is the step value.
As an example, note that DCO(6,3) is typically 0.80 MHz (or 800 kHz), while DCO(13,3) is 7.8 MHz. Note that the table only lists DCO(r,3) pairs for each range, and also values for DCO(0,0) and DCO(15,7), the low and high end of the DCO values. What about all the others? At the bottom of the table, there are two values called SRSEL and SDCO. These values give the ratio of subsequent ranges and steps as SRSEL = (r+1,s)/(r,s) and SDCO = (r,s+1)/r(s), allowing you to get a value for any of the possible combinations. For example, DCO(6,4) would be SDCO * DCO(6,3), or in the case of the G2211, 1.08*0.80 Mhz = 0.864 MHz. DCO(6,7) would be SDCO * DCO(6,6) = SDCO * (SDCO * DCO(6,5)) and so on, so a general formula would be DCO(r,s+n) = SDCO^n * DCO(r,s). (Note that you can get the lower step values with negative n, eg. DCO(6,1) = DCO(6,3-2) = SDCO ^ (-2) * DCO(6,3).)
One final topic before getting to the code; each MSP430 device comes with at least one calibrated value for the DCO. These values are found for each individual chip at the fabrication facility and programed into the information memory section of the flash memory. The values are not necessarily the same for my G2211 as it is for yours, but if you ever accidentally (or intentionally) erase the calibration values, TI does provide a program that will recalibrate the DCO and write the values to the memory for later use. (You should be able to find this program in the code examples you can download for your device. The G2xx code can be obtained here, and the program is called msp430x20xx_dco_flashcal.c.) The G2x11 devices only have one calibrated frequency at 1 MHz.
Example
Now for the practical part. Fire up CCS with your launchpad, and enter the debugging mode with any program you have. We're not going to actually run the program, just look at some of the registers as they come up by default. The MSP430 x2xx devices supposedly default to a 1.1 MHz DCO. What value actually comes up? In the debugger, open up a view of the registers, and find the BCS+ registers under System_Clock. For the G2211, the registers start with values of 0x60 for DCOCTL and 0x87 for BCSCTL1. Expand the registers to look at the individual bits, and we can see that RSEL is 0b0111, or 7, and DCO is 0b011, or 3. The default setting for the DCO is DCO(7,3), which according to the datasheet is between 0.80 MHz and 1.50 MHz. The actual value depends on your unit, the temperature, pressure, phase of the moon... ok, not really the moon phase, but you get the idea. If you happen to have an oscilloscope, we can actually look at the frequency by using the alternate function for P1.4-- the SMCLK can be driven by the DCO and put on this pin for external use.
Let's write up some code to actually change the DCO now. We're mostly interested in manipulating the DCOx and RSELx bits, which are bits 5-7 in DCOCTL and 0-3 in BCSCTL1 respectively. When we've selected the pair of values we want, we can change those bits in code. For example, if we want to change to DCO(12,2), we want 0b1100 for RSELx and 0b010 for DCOx. We can set these values in our code with the following:
BCSCTL1 &= ~(BIT0 + BIT1); // set bits 0 and 1 to 0
DCOCTL |= BIT6; // set bit 6 to 1
Does the order matter? Well, keep in mind the frequency will change with every step. So after the first line, assuming we have the default configuration found above, the bits have changed to 0b0100, putting us in DCO(4,3). The second line moves us to DCO(12,3). The third line moves us to DCO(12,2), making the last step redundant. If we had started by setting bits 2 and 3 in RSELx, we would have stepped from DCO(7,3) to DCO(15,3), putting a really high frequency on everything. That may not be an issue, but if you have any sensitive components you might consider stepping rather than jumping up to higher frequencies. If MCLK is driven by DCO (it is by default) you may find some problems as the higher frequencies may be above the 16 MHz limit for the processor. Going the other direction, jumping down puts the DCO at a really low frequency, which slows down the operation of the subsequent steps, but shouldn't cause any serious trouble.
Setting to calibrated values is much easier, since CCS provides us with shortcuts to those values:
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
Those two lines are all that's needed to set the DCO at exactly 1 MHz! (Within 3%, anyway.)
I've written some code in dcodemo_g2211.c that gives an example of how to use the DCO in a program. Browse through it and try running it on your launchpad to see how it works. The program simply flashes the LED with a delay loop and waits for the user to press the button. The program then changes the DCO frequency, and re-flashes the LED. Since the frequency increases, however, the LED flash is much faster, even though it uses the same delay loop! The DCO is controlling the operating speed of the processor, and so the for loop steps through much more quickly. Another button press slows down the DCO and re-flashes the LED, this time at a slow rate. Another button press returns the LaunchPad to the original state, and the program runs through again.
We haven't covered all the features of the DCO yet, and will discuss them as we progress further. Next we'll talk about the use of timers in the MSP430. As always, feel free to discuss and ask questions about what you've read here!
Reader Exercise: My G2211 unit that came with my LaunchPad uses DCO(6,5) for the calibrated 1 MHz frequency on the DCO, and sets the MODx bits to 0b00101 (which is also 5). What does yours use? Write a program that uses the calibrated value and use the debugger to find out what the register settings are for the 1 MHz calibration on your unit. Supposedly, these are set individually to the chip, so I'd be interested to hear if anyone actually has a different value than mine!
This image comes directly from the User's Guide, and explains how to select the different possible frequencies for the DCO. The total range of frequencies is divided into 16 overlapping ranges. So Range 7's low end overlaps Range 6's high end, and Range 7's high end overlaps Range 8's low end. Make sense? Ok, each range is further subdivided into 8 possible frequencies. If you plot all of these out, you get something similar to the above image, but with 16 lines instead of the three representative lines shown here. There are then 128 distinct frequencies available to the DCO, with some overlap of course.
Registers
We are able to select the frequency we use with the RSELx bits in BCSCTL1 (select range 0 to 15) and the DCOx bits in DCOCTL (select step 0 to 7). How do we know which pair we want? The device-specific datasheet should give you some help in that regard. For the G2x11, we see the DCO frequency table on page 26. For any device, this table will either list the typical value for a sample of selections, or a set of min/max values for the selection set. (Note: As of this writing, the current revision of the G2x11 datasheet (SLAS695B) is printed incorrectly, giving typical values for some selections and min/max values for others. In future revisions of the document it will likely be changed to only one or the other.) TI uses an ordered pair notation to describe the DCO setting, such as (8,2) for Range 8, Step 2 (or DCO 2 to use their term). We'll use that notation from now on to describe DCO settings with the convention DCO(r, s) where r is the range value and s is the step value.
As an example, note that DCO(6,3) is typically 0.80 MHz (or 800 kHz), while DCO(13,3) is 7.8 MHz. Note that the table only lists DCO(r,3) pairs for each range, and also values for DCO(0,0) and DCO(15,7), the low and high end of the DCO values. What about all the others? At the bottom of the table, there are two values called SRSEL and SDCO. These values give the ratio of subsequent ranges and steps as SRSEL = (r+1,s)/(r,s) and SDCO = (r,s+1)/r(s), allowing you to get a value for any of the possible combinations. For example, DCO(6,4) would be SDCO * DCO(6,3), or in the case of the G2211, 1.08*0.80 Mhz = 0.864 MHz. DCO(6,7) would be SDCO * DCO(6,6) = SDCO * (SDCO * DCO(6,5)) and so on, so a general formula would be DCO(r,s+n) = SDCO^n * DCO(r,s). (Note that you can get the lower step values with negative n, eg. DCO(6,1) = DCO(6,3-2) = SDCO ^ (-2) * DCO(6,3).)
One final topic before getting to the code; each MSP430 device comes with at least one calibrated value for the DCO. These values are found for each individual chip at the fabrication facility and programed into the information memory section of the flash memory. The values are not necessarily the same for my G2211 as it is for yours, but if you ever accidentally (or intentionally) erase the calibration values, TI does provide a program that will recalibrate the DCO and write the values to the memory for later use. (You should be able to find this program in the code examples you can download for your device. The G2xx code can be obtained here, and the program is called msp430x20xx_dco_flashcal.c.) The G2x11 devices only have one calibrated frequency at 1 MHz.
Example
Now for the practical part. Fire up CCS with your launchpad, and enter the debugging mode with any program you have. We're not going to actually run the program, just look at some of the registers as they come up by default. The MSP430 x2xx devices supposedly default to a 1.1 MHz DCO. What value actually comes up? In the debugger, open up a view of the registers, and find the BCS+ registers under System_Clock. For the G2211, the registers start with values of 0x60 for DCOCTL and 0x87 for BCSCTL1. Expand the registers to look at the individual bits, and we can see that RSEL is 0b0111, or 7, and DCO is 0b011, or 3. The default setting for the DCO is DCO(7,3), which according to the datasheet is between 0.80 MHz and 1.50 MHz. The actual value depends on your unit, the temperature, pressure, phase of the moon... ok, not really the moon phase, but you get the idea. If you happen to have an oscilloscope, we can actually look at the frequency by using the alternate function for P1.4-- the SMCLK can be driven by the DCO and put on this pin for external use.
Let's write up some code to actually change the DCO now. We're mostly interested in manipulating the DCOx and RSELx bits, which are bits 5-7 in DCOCTL and 0-3 in BCSCTL1 respectively. When we've selected the pair of values we want, we can change those bits in code. For example, if we want to change to DCO(12,2), we want 0b1100 for RSELx and 0b010 for DCOx. We can set these values in our code with the following:
BCSCTL1 &= ~(BIT0 + BIT1); // set bits 0 and 1 to 0
BCSCTL1 |= BIT2 + BIT3; // set bits 2 and 3 to 1
DCOCTL &= ~(BIT5 + BIT7); // set bits 5 and 7 to 0DCOCTL |= BIT6; // set bit 6 to 1
Does the order matter? Well, keep in mind the frequency will change with every step. So after the first line, assuming we have the default configuration found above, the bits have changed to 0b0100, putting us in DCO(4,3). The second line moves us to DCO(12,3). The third line moves us to DCO(12,2), making the last step redundant. If we had started by setting bits 2 and 3 in RSELx, we would have stepped from DCO(7,3) to DCO(15,3), putting a really high frequency on everything. That may not be an issue, but if you have any sensitive components you might consider stepping rather than jumping up to higher frequencies. If MCLK is driven by DCO (it is by default) you may find some problems as the higher frequencies may be above the 16 MHz limit for the processor. Going the other direction, jumping down puts the DCO at a really low frequency, which slows down the operation of the subsequent steps, but shouldn't cause any serious trouble.
Setting to calibrated values is much easier, since CCS provides us with shortcuts to those values:
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
Those two lines are all that's needed to set the DCO at exactly 1 MHz! (Within 3%, anyway.)
I've written some code in dcodemo_g2211.c that gives an example of how to use the DCO in a program. Browse through it and try running it on your launchpad to see how it works. The program simply flashes the LED with a delay loop and waits for the user to press the button. The program then changes the DCO frequency, and re-flashes the LED. Since the frequency increases, however, the LED flash is much faster, even though it uses the same delay loop! The DCO is controlling the operating speed of the processor, and so the for loop steps through much more quickly. Another button press slows down the DCO and re-flashes the LED, this time at a slow rate. Another button press returns the LaunchPad to the original state, and the program runs through again.
We haven't covered all the features of the DCO yet, and will discuss them as we progress further. Next we'll talk about the use of timers in the MSP430. As always, feel free to discuss and ask questions about what you've read here!
Reader Exercise: My G2211 unit that came with my LaunchPad uses DCO(6,5) for the calibrated 1 MHz frequency on the DCO, and sets the MODx bits to 0b00101 (which is also 5). What does yours use? Write a program that uses the calibrated value and use the debugger to find out what the register settings are for the 1 MHz calibration on your unit. Supposedly, these are set individually to the chip, so I'd be interested to hear if anyone actually has a different value than mine!
20 July 2010
Tutorial 08-a: The Beating Heart (BCS+ Part I)
With the basics behind us, we can jump into some of the more advanced (and far more interesting!) topics to learn how to use the MSP430 microcontroller. The goal of this tutorial series is to examine the various peripherals available on the MSP430 devices and how to use them. Along the way, we'll look at the concepts of interrupts and low power modes as well. To follow this tutorial, it is extremely helpful to have a copy of the Family User's Guide and Datasheets for the specific device you are using. I printed these out (including the 600+ page User's Guide) and had them bound for easy access, but an electronic copy will work fine. The first peripheral we'll look at is the Basic Clock System + (BCS+) used in the MSP430x2xx Family, including the Value Line chips compatible with the LaunchPad platform. This system is detailed in Chapter 5 of the x2xx Family User's Guide.
We've seen in our analogy to a town that we can issue different commands and control different things easily in the MSP430. Just as in any town, if the parts aren't working in conjunction then everything winds up in a big mess. When does this switch get flipped? Does it happen before or after that event? What order do I do things, and when? Every town needs a clock, and a microcontroller depends on one.
The 3 Clocks
Each family of MSP430 has a slightly different clock system, though many of the principles are the same for each. The x2xx family uses the BCS+ system, which provides the MSP430 with three separate clocks that can run as quickly as 16 MHz in particular conditions. The reason we have three clocks instead of just one or even two is to compromise between systems that need speed and the ability to minimize power consumption, one of the real hallmarks of the MSP430. Faster clocks consume more power, so to really reduce the power used we need slower clocks. But some functions need to respond and conclude quickly, so we also need fast clocks. You can design around the use of a single clock, but having the flexibility of three is powerful. Let's look at the three clocks available in BCS+:
We've seen in our analogy to a town that we can issue different commands and control different things easily in the MSP430. Just as in any town, if the parts aren't working in conjunction then everything winds up in a big mess. When does this switch get flipped? Does it happen before or after that event? What order do I do things, and when? Every town needs a clock, and a microcontroller depends on one.
The 3 Clocks
Each family of MSP430 has a slightly different clock system, though many of the principles are the same for each. The x2xx family uses the BCS+ system, which provides the MSP430 with three separate clocks that can run as quickly as 16 MHz in particular conditions. The reason we have three clocks instead of just one or even two is to compromise between systems that need speed and the ability to minimize power consumption, one of the real hallmarks of the MSP430. Faster clocks consume more power, so to really reduce the power used we need slower clocks. But some functions need to respond and conclude quickly, so we also need fast clocks. You can design around the use of a single clock, but having the flexibility of three is powerful. Let's look at the three clocks available in BCS+:
- MCLK: This is the Master Clock, the one that drives the processor and times the commands in your program. This is typically a high frequency clock, but can be configured for low frequencies if needed.
- SMCLK: The Sub-Main Clock is a secondary clock that is often used by other peripherals. It can be the same frequency as MCLK or different, depending on the application.
- ACLK: The Auxilliary Clock is usually timed outside the MSP430 and is typically used for peripherals. Often, this is a low frequency clock, but can also be used at high frequencies when desired.
The 4 Sources
There are also up to four sources available in BCS+ to drive each of the three clocks:
There are also up to four sources available in BCS+ to drive each of the three clocks:
- LFXT1CLK: The name of this source implies its use with a low-frequency crystal, and this is often the case. A 32,768 Hz crystal can be connected to your MSP430 for low-power, high-accuracy timing. In some x2xx devices, this source also has a high frequency mode that can use crystals from 400 kHz to 16 MHz, assuming the chip is powered with a large enough voltage to handle the frequency. In addition, other resonators and external signals can be used for this source.
- XT2CLK: Again, this source is named for its implied use with a second crystal, but in this case only a high frequency crystal. It can also use other resonators and external signals. This source is not available on every x2xx device. (See page 5-2 of the x2xx Family User's Guide to see which devices use XT2.)
- DCOCLK: The internal source is the digitally controlled oscillator. Though not as accurate and stable as crystal sources, the DCO is still quite good and can be configured to operate at a wide range of frequencies.
- VLOCLK: The MSP430 includes a second internal oscillator for very-low power, very-low frequency applications. The VLO can run slower than the LFXT1 watch crystal, and typically is used at about 12 kHz. This source is not available in all x2xx devices. (Refer to 5-2 in the User's Guide.)
Each clock can also divide the frequency by which it's sourced by a factor of 2, 4, or 8. In addition, many peripherals can further divide their clock by the same factors, giving a large number of possible frequencies available from just one source. While MCLK and SMCLK can use any of the four sources, ACLK uses only LFXT1 or VLO. The default configuration for MCLK and SMCLK is to use the DCO at about 1.1 MHz, and for ACLK is to use LFXT1. In the coming parts for Tutorial 08, we'll look at each source and how to configure them properly. Because it's in every MSP430 device, we'll start with the DCO before taking a look at using crystals.
So the BCS+ provides us three separate clocks with 32 possible ways of sourcing them. The clocks can be divided for operation of different peripherals individually. These varied combinations provide for nearly any conditions needed for an MSP430 project. We should not neglect, however, to note that TI has gone to great effort to make the clock system very reliable; even the VLO and DCO are very well made, accurate, and stable. For precision timing, nothing can surpass well-designed crystal control, but the internal clocks do a great job, and can even change configuration in the middle of a program. Such power available without much sacrifice for quality is one of the real benefits of the MSP430 design.
Look forward to the next post, where we'll examine how we configure the DCO for different operating modes in the MSP430!
19 July 2010
Disclaimer on Changing Chips
Just a word of caution; the MSP430G2231 in my LaunchPad was seated pretty firmly. I've written my tutorial code for the G2211, and so following it exactly requires changing the chips out. If you're not careful about it, you can really mangle the pins on the G2231 when you try to pull it out. Get yourself an IC extractor, or pry at it carefully and evenly from underneath. If you do end up bending some of the pins, you should be able to bend them back into place if you're careful. If you break off a pin... well, consider yourself warned.
Anyone have some good tips on pulling out DIPs?
Anyone have some good tips on pulling out DIPs?
Tutorial 07: Pushing Buttons
We've gotten to the point now where we can program the MSP430 and make it respond by flashing an LED or two. While being able to change pins to outputs is useful, it's the combination of input and output that make the microcontroller so powerful. The pushbutton is one of the simplest types of inputs, and will be very helpful for learning more about the peripherals.
There are all kinds of switches available on the market, and there are some differences in the ways they need to be attached to the MSP430. For now we'll look at single-pole, single-throw (SPST) types, such as the momentary push-button. The LaunchPad platform includes two of these types of buttons; one is connected to P1.3 (that's the button on the lower left of the board) and the other to the RST/SBWTDIO pin (pin 16 on the DIP).
Connecting Buttons
If you are following the tutorial using the LaunchPad, then open up a copy of the LaunchPad User's Guide and turn to page 15 to see a circuit schematic of the target section of the board. You can see here that the two buttons are connected between their respective pins and ground. Note also that the same pins have 47 kΩ resistors connecting them to Vcc. To use pushbuttons in digital logic, they need to be able to provide a 1 in one state and a 0 in the other. When the button is up, the resistor ties the pins to Vcc, pulling up the voltage to whatever level the board is powered at (in the case of the LaunchPad, it's 3.6V). When you press the button, it closes the short to ground. So unpressed is logic 1, and depressed is logic 0.
You can use the opposite convention as well, reversing the positions of the button and the resistor. For obvious reasons, we call the first configuration a "pull-up resistor" and the second a "pull-down resistor". Without these resistors, the input pin would be floating, and could take on any value between ground and Vcc, which gives inconsistent behavior for your design. Whichever case makes more sense for your design, always remember to use the resistors to pull the open state up or down. A larger resistor (such as the 47 kΩ used on the LaunchPad) keeps the current draw from the button low. Ideally we only want to change the potential on the input pin and not use any power to do so.
You might recall that there are internal resistors on each of the GPIO pins for the MSP430 that can act as pull-up and pull-down resistors. The resistance value quoted for these in the MSP430 datasheets is large enough that the current draw would not be too high, but as readers have pointed out it may not be the best practice to use these for your push-buttons, especially while prototyping and testing.
Example
With the resistors in place, using buttons in an MSP430 design is quite simple. Let's illustrate them by writing a program that flashes the red LED on P1.0 a few times, then flashes the green LED on P1.6 a few times after the button is pressed. Pressing the button again should return to the red LED, and so on. For this program, we'll need to configure the two LED pins as outputs and be sure the button pin (P1.3) is configured as an input. We'll use the technique from the Blinky program to take care of the LED delay again, so we'll need a counter as well. A second counter will keep track of the number of times the LED flashes.
The new thing needed is an ability to tell the MSP430 to check the state of the button periodically; we call this polling. When the program reaches the point where it is waiting for the user to push the button, it should check and recheck the button until it sees that it has been pressed. We can do this by using a logic operation to check the value on P1IN. Since the button is attached to P1.3, bit 3 of P1IN tells us if the button is pressed (logic 0) or unpressed (logic 1). The other bits of P1IN could, in principle, be anything, so how can we extract just the value of bit 3? A simple way is to use the & operator-- since x & 0 = 0 and x & 1 = x, then P1IN & BIT3 (0b00001000) will return 0b0000x000, where x is the current value of bit 3 in P1IN. Note that the result is not either 0 or 1, but rather 0 or 0b00001000, which is also the value BIT3. Since 0 corresponds to the pressed state, we can poll P1IN in a loop that continues while (P1IN & BIT3) == BIT3, or equivalently while (P1IN & BIT3) != 0.
I've written my own version of a program that uses this in pushy_G2211.c. Try coding the program up yourself first, and then compare it to mine. A couple of new techniques used in the code are the #define command in the header, and encapsulation of a re-used command in a function call. If you're not familiar with either of these techniques, brush up on them in your favorite, reliable book on C programming. Essentially, #define lets me rename the value BIT0 to something more descriptive-- in this case, red_LED. Since this doesn't change the value of BIT0, it can still be used in the code, or you can even define two things to be BIT0, as you would if you had LEDs on P1.0 and P2.0 of a larger MSP430 device. The delay() function also makes the code more readable, and illustrates the power of encapsulation. Since a delay function is so common, I could put this into a library, and then recall it whenever I want without having to retype the same thing over and over. I encourage you to use these and any other good coding practices as much as possible to help make your code easier to understand and reuse!
This code isn't perfect, as it can't account for all situations. What happens if you press the button while an LED is flashing? Since the input value only matters during the while loop, nothing. If you have ninja reflexes and push the button in a way where the MSP430 polls it before and after the pressing, then it never sees the button press. And what happens if you just hold the button down? The solution here is to use interrupts, which is a topic beyond this tutorial. But for now, you have a rudimentary way to use buttons.
Reader Exercise 1: Copy the code into a new CCS project and try loading Pushy into your G2211. Step through the code with the debugger to be sure it works. (Change the limit on count to save clicks. Change the limit on flash too, if you're not feeling particularly patient.) Note that to get the debugger to work with the button you need to be holding it down as you step into the next line. Try watching the P1IN register as you step through to see the input value change.
Reader Exercise 2: We didn't discuss the RST button on the LaunchPad; try letting the red LED blink, then push this button instead of the button on P1.3. (You'll have to terminate the debugger to get this to work.) What does it do? While the LaunchPad is configured in a way where this is the only function this button can have, it's a very useful tool to have, especially if you ever need to restart you program!
There are all kinds of switches available on the market, and there are some differences in the ways they need to be attached to the MSP430. For now we'll look at single-pole, single-throw (SPST) types, such as the momentary push-button. The LaunchPad platform includes two of these types of buttons; one is connected to P1.3 (that's the button on the lower left of the board) and the other to the RST/SBWTDIO pin (pin 16 on the DIP).
Connecting Buttons
If you are following the tutorial using the LaunchPad, then open up a copy of the LaunchPad User's Guide and turn to page 15 to see a circuit schematic of the target section of the board. You can see here that the two buttons are connected between their respective pins and ground. Note also that the same pins have 47 kΩ resistors connecting them to Vcc. To use pushbuttons in digital logic, they need to be able to provide a 1 in one state and a 0 in the other. When the button is up, the resistor ties the pins to Vcc, pulling up the voltage to whatever level the board is powered at (in the case of the LaunchPad, it's 3.6V). When you press the button, it closes the short to ground. So unpressed is logic 1, and depressed is logic 0.
You can use the opposite convention as well, reversing the positions of the button and the resistor. For obvious reasons, we call the first configuration a "pull-up resistor" and the second a "pull-down resistor". Without these resistors, the input pin would be floating, and could take on any value between ground and Vcc, which gives inconsistent behavior for your design. Whichever case makes more sense for your design, always remember to use the resistors to pull the open state up or down. A larger resistor (such as the 47 kΩ used on the LaunchPad) keeps the current draw from the button low. Ideally we only want to change the potential on the input pin and not use any power to do so.
You might recall that there are internal resistors on each of the GPIO pins for the MSP430 that can act as pull-up and pull-down resistors. The resistance value quoted for these in the MSP430 datasheets is large enough that the current draw would not be too high, but as readers have pointed out it may not be the best practice to use these for your push-buttons, especially while prototyping and testing.
Example
With the resistors in place, using buttons in an MSP430 design is quite simple. Let's illustrate them by writing a program that flashes the red LED on P1.0 a few times, then flashes the green LED on P1.6 a few times after the button is pressed. Pressing the button again should return to the red LED, and so on. For this program, we'll need to configure the two LED pins as outputs and be sure the button pin (P1.3) is configured as an input. We'll use the technique from the Blinky program to take care of the LED delay again, so we'll need a counter as well. A second counter will keep track of the number of times the LED flashes.
The new thing needed is an ability to tell the MSP430 to check the state of the button periodically; we call this polling. When the program reaches the point where it is waiting for the user to push the button, it should check and recheck the button until it sees that it has been pressed. We can do this by using a logic operation to check the value on P1IN. Since the button is attached to P1.3, bit 3 of P1IN tells us if the button is pressed (logic 0) or unpressed (logic 1). The other bits of P1IN could, in principle, be anything, so how can we extract just the value of bit 3? A simple way is to use the & operator-- since x & 0 = 0 and x & 1 = x, then P1IN & BIT3 (0b00001000) will return 0b0000x000, where x is the current value of bit 3 in P1IN. Note that the result is not either 0 or 1, but rather 0 or 0b00001000, which is also the value BIT3. Since 0 corresponds to the pressed state, we can poll P1IN in a loop that continues while (P1IN & BIT3) == BIT3, or equivalently while (P1IN & BIT3) != 0.
I've written my own version of a program that uses this in pushy_G2211.c. Try coding the program up yourself first, and then compare it to mine. A couple of new techniques used in the code are the #define command in the header, and encapsulation of a re-used command in a function call. If you're not familiar with either of these techniques, brush up on them in your favorite, reliable book on C programming. Essentially, #define lets me rename the value BIT0 to something more descriptive-- in this case, red_LED. Since this doesn't change the value of BIT0, it can still be used in the code, or you can even define two things to be BIT0, as you would if you had LEDs on P1.0 and P2.0 of a larger MSP430 device. The delay() function also makes the code more readable, and illustrates the power of encapsulation. Since a delay function is so common, I could put this into a library, and then recall it whenever I want without having to retype the same thing over and over. I encourage you to use these and any other good coding practices as much as possible to help make your code easier to understand and reuse!
This code isn't perfect, as it can't account for all situations. What happens if you press the button while an LED is flashing? Since the input value only matters during the while loop, nothing. If you have ninja reflexes and push the button in a way where the MSP430 polls it before and after the pressing, then it never sees the button press. And what happens if you just hold the button down? The solution here is to use interrupts, which is a topic beyond this tutorial. But for now, you have a rudimentary way to use buttons.
Reader Exercise 1: Copy the code into a new CCS project and try loading Pushy into your G2211. Step through the code with the debugger to be sure it works. (Change the limit on count to save clicks. Change the limit on flash too, if you're not feeling particularly patient.) Note that to get the debugger to work with the button you need to be holding it down as you step into the next line. Try watching the P1IN register as you step through to see the input value change.
Reader Exercise 2: We didn't discuss the RST button on the LaunchPad; try letting the red LED blink, then push this button instead of the button on P1.3. (You'll have to terminate the debugger to get this to work.) What does it do? While the LaunchPad is configured in a way where this is the only function this button can have, it's a very useful tool to have, especially if you ever need to restart you program!
Question for Readers
I just received my two LaunchPads this morning; I'm excited they're finally here! One of the things I mentioned in an early post was that, with my PW28 target board, I put female headers in for the breakout section. These are my reasons for having used that convention:
- A socket can connect to a plain solid wire for quick connections to breadboards, etc.
- In rockets, the rule of thumb is if something is disconnected, the side that remains powered should not be an exposed pin to prevent an accidental short when wires are jostled around.
- Looks cleaner than the bare pins; no concern of something outside the circuit (eg. a meter) brushing up against a pair of pins and accidentally shorting them.
It seems many others use the opposite convention, such as in the Arduino case. (Reader Plazma points out that other photos of the Arduino show the female convention being used.) Ultimately, it would be nice to use the convention that is common to most users, making use of other people's designs, "shields", expansion boards and what not easy.
So what does everyone think? Which convention would be the better one to use, male or female headers on the LaunchPad? Why?
17 July 2010
Comments
For those who have put comments on, I apologize for not having moderated them promptly. The blog is now set so that anyone can post without signing in, and it will notify me when I need to moderate them. I'd like to moderate them just so I'm aware when someone says something-- I trust everyone, but I don't trust myself to go back and look. This way I get to learn from y'all!
Also, while I've posted up the initial tutorials, they may change and edit a bit more as I read through them again and find errors. Thanks for your patience! My LaunchPads should be arriving on Monday, so look forward to a little more then!
Also, while I've posted up the initial tutorials, they may change and edit a bit more as I read through them again and find errors. Thanks for your patience! My LaunchPads should be arriving on Monday, so look forward to a little more then!
Tutorial 06: Getting the Bugs Out
The debugging features of the MSP430 are one of the most helpful tools you'll have in developing your projects. Let's take a look at how to use some of the basic features here. Load up your Blinky program and start the debugger, but this time don't push the 'Run' button, just leave it in a hold state. Your screen should look something like the image here. Note a few things to start. There are six windows opened here by default. The one on the far right, the 'Cheat Sheets', gives tips and help if you need it. You can also just close this window. (If you really get annoyed with it, just choose Disable All Cheatsheets on that window.)
The five remaining windows are Debug, Variables (labeled Local in this screenshot), the code, Dissasembly, and a Console. The console, again, shows results and errors that come from compiling, loading, and in some cases the code itself. The code window should be self-explaning, but note that the void main(void) { line is highlighted and has an arrow next to it. This shows where in the code the debugger is sitting. When you first load code into the flash memory of the chip, it turns on and holds everything right at the start. The variables window shows current values of code variables and (we'll see in a little while) of registers in the MSP430. The Debug window shows where we are in the hierarchy of the project itself. (Ours is simple, only one source file, so this window isn't as helpful right now.)
Note the collection of icons in the Debug window. You can see the 'Run' button there. The other important ones for this tutorial follow the 'Run' button. There's 'Halt' (looks like a pause button, should be grayed out when the debugger holds, lights up while 'Run' grays out when the chip is running), then 'Terminate All'. These control the debugger, like a play, pause, and start button. Next come a series of arrows, the first of which is 'Step Into'. We'll use that button today. A little farther, there's an icon that looks like a chip with two cycling arrows. This button resets the CPU in the MSP430 and sends the debugger back to the beginning.
Example
Before we start debugging our code, let's change the number of loops in our delay to 6. You'll see why in a bit. Scroll through the code in the code window until you find the right line, and change the count to end at 6 rather than 60000. Up at the top of the CCS window, you'll see icons similar to what we had in the compiler environment. Next to the 'Build Active Project' icon, there's a 'Rebuild Active Project' icon. After you make simple changes in the code here, click that button to recompile and reload the updated code to the MSP430. (If you need to make significant changes to the code, it's easier to terminate the debugger and work in the compiler environment.) Go ahead and tell CCS to reload the code into your MSP430, and the debugger will start over again.
Now we'll use the 'Step Into' button of the debugger to step through the code line by line. One click of the button, and you should see the arrow move down two lines, to WDTCTL. You may have noticed that the count variable already appeared in the Local Variables window; CCS loads that information automatically before debugging. The value of count is probably just some random value that we won't be using. We'll get back to that window soon.
Before we 'Step Into' the WDTCTL line, let's open up another useful window. Go to View → Registers, and you'll see another variable window pop up with all the registers in your device. (This feature is so useful for learning from! We'll make extensive use of this as we learn about the MSP430 peripherals, so remember how to do this part.) To the bottom of the list, you'll find Watchdog_Timer. Open up this section, and you'll find the WDTCTL register. The debugger is showing that the register currently has the hex value 0x6900. Opening the WDTCTL register shows the individual bits. Note that all of them are set to 0 when you power up the MSP430. This setting uses the watchdog timer normally, and running like this would reset the CPU periodically. Now step into the next line of our code and see what happens.
Stepping into the next line, you see the WDTHOLD turns to 1 (and turns red, signifying something changed in this clock cycle) and the value of WDTCTL is now 0x6980. You may recall that setting the WDT requires a password of 0x5a. When you read the password byte of WDTCTL, however, it returns 0x69.
(Want to force a reset in your code? Try writing WDTCTL = WDTCTL. Reading WDTCTL returns a value that is not the right password and you give the incorrect key to be able to write to the register; the MSP430 resets if this happens.)
See if you can find the P1 registers and then step into the next two lines to see what happens there. The debugger should now be on the LED toggle line in the infinite loop. Before we go further, change the variable window back to the local variables. Note that count still has some random value in it. Now, stepping into the LED toggle line, we should change P1OUT to light up the LED! We are now at the for loop for the delay. Step once into this; the debugger goes right back to the same line, but note the change in the value of count in the variable window. Count increments by 1 each time you press 'Step Into'. When it reaches count==6, the debugger moves on to the next line. One more step brings you back to the LED toggle. (Glad I had you change the delay to 6 instead of 60000?) You can then step through the code to turn off the LED, delay again, then repeat as much as you wish. At any time you can hit 'Run' and set the MSP430 off on its own. If you want to show someone that your LaunchPad is working, don't forget to increase the value in the delay loop. The MSP430 is fast enough that your eye won't pick up the frequency with counting up to 6. =)
The debugger is a very useful tool, though keep in mind it won't always work for what we want it to do. The MSP430 is designed to interface with the outside world. While the debugger can pause the clock inside the MSP430, it can't pause the clock in our world. Later on we'll look at what to do when you're debugging code that relies on outside timings. But I hope you can see just how helpful the debugger can be in your project. If you know of or discover any other features of the CCS debugger that you find very helpful, send a comment and let us know!
This post concludes the initial collection of tutorials on the MSP430. You now have enough knowledge to be able to write a program, download the code into an MSP430, and create some basic projects. Good luck on your next project, and join in our growing community to let people know what you're able to do and learn with the MSP430! Come back often as I'll be posting new tutorials on the peripherals of the MSP430 soon.
Reader Exercise: Try out the code you wrote in Tutorial 04. Does it behave how you expected? Use the debugger to step through it (change any delay loops to something manageable) and be sure everything runs as it should.
The five remaining windows are Debug, Variables (labeled Local in this screenshot), the code, Dissasembly, and a Console. The console, again, shows results and errors that come from compiling, loading, and in some cases the code itself. The code window should be self-explaning, but note that the void main(void) { line is highlighted and has an arrow next to it. This shows where in the code the debugger is sitting. When you first load code into the flash memory of the chip, it turns on and holds everything right at the start. The variables window shows current values of code variables and (we'll see in a little while) of registers in the MSP430. The Debug window shows where we are in the hierarchy of the project itself. (Ours is simple, only one source file, so this window isn't as helpful right now.)
Note the collection of icons in the Debug window. You can see the 'Run' button there. The other important ones for this tutorial follow the 'Run' button. There's 'Halt' (looks like a pause button, should be grayed out when the debugger holds, lights up while 'Run' grays out when the chip is running), then 'Terminate All'. These control the debugger, like a play, pause, and start button. Next come a series of arrows, the first of which is 'Step Into'. We'll use that button today. A little farther, there's an icon that looks like a chip with two cycling arrows. This button resets the CPU in the MSP430 and sends the debugger back to the beginning.
Example
Before we start debugging our code, let's change the number of loops in our delay to 6. You'll see why in a bit. Scroll through the code in the code window until you find the right line, and change the count to end at 6 rather than 60000. Up at the top of the CCS window, you'll see icons similar to what we had in the compiler environment. Next to the 'Build Active Project' icon, there's a 'Rebuild Active Project' icon. After you make simple changes in the code here, click that button to recompile and reload the updated code to the MSP430. (If you need to make significant changes to the code, it's easier to terminate the debugger and work in the compiler environment.) Go ahead and tell CCS to reload the code into your MSP430, and the debugger will start over again.
Now we'll use the 'Step Into' button of the debugger to step through the code line by line. One click of the button, and you should see the arrow move down two lines, to WDTCTL. You may have noticed that the count variable already appeared in the Local Variables window; CCS loads that information automatically before debugging. The value of count is probably just some random value that we won't be using. We'll get back to that window soon.
Before we 'Step Into' the WDTCTL line, let's open up another useful window. Go to View → Registers, and you'll see another variable window pop up with all the registers in your device. (This feature is so useful for learning from! We'll make extensive use of this as we learn about the MSP430 peripherals, so remember how to do this part.) To the bottom of the list, you'll find Watchdog_Timer. Open up this section, and you'll find the WDTCTL register. The debugger is showing that the register currently has the hex value 0x6900. Opening the WDTCTL register shows the individual bits. Note that all of them are set to 0 when you power up the MSP430. This setting uses the watchdog timer normally, and running like this would reset the CPU periodically. Now step into the next line of our code and see what happens.
Stepping into the next line, you see the WDTHOLD turns to 1 (and turns red, signifying something changed in this clock cycle) and the value of WDTCTL is now 0x6980. You may recall that setting the WDT requires a password of 0x5a. When you read the password byte of WDTCTL, however, it returns 0x69.
(Want to force a reset in your code? Try writing WDTCTL = WDTCTL. Reading WDTCTL returns a value that is not the right password and you give the incorrect key to be able to write to the register; the MSP430 resets if this happens.)
See if you can find the P1 registers and then step into the next two lines to see what happens there. The debugger should now be on the LED toggle line in the infinite loop. Before we go further, change the variable window back to the local variables. Note that count still has some random value in it. Now, stepping into the LED toggle line, we should change P1OUT to light up the LED! We are now at the for loop for the delay. Step once into this; the debugger goes right back to the same line, but note the change in the value of count in the variable window. Count increments by 1 each time you press 'Step Into'. When it reaches count==6, the debugger moves on to the next line. One more step brings you back to the LED toggle. (Glad I had you change the delay to 6 instead of 60000?) You can then step through the code to turn off the LED, delay again, then repeat as much as you wish. At any time you can hit 'Run' and set the MSP430 off on its own. If you want to show someone that your LaunchPad is working, don't forget to increase the value in the delay loop. The MSP430 is fast enough that your eye won't pick up the frequency with counting up to 6. =)
The debugger is a very useful tool, though keep in mind it won't always work for what we want it to do. The MSP430 is designed to interface with the outside world. While the debugger can pause the clock inside the MSP430, it can't pause the clock in our world. Later on we'll look at what to do when you're debugging code that relies on outside timings. But I hope you can see just how helpful the debugger can be in your project. If you know of or discover any other features of the CCS debugger that you find very helpful, send a comment and let us know!
This post concludes the initial collection of tutorials on the MSP430. You now have enough knowledge to be able to write a program, download the code into an MSP430, and create some basic projects. Good luck on your next project, and join in our growing community to let people know what you're able to do and learn with the MSP430! Come back often as I'll be posting new tutorials on the peripherals of the MSP430 soon.
Reader Exercise: Try out the code you wrote in Tutorial 04. Does it behave how you expected? Use the debugger to step through it (change any delay loops to something manageable) and be sure everything runs as it should.
Tutorial 05: Loading the Program
Note: I just received word that my LaunchPad has been shipped, and so I should have it soon. I figured it'd be good to make some forward progress anyway, so I'm going to go ahead and do this post using my 28-pin TSSOP target board with the F2132, but talk in terms of the G2211 and the LaunchPad. I'll change any discrepancies as soon as I have a LaunchPad with which to program and take pictures.
This post will describe a little of what you need to use TI's Code Composer Studio. This programming environment, or Interactive Development Environment (IDE) is based on the open-source project Eclipse. Eclipse is a great editing environment, and you should find it fairly easy to use for programming your MSP430. The TI LaunchPad wiki has a link from which you can download the software; it does require registration with TI, but with your account you are also able to request free samples of other products (including MSP430's) to try out. CCS can be used free of charge, but limits you to 16 kb of code. While that may not sound like much, keep in mind the MSP430's that come with the LaunchPad have no more than 2 kb of programming space! Code used to program the MSP430 turns out to be very efficient and dense, and won't take up much space. We'll be able to see how much space our code takes up when we start using the debugger included with CCS.
Once you've installed CCS, start it up and it will ask for a workspace. The workspace is just the directory where you will keep your projects; you can always change it later if you need to with the 'Change Workspace' option in the file menu. For now, use something simple, like ~/My Documents/MSP430 LaunchPad. Once that's done, you should have a welcome screen come up, that looks like this image. You can enter the IDE itself by clicking on the cube in the upper right corner; but first, take note of the Getting Started icon. Clicking on this will bring you to a few links with lots of helpful information on how to use CCS. I would recommend looking through these before getting started, especially if you've never used an IDE before.
Assuming you've now done that, or are comfortable already with this type of interface, close the welcome screen (you can come back to it with the 'Welcome' option in the help menu) and bring up the interactive editor. There's not too much here at first, so let's go ahead and start a new project. Select File → New → CCS Project, and name your project something descriptive. I like to give the program a name, and include a suffix to specify which MSP430 the program is targeting. For blinky, I name the project something like blinky_G2211. Click Next, and make sure that the Project Type is selected as MSP430 (should be the only option if you installed the CCS version with only MSP430 support.) Click Next. There's nothing to do on the next page for now, so click Next again. On the final screen, we need to choose the device we're programming. Make sure the Output Type is selected as Executable, and then choose the MSP430G2XXX in the filter for the Device Variant. The filter allows you to select subfamilies of the MSP430 to reduce the number of devices you have to sort through to find yours. Once you've filtered the results, choose MSP430G2211 for the Device Variant. For now, the other options should be fine with their default settings. A quick word before continuing; be sure you choose the correct device variant here; different linkers are needed for different MSP430 devices, so be sure to choose the one that matches your target device.
Click next one last time, and you should see your new project come up in the left-most window. The project creates a sub-directory in your workspace that holds all the files and information needed for downloading the code into your chip. But first, we need to make some code to download. Go to File → New → Source File, and enter a name for the source file that ends with .c; something descriptive is helpful, but for larger projects with multiple source files, something like main.c is a good choice. Note that CCS will give you a warning until your filename has a .c extension on it. Go ahead and click Finish, and a new window opens up in which you can type your code. Go ahead and fill in your code for blinky, and be sure to give it some good comments to explain how it works. Make sure you have one blank line at the end. CCS defaults to issuing a warning if there is any text on the last line of the code. If someone knows how to change this behavior, let me know. Otherwise, just live with the quirk.
Note that I've changed the size of my windows. I like to have my editor show 80 columns (a standard for terminal windows) so that I can avoid overly-long lines of code if possible. Feel free to adjust the window sizes to whatever is useful to you. Ok, we have code, now we need to compile it. Technically we don't have to compile before loading it into our MSP430, but I think it's a good idea to get all compile-time bugs sorted out first. The 'Build Active Project' button to the right of the print button will compile your code for you. Alternatively, you can select Project → Build Active Project. If you didn't make any typographical errors, your code should compile without any errors. The compiler brings up two new windows at the bottom: a Console showing the compiler commands and results, and a Problems list that would show any compiler errors or warnings. The code given in the previous post should compile error-free.
Alright, now that we're confident our code should work, let's load it into the MSP430! Plug your LaunchPad into your USB port. If you've installed the drivers correctly, then click the Debug button (looks like a little beetle) or alternatively select Target → Debug Active Project. The debugger will change the windows, make sure your code has been compiled since any changes were made, then check to be sure your MSP430 is connected. If your chip isn't powered properly, it won't detect the device at all. If everything is powered and installed right, it should just load the code and give you the debugging environment windows. Note that at the bottom window, it shows you the size of the code loaded into the MSP430. Blinky (as I wrote it) shows Text: 86 bytes Data: 2 bytes. Blinky is by no means a complicated program, but as you can see the size of our programs won't be very high. the 2 kb that comes with each of your G2211 and G2231 is more than enough for what you are able to do with those chips.
If you were expecting right away to see your LED blinking away merrily, you'll be disappointed. The debugger actually holds the chip in a state just after a Power Up Reset (abbreviated PUC). In the middle window, you should see your code with the line at void main(void) { highlighted. This window shows the position in the code the chip is currently looking. We'll look at using this feature to our advantage shortly, but for now just click the green 'Run' arrow at the left side of the debug window. This turns off the debugging control of the clock, and lets the MSP430 run normally. The LED should be blinking about once a second or so. If, however, you run your program and the LED stays on, check to make sure you fixed the problem in my original code; if you declare int count; you won't ever count up to 60,000. You should be declaring unisgned int count; in your code instead.
If after all of this you see your LED blinking, then congratulations, you've just finished your first MSP430 project! Otherwise, move on to the next tutorial anyway. If you can't get your code to work, then the debugger may be able to show where the error is occurring. To leave the debugger, click the 'Terminate All' icon near the 'Run' icon.
This post will describe a little of what you need to use TI's Code Composer Studio. This programming environment, or Interactive Development Environment (IDE) is based on the open-source project Eclipse. Eclipse is a great editing environment, and you should find it fairly easy to use for programming your MSP430. The TI LaunchPad wiki has a link from which you can download the software; it does require registration with TI, but with your account you are also able to request free samples of other products (including MSP430's) to try out. CCS can be used free of charge, but limits you to 16 kb of code. While that may not sound like much, keep in mind the MSP430's that come with the LaunchPad have no more than 2 kb of programming space! Code used to program the MSP430 turns out to be very efficient and dense, and won't take up much space. We'll be able to see how much space our code takes up when we start using the debugger included with CCS.
Once you've installed CCS, start it up and it will ask for a workspace. The workspace is just the directory where you will keep your projects; you can always change it later if you need to with the 'Change Workspace' option in the file menu. For now, use something simple, like ~/My Documents/MSP430 LaunchPad. Once that's done, you should have a welcome screen come up, that looks like this image. You can enter the IDE itself by clicking on the cube in the upper right corner; but first, take note of the Getting Started icon. Clicking on this will bring you to a few links with lots of helpful information on how to use CCS. I would recommend looking through these before getting started, especially if you've never used an IDE before.
Assuming you've now done that, or are comfortable already with this type of interface, close the welcome screen (you can come back to it with the 'Welcome' option in the help menu) and bring up the interactive editor. There's not too much here at first, so let's go ahead and start a new project. Select File → New → CCS Project, and name your project something descriptive. I like to give the program a name, and include a suffix to specify which MSP430 the program is targeting. For blinky, I name the project something like blinky_G2211. Click Next, and make sure that the Project Type is selected as MSP430 (should be the only option if you installed the CCS version with only MSP430 support.) Click Next. There's nothing to do on the next page for now, so click Next again. On the final screen, we need to choose the device we're programming. Make sure the Output Type is selected as Executable, and then choose the MSP430G2XXX in the filter for the Device Variant. The filter allows you to select subfamilies of the MSP430 to reduce the number of devices you have to sort through to find yours. Once you've filtered the results, choose MSP430G2211 for the Device Variant. For now, the other options should be fine with their default settings. A quick word before continuing; be sure you choose the correct device variant here; different linkers are needed for different MSP430 devices, so be sure to choose the one that matches your target device.
Click next one last time, and you should see your new project come up in the left-most window. The project creates a sub-directory in your workspace that holds all the files and information needed for downloading the code into your chip. But first, we need to make some code to download. Go to File → New → Source File, and enter a name for the source file that ends with .c; something descriptive is helpful, but for larger projects with multiple source files, something like main.c is a good choice. Note that CCS will give you a warning until your filename has a .c extension on it. Go ahead and click Finish, and a new window opens up in which you can type your code. Go ahead and fill in your code for blinky, and be sure to give it some good comments to explain how it works. Make sure you have one blank line at the end. CCS defaults to issuing a warning if there is any text on the last line of the code. If someone knows how to change this behavior, let me know. Otherwise, just live with the quirk.
Note that I've changed the size of my windows. I like to have my editor show 80 columns (a standard for terminal windows) so that I can avoid overly-long lines of code if possible. Feel free to adjust the window sizes to whatever is useful to you. Ok, we have code, now we need to compile it. Technically we don't have to compile before loading it into our MSP430, but I think it's a good idea to get all compile-time bugs sorted out first. The 'Build Active Project' button to the right of the print button will compile your code for you. Alternatively, you can select Project → Build Active Project. If you didn't make any typographical errors, your code should compile without any errors. The compiler brings up two new windows at the bottom: a Console showing the compiler commands and results, and a Problems list that would show any compiler errors or warnings. The code given in the previous post should compile error-free.
Alright, now that we're confident our code should work, let's load it into the MSP430! Plug your LaunchPad into your USB port. If you've installed the drivers correctly, then click the Debug button (looks like a little beetle) or alternatively select Target → Debug Active Project. The debugger will change the windows, make sure your code has been compiled since any changes were made, then check to be sure your MSP430 is connected. If your chip isn't powered properly, it won't detect the device at all. If everything is powered and installed right, it should just load the code and give you the debugging environment windows. Note that at the bottom window, it shows you the size of the code loaded into the MSP430. Blinky (as I wrote it) shows Text: 86 bytes Data: 2 bytes. Blinky is by no means a complicated program, but as you can see the size of our programs won't be very high. the 2 kb that comes with each of your G2211 and G2231 is more than enough for what you are able to do with those chips.
If you were expecting right away to see your LED blinking away merrily, you'll be disappointed. The debugger actually holds the chip in a state just after a Power Up Reset (abbreviated PUC). In the middle window, you should see your code with the line at void main(void) { highlighted. This window shows the position in the code the chip is currently looking. We'll look at using this feature to our advantage shortly, but for now just click the green 'Run' arrow at the left side of the debug window. This turns off the debugging control of the clock, and lets the MSP430 run normally. The LED should be blinking about once a second or so. If, however, you run your program and the LED stays on, check to make sure you fixed the problem in my original code; if you declare int count; you won't ever count up to 60,000. You should be declaring unisgned int count; in your code instead.
If after all of this you see your LED blinking, then congratulations, you've just finished your first MSP430 project! Otherwise, move on to the next tutorial anyway. If you can't get your code to work, then the debugger may be able to show where the error is occurring. To leave the debugger, click the 'Terminate All' icon near the 'Run' icon.
13 July 2010
Tutorial 04: Stuck in a Loop
We now have enough to be able to write programs for the MSP430, so before we go into the peripherals that make the microcontroller useful, let's get started programming and debugging. We'll start using the MSP430G2211 that comes with the LaunchPad. If you're not using LaunchPad, it's easy to change this first program for whatever device you're using. All it needs is an LED connected to one of the GPIO (General Purpose I/O) pins. (Connect it with a resistor to prevent too much current draw out of the MSP. A couple hundred ohms should be sufficient.)
In the previous tutorial, we mentioned the useful BITx definitions in the device-specific header file. These were at one time variation specific (eg. msp430x2x01 as opposed to msp430g2001), but with the most recent version of Code Composer Studio, TI appears to be moving to device specific header files. Whenever you write software for your MSP device, be sure to include the appropriate header file. For this tutorial, if you're not using a LaunchPad or the G2211, change the header file to whatever device you're using.
So the start of any MSP430 program will have a line similar to this:
#include <msp430g2211.h>
For simple programs, this is often all that is needed before coding the main function, and that is certainly the case for the "Hello, world!" program of microcontrollers, blinky. Blinky is a simple program that toggles an LED at a given period. It's best to use timers, interrupts, and such to do this type of function, but you'll have to wait until we look at those types of peripherals and functions before we can do that. The simplest way to get the program to work is with some type of delay loop. The LaunchPad has a green LED connected to P1.0 and a red LED connected to P1.6. We'll use the green LED for now. Let's get started!
The beginning of our code looks like this:
#include <msp430g2211.h>
void main(void) {
} // main
Unfortunately, we do need one step that we can't explain completely yet before we do anything else. The MSP430 includes a special timer called the Watchdog Timer (WDT). Its function is to reset the CPU if it gets stuck (ie. the watchdog timer runs out). This timer is on by default when the chip powers up. Though we could use this timer to give us our delay, for now we don't want our program to reset on us, so we need to first turn this timer off. (We'll look at using the WDT later.)
The WDT has a 16 bit register called WDTCTL, but only the first 8 bits have any control. The upper byte is used as a security measure; to prevent your code from accidentally changing the WDT, you must provide a password. The password turns out to be 0x5a (in the upper byte, so actually 0x5a00), but the header file helps you out by defining that value as the much easier to remember WDTPW. Add this value to the 1-byte configuration value you want to assign to WDTCTL. To turn off the WDT, we can use the header-defined value WDTHOLD:
WDTCTL = WDTPW + WDTHOLD;
You'll get into the habit of starting all of your first programs with this line, but keep in mind the WDT has a lot of useful functions. We'll discuss those when we talk about the WDT in depth.
Ok, now that we've disabled the watchdog, we can continue writing the code. We want to light an LED on P1.0, so we can use the last tutorial to set that up:
P1OUT = 0;
P1DIR = BIT0;
Now we want to toggle the LED and delay for some given amount of time. I'm using a for loop, though a while or do-while loop would be just as effective. We'll need a counter for the loop, so remember to define it at the start of the code:
#include <msp430g2211.h>
void main(void) {
unsigned int count;
WDTCTL = WDTPW + WDTHOLD;
P1OUT = 0;
P1DIR = BIT0;
P1OUT |= BIT0;
for (count = 0; count < 60000; count++);
P1OUT &= ~BIT0;
for (count = 0; count < 60000; count++);
} // main
What happens when we get to the end of the code? In a computer, it would just exit. In a microcontroller, however, it would just move on to the next address to read its next "instruction". There could be just about anything in there, from random noise to leftover code from older (larger) programs. In any case, it would just continue stepping merrily through the address space until it gets to the end and then... well, I don't know what happens. It's not what is intended to happen in any case, so we need to prevent the processor from ever moving beyond the actual code. We'll do this now by putting the code into an infinite loop. That's usually a bad idea in computer code, but essential here.
Again, you could easily do the same thing with a while(1) loop or something similar instead.
So there's blinky. The light turns on, it waits, turns off the light, waits again, then goes back to the beginning to do it all over ad nauseum.
Note there's a cleaner way to accomplish this task:
#include <msp430g2211.h>
Reader Exercise: Write a program like blinky that alternates the green and red LEDs on the LaunchPad (the red LED is on P1.6). Then modify the program so that it alternates flashing the green LED, then the red LED, with short pulses and a delay between the individual flashes.
In the previous tutorial, we mentioned the useful BITx definitions in the device-specific header file. These were at one time variation specific (eg. msp430x2x01 as opposed to msp430g2001), but with the most recent version of Code Composer Studio, TI appears to be moving to device specific header files. Whenever you write software for your MSP device, be sure to include the appropriate header file. For this tutorial, if you're not using a LaunchPad or the G2211, change the header file to whatever device you're using.
So the start of any MSP430 program will have a line similar to this:
#include <msp430g2211.h>
For simple programs, this is often all that is needed before coding the main function, and that is certainly the case for the "Hello, world!" program of microcontrollers, blinky. Blinky is a simple program that toggles an LED at a given period. It's best to use timers, interrupts, and such to do this type of function, but you'll have to wait until we look at those types of peripherals and functions before we can do that. The simplest way to get the program to work is with some type of delay loop. The LaunchPad has a green LED connected to P1.0 and a red LED connected to P1.6. We'll use the green LED for now. Let's get started!
The beginning of our code looks like this:
#include <msp430g2211.h>
void main(void) {
} // main
Unfortunately, we do need one step that we can't explain completely yet before we do anything else. The MSP430 includes a special timer called the Watchdog Timer (WDT). Its function is to reset the CPU if it gets stuck (ie. the watchdog timer runs out). This timer is on by default when the chip powers up. Though we could use this timer to give us our delay, for now we don't want our program to reset on us, so we need to first turn this timer off. (We'll look at using the WDT later.)
The WDT has a 16 bit register called WDTCTL, but only the first 8 bits have any control. The upper byte is used as a security measure; to prevent your code from accidentally changing the WDT, you must provide a password. The password turns out to be 0x5a (in the upper byte, so actually 0x5a00), but the header file helps you out by defining that value as the much easier to remember WDTPW. Add this value to the 1-byte configuration value you want to assign to WDTCTL. To turn off the WDT, we can use the header-defined value WDTHOLD:
WDTCTL = WDTPW + WDTHOLD;
You'll get into the habit of starting all of your first programs with this line, but keep in mind the WDT has a lot of useful functions. We'll discuss those when we talk about the WDT in depth.
Ok, now that we've disabled the watchdog, we can continue writing the code. We want to light an LED on P1.0, so we can use the last tutorial to set that up:
P1OUT = 0;
P1DIR = BIT0;
Now we want to toggle the LED and delay for some given amount of time. I'm using a for loop, though a while or do-while loop would be just as effective. We'll need a counter for the loop, so remember to define it at the start of the code:
#include <msp430g2211.h>
void main(void) {
unsigned int count;
WDTCTL = WDTPW + WDTHOLD;
P1OUT = 0;
P1DIR = BIT0;
P1OUT |= BIT0;
for (count = 0; count < 60000; count++);
P1OUT &= ~BIT0;
for (count = 0; count < 60000; count++);
} // main
What happens when we get to the end of the code? In a computer, it would just exit. In a microcontroller, however, it would just move on to the next address to read its next "instruction". There could be just about anything in there, from random noise to leftover code from older (larger) programs. In any case, it would just continue stepping merrily through the address space until it gets to the end and then... well, I don't know what happens. It's not what is intended to happen in any case, so we need to prevent the processor from ever moving beyond the actual code. We'll do this now by putting the code into an infinite loop. That's usually a bad idea in computer code, but essential here.
#include <msp430g2211.h>
void main(void) {
unsigned int count;
WDTCTL = WDTPW + WDTHOLD;
P1OUT = 0;
P1DIR = BIT0;
P1OUT = 0;
P1DIR = BIT0;
for (;;) {
P1OUT |= BIT0;
for (count = 0; count < 60000; count++);
P1OUT &= ~BIT0;
for (count = 0; count < 60000; count++);
}
} // main
Again, you could easily do the same thing with a while(1) loop or something similar instead.
So there's blinky. The light turns on, it waits, turns off the light, waits again, then goes back to the beginning to do it all over ad nauseum.
Note there's a cleaner way to accomplish this task:
#include <msp430g2211.h>
void main(void) {
unsigned int count; // loop counter
WDTCTL = WDTPW + WDTHOLD; // disable watchdog
P1OUT = 0; // initialize LED off
P1DIR = BIT0; // P1.0 output
P1OUT = 0; // initialize LED off
P1DIR = BIT0; // P1.0 output
for (;;) {
P1OUT ^= BIT0; // toggle LED on P1.0
for (count = 0; count < 60000; count++); //delay
}
} // main
Now you only have to change one loop length to adjust the frequency of the blink. (Though if you want to play with different duty cycles, the first method works well.) I've also added some comments to the code. Programming teachers seem to always stress the importance of good commenting habits; it'll save your hairline in microcontrollers. Comments don't add to the code size at all, so be sure to document everything you do well.
Next time we'll put this into our G2211 and learn how to use CCS to load programs onto the LaunchPad.
Reader Exercise: Write a program like blinky that alternates the green and red LEDs on the LaunchPad (the red LED is on P1.6). Then modify the program so that it alternates flashing the green LED, then the red LED, with short pulses and a delay between the individual flashes.
Disclaimer: I don't have my LaunchPad yet, so I haven't technically tested this code. After doing similar programs for three or four other MSP430's, I'm confident it works, but until I can get a video posted of my LaunchPad blinking its LED with this code, I reserve the right to have made mistakes. =)
Disclaimer 2: When I first typed up this post, I declared the count variable as just int count;. In the MSP430 compiler, a 16-bit plain int cannot count up as high as 60,000; it reaches its highest value then wraps around to a negative value. Using a plain int for this code will never leave the delay loop. An unsigned int, rather, is non-negative. Using an unsigned int allows us to count up higher. Longer delays may require an unsigned long. An alternative would be to use a hex notation; 0xFFFF is the highest value an int can count to. In plain int decimal, this corresponds to 32,767. In unsigned int decimal, it's 65,535.
Disclaimer 2: When I first typed up this post, I declared the count variable as just int count;. In the MSP430 compiler, a 16-bit plain int cannot count up as high as 60,000; it reaches its highest value then wraps around to a negative value. Using a plain int for this code will never leave the delay loop. An unsigned int, rather, is non-negative. Using an unsigned int allows us to count up higher. Longer delays may require an unsigned long. An alternative would be to use a hex notation; 0xFFFF is the highest value an int can count to. In plain int decimal, this corresponds to 32,767. In unsigned int decimal, it's 65,535.
12 July 2010
Tutorial 03: Flipping Bits
Now that we have access to the registers, how do we actually flip the switches (change the bits)? We'll examine the ways to do this using the following example: we'll use a G2001 with an LED connected from P1.4 to ground. If P1.4 is at 0 V, nothing happens, but if P1.4 is at Vcc, the LED will turn on. Since we've connected to P1.4, we should be able to control it by fiddling with bit 4 in the P1 registers. (Keep in mind that we're not changing the 4th bit, at least not in the way we normally think of it. The 1st bit is bit 0, so bit 4 is technically the 5th bit, but who's counting?)
Before we look at setting bit values, we should take a look at the ways we can represent the values in 8-bit registers. We could always use regular decimal notation, but unfortunately it has little advantage to counter the confusion caused by having to use 8-bit numbers in a non-multiple base (the decimal base is, of course, 10).
The clearest way to represent the value is in binary notation, or base 2. The register has 8 digits, each is a 0 or 1, corresponding to the value in each bit. To make a binary 2 clear from a decimal 10, we can preface the number with the notation 0b (first character is a zero), such as 0b10.
Another common notation used is hexadecimal (base 16). This notation is convenient because each 8-bit value is represented by exactly two digits, each a value from 0-9 or a-f. The preface for hexadecimal is 0x, so the number 2 in hex is 0x02. The number 12 would be 0x0c, since the digits a-f correspond to the numbers 10-15. 16-bit numbers are represented with 4 digits, such as 0x14da. Many values in the MSP430 are 16-bit, so hexadecimal is very convenient here. (I apologize for the change in notation from the previous tutorial; in the TI documentation they use the notation 14DAh for hex values, but here we're using 0x14da instead. The 0x notation is used in the programming, and I will stick to that notation unless I'm citing from a TI document directly that uses the h notation.)
We could also use an octal notation (base 8), with the preface 0o. I've not seen this in practice, however.
We'll start using some actual code in this post, so I want to establish a convention. Anything written in the Courier font is a code snippet or example. The coloring in the code matches the color scheme I usually see when I look at a .c file in a text editor, and for now doesn't make a difference. You may have other color schemes that you see. I'll try to use the colors that are used in CCS as best I can.
Binary notation is obviously the one that makes it clear what bits we're using and what they're set to. Unfortunately, it also takes lots of characters to write them out. When we write C programs for the MSP430, we can include a header file with information and shortcuts specific to the device we're using (such as #include <msp430g2001.h>). These header files include some shortcut names for the binary values where each digit is 0 except for a specific bit; the header file allows us to use the name BIT2 to represent 0b00000100. There is a BIT0 through BIT7 included in each header file, which makes for a nice shortcut and less typing. In the discussion below, however, I'll try to keep it to the full 8 digit binary values to make it clear what is happening in the operations described. Now, on to the fiddling!
For our LED example, we'll need to first make P1.4 an output so that we can control the voltage above the LED. We do this by changing bit 4 in P1DIR to 1, for output mode.
1. Direct Assignment
If we know exactly what the binary (or hex, or even decimal) value corresponding to the configuration we need is, we can just set it directly: P1DIR = 0b00010000; would set all of the bits in P1DIR to 0 except bit 4. This method works pretty well for initializing the processor, but later in the program can be problematic when we might not know for certain what state bits we don't want to change are in. Turning off the bit is easy, just set it to the value with bit 4 set at 0: P1DIR = 0b00000000, or just as easily for this particular case, P1DIR = 0. (Using the BITx notation, we would write P1DIR = BIT4.)
2. Addition and Subtraction
If we don't know exactly the value needed for the configuration, or if we're just trying to turn on one bit, we could just add the bit's value to P1DIR (I'm using the colon character : to represent unknown digit values): 0b:::0:::: + 0b:::1:::: = 0b:::1::::, so we could turn on bit 4 by doing P1DIR += 0b00010000. *(Confused by the +=? See the footnote below!) The problem with this method is if we accidentally turn it on twice: 0b:::1:::: + 0b00010000 is going to cause a carry over into the next bits, changing I/O directions where we don't want to! This method should be used with caution. Note that the equivalent to turn the bit off would be to subtract the value, of course. (BITx notation: P1DIR += BIT4 or P1DIR -= BIT4.)
3. Logic Operators & and |
To avoid the problems with addition and subtraction, we can use logic operations. Let's say we have a bit with the value x. (x could be 0 or 1, we'll just look at this generally.) The operations and (&) and or (|) can be used to change the value of the bit to be specifically 1 or 0. Note that x & 0 = 0 no matter what value x is. Similarly, x | 1 = 1 regardless of the value of x. Also, x & 1 = x and x | 0 = x, so the value of x is unchanged. for these operations. So what would be the result of the operation P1DIR | 0b00010000? Bits 0-3 and 5-7 would be unchanged (remember, | 0 doesn't change the value) while bit 4 is set to 1. (It may have been 1 before, but is definitely 1 after the operation!) On the other hand, P1DIR &= 0b11101111 would have the effect of setting bit 4 to zero and leaving the others unchanged. Note that 0b11101111 is the not operation (~) applied to the original 0b00010000, so we could write this as P1DIR &= ~0b00010000. (In BITx notation: P1DIR |= BIT4 turns bit 4 on, and P1DIR &= ~BIT4 turns it off.)
Reader Exercise: Sometimes you'll see example code that uses the notation a + b; and sometimes a | b; to do the same thing. Convince yourself that these are equivalent in particular circumstances; when would you not want to use one or the other?
4. Toggling with ^
Ok, I said there were three choices, and there really are only three. This fourth option is similar to the third choice, but is an effective way if we just want to toggle the value, not set it to be specifically 0 or 1. The exclusive or operator (^) has this effect: x^0 = 1 if x is 1, and 0 if x is 0. x^1 = 1 if x is 0, and 0 if x is 1. So x^0 leaves the bit unchanged, and x^1 changes the value of x to its opposite. P1DIR ^= 0b00010000 flips bit 4 (to 1 if it was 0, to 0 if it was 1) just like toggling a switch. (In BITx notation: P1DIR ^= BIT4.)
Now, in our program we need to initialize the pin to be an output:
P1DIR = BIT4;
(An equivalent way to do this is to use a logic operator rather than an assignment: P1DIR |= BIT4;)
(An equivalent way to do this is to use a logic operator rather than an assignment: P1DIR |= BIT4;)
The value in P1OUT could be either 0 or 1, so if we care what state the LED starts in we should set that:
P1OUT = 0;
(A better practice is to initialize the output state before we change the pin to an output.)
Now we have an output pin set at 0, keeping the LED off. To turn it on, we give the command:
P1OUT |= BIT4;
To turn it off, we give:
P1OUT &= ~BIT4;
To toggle its state (off if on, on if off):
P1OUT ^= BIT4;
As a final example, demonstrating some power in the other assignment methods, let's put another LED on P1.6.
First, let's configure the two pins as outputs with an initial state off:
P1OUT = 0;
P1DIR = BIT4 + BIT6;
(adding the two values together is easily verified to be 0b01010000).
We can turn each one on and off individually:
P1OUT |= BIT4; // P1.4 on
P1OUT &= ~BIT4; // P1.4 off
P1OUT |= BIT6; // P1.6 on
P1OUT &= ~BIT6; // P1.6 off
Or we can turn them on and off together:
P1OUT |= BIT4 + BIT6; // both on
P1OUT &= ~(BIT4 + BIT6); // both off
And finally, toggle them simultaneously:
P1OUT ^= BIT4 + BIT6; // toggle both
Reader Exercise: Write down the necessary code to use LEDs on pins 3 and 7 of port 1, with pin 3 initially off and pin 7 initially on. Then toggle the LEDs so that 3 is on and 7 is off.
* += is a shorthand operator in C. If I say x += 1;, the command adds one to x and reassigns the result to x. In other words, it's the same as saying x = x + 1;. While algebraically that statement makes no sense, in programming it's very common. Don't think of = as meaning the two sides are equal, read it as "x is now equal to the value currently in x plus 1".
* += is a shorthand operator in C. If I say x += 1;, the command adds one to x and reassigns the result to x. In other words, it's the same as saying x = x + 1;. While algebraically that statement makes no sense, in programming it's very common. Don't think of = as meaning the two sides are equal, read it as "x is now equal to the value currently in x plus 1".
Subscribe to:
Posts (Atom)