10 September 2011

Tutorial 14a: The Alphanumeric LCD

We're almost at a point where we have built a complete scientific instrument. The one thing the capacitance meter lacks is a way to provide the measurement outside of the debugging environment-- not very convenient for working in the field. There are a number of ways we can transfer the data somewhere usable. One way that is useful for single measurements is by displaying the result on an LCD display, much as consumer meters do. We're now going to look at using a standard alphanumeric LCD module with the LaunchPad. This project will also introduce the concept of building a custom library; by the end of this tutorial, you will have a library that you can import into future projects to add an LCD display without having to re-code the entire thing.

The LCD Module (LCM)

One disadvantage to this tutorial is that it require having an LCD display, which you might not have. If not, and are willing to purchase one, I would recommend doing so. These displays can be very useful, and are not very expensive. They come in a variety of sizes and styles-- for this tutorial we will use a standard 16x2 character alphanumeric display modules, such as those found at SparkFun.com. SparkFun carries a variety of these modules; feel free to pick one to your liking, but be certain of a few things: it needs to be configured to run on 3.3 V and should not have been modified to accept serial input. If you'd like a larger module (such as a 20x4 display), it's up to you, as they all work the same way. Get whatever color you'd like.

The SparkFun LCM's utilize an ST7066 chip as the interface to the display, which is based on the ubiquitous HD44780 interface. (If the names make this sound technical, don't worry too much about them-- the important thing here is that we have an interface that translates data from the MSP430 into the commands and characters needed to control the LCM.) This interface uses an 8-bit parallel transmission for sending data to/from the display. As you can imagine, with 8 bits for data, plus another 3 bits for control, you can very quickly run out of GIO pins on your MSP430. In fact, even if we use the G2211 device without a crystal so that P2.5 and P2.6 are available, we only have 10 GIO pins available in total, so we're short 3 pins to control the LCM (needing 11 pins) and the comparator interface (needing 2 pins) for our meter. Fortunately, the HD44780 interface (and thus the ST7066) provides a means of sending data in two 4-bit chunks, and as long as we have no need for reading data from the LCM, we can get by with 6 pins for LCM control, allowing us to just fit the comparator and the LCM into the 8 GIO pins for P1 on our G2211. We're stretching the limits of this chip at this point, which is excellent motivation for expanding to other MSP430 devices in the future!

Connecting to the LCM

The standard LCM module has 16 pin connections (14 without a backlight). The first few connections are for power (possibly in two places, if the LCD is also backlit) and contrast adjustment. Pin 1 (labeled as Vss) should be connected to your LaunchPad ground. Pin 2 (Vdd) is connected to the LaunchPad Vcc. If you are using the backlight, pin 15 (LED+) is also connected to Vcc and pin 16 (LED-) to ground. (This is most easily done on a breadboard. If you find yourself losing track of this description, a good guide to follow is one written by LadyAda.) Pin 3 (Vo) controls the contrast of the screen. If you have a 10k potentiometer available, tie it to the wiper and tie the two ends to Vcc and ground for an adjustable contrast. If not, you can just ground this pin; it probably won't look as good as it could, but it will work.

That leaves 11 pins for the control and data lines. The three control lines are pins 4 (RS), 5 (R/W), and 6 (E). The read/write (R/W) pin is not necessary here, and by tying it to ground we keep the LCM always in write mode. We won't be able to read anything from the LCM (such as the address of the cursor, the busy state flag, etc.), but it saves us a pin on the MSP430. The Register Select (RS) and Enable (E) pins are what we'll use to control the LCM. Finally, pins 7-14 are the data lines D0-D7 respectively. You can consider these pins much like the P1 pins on the MSP430-- D0 is the first bit, D1 the second, and so on. If we used an entire GIO port on an MSP430 to control the data lines, we could connect Px.n to Dn, and by writing a value to Px, we can write the same value to D (conveniently saving us from any strange coding to accommodate changing the order). Since the G2211 doesn't provide enough ports to do this, we'll use the 4-bit mode instead. This mode uses only D4-D7. Leave D0-D3 unconnected for now. (Doing so prevents accidentally writing commands we don't intend.)

For the capacitance meter, we're going to change some of the pin arrangements to accommodate the LCM. We'll use P1.1 as TA0.0 rather than CA1, and use P1.2/CA2 as the input to V+ on the comparator. P1.0 will control RS, P1.3 will control E, and P1.4-7 will control D4-7.

Note: P1.3 is also connected to the button-- this shouldn't affect the code, but since there is a pull-up resistor on P1.3, there will be excess current whenever we drive E low. Unfortunately, the LaunchPad is not designed with a jumper like on P1.0 and P1.6 for the LEDs, so we'll just have to live with this. While we're on the topic, be sure to remove the jumpers for the two LEDs and on the TXD/RXD pins.

Sending Commands to the LCM

Once we're wired up, sending commands or characters to the LCM is a straightforward task. In fact, it can even be done by hand, without a microcontroller at all! (If you're interested in this, or would like to know more about what's going on, see the Reader Exercise below.) The basic idea is that we write an instruction to the data pins and pulse E. The instruction is sent on the falling edge of E, which is why it's pulsed. The instruction issues a command if RS is low, and sends a character if RS is high.

As an example, let's look at the commands we need to set the LCM in 4-bit mode. The 8-bit binary instruction 0b001nnnxx is the "Function Set" instruction. (Here, the n's represent values we choose for the configuration, and the x's imply an unused bit-- these can have either 0's or 1's and not affect the instruction.) Bit 4 in this instruction sets the interface mode: a 1 sets the LCM to accept 8-bit instructions, and a 0 sets it to accept 4-bit instructions. So by sending the instruction 0b00100000 (or 0x20), we configure the LCM to accept commands and characters in two 4-bit chunks instead of one 8-bit chunk. This command must be issued first in order to do anything with our 6-wire setup. We first set the data lines with P1OUT |= 0x20; (which also sets RS low (command mode) and E low in this wiring scheme) and then send the command by pulsing E.

The LCM does not respond instantly to the command, and there are some strict timing requirements in order for it to work correctly. Specifically, RS must be set low a certain amount of time before beginning the pulse on E. The data lines must be set a certain amount of time before the falling edge on the pulse, and must be held at that value a certain amount of time after the pulse. Then a certain amount of time must elapse before we can pulse E again. Fortunately for us, the only timing value of major concern is the time between command pulses. The other times are on the order of a few hundred nanoseconds, and at the processing speeds of the MSP430 there is enough latency to accommodate them. The amount of time needed to complete a command before accepting another can be on the order of 150 milliseconds, however, and so delays must be incorporated to handle them.

So, to recap, here's the set of instructions needed to set the LCM in 4-bit instruction mode:

__delay_cycles(10000);   // wait for the LCM to settle on power-up
P1OUT |= 0x20;   // set to 4-bit instructions
P1OUT |= BIT3;   // E high
__delay_cycles(200);
P1OUT &= ~BIT3;  // E low
__delay_cycles(200);
P1OUT &= 0x0F;   // clear the upper 4 bits

Though E can be set high before setting the data lines, it's convenient to switch the order to prevent any timing mismatches. Note that if you use different pin connections, or especially if you use multiple GIO ports, this code won't work exactly as is; it's convenient to use P1.4-7 for D4-7 to be able to assign directly to P1OUT, but this is not general. If we were to swap the order, for example, to P1.4-7 as D7-4, then we would be writing 0b0100 instead of 0b0010 on the data line with this code. So be careful; either use the pin connections I've suggested here, or assign the data line bits individually as needed. The final line clears the data line bits to make it easier to set the next command properly.

Other Initializations: Sending Commands in 4-bit Mode

Now we have our LCM ready to accept 4-bit commands. This mode works by sending the upper 4-bits (or nibble) with a pulse on E, and then sending the lower nibble with a second pulse. With our wiring scheme, we can do this easily by the following code:

P1OUT |= ( & 0xF0);  // send upper nibble
pulse();
P1OUT &= 0x0F;   // clear
P1OUT |= (( & 0x0F;) << 4);  // send lower nibble
pulse();
P1OUT &= 0x0F;   // clear

I'm assuming here that I've lumped the commands to pulse E with the incorporated delays into a function void pulse(void).   refers, of course, to whatever 8-bit command or character we're sending to the LCM. If we encapsulate this set of commands into a function void SendByte(char),  then we can issue the next initialization commands as follows:

SendByte(0x28);   // Function Set 4-bit, 2-line mode (for 2-line displays, of course)
SendByte(0x0E);   // Display on, underline cursor on, non-blinking
SendByte(0x06);   // Character entry mode: increment address, no display shift

After sending these commands, our LCM is ready to display whatever characters/text we want to send it. Note that to send characters, the commands are similar to above, but P1OUT must also set BIT0 (RS) to tell the LCM to receive character instructions rather than commands. In lcddemoG2211.c, I demonstrate this with a more generalized version of SendByte that lets you send commands and characters. It also demonstrates other commands, such as clearing the display and moving the cursor. If you have an LCM, try out the code yourself. I wouldn't use a DCO faster than about 2 MHz with the selected delays, so if you play around with the code keep that in mind. In the next tutorial, we'll look at how to encapsulate all of this into a custom library that we can keep on hand and how to import it into our capacitance meter project.

Reader Exercise: Not really an exercise-- more suggested reading. If you'd like to know more about how the modules work and the specific commands and characters that can be sent, I suggest reading the following two articles from Everyday Practical Electronics:
        How To Use Intelligent LCDs: Part One
        How To Use Intelligent LCDs: Part Two
These articles are very easy to understand, and do a great job of explaining how to use the LCM.

09 September 2011

Return of the Blog

To all those who have been so patiently waiting: thank you for coming back. As you can see, another tutorial has been posted, and more are on their way. I've not yet finished my dissertation, but I'm making substantial progress, and in a few months I'll finally be a free man!

In the mean time, as I'm coming back to this blog, I've decided it's in desperate need of an interface overhaul. So I'm posing a question to my readers: what would you like to see in the interface? How would you like to have the tutorials presented so as to make them more accessible?

I will likely go back through the past tutorials and clean things up, clarify specifics, and generally improve the quality of information in them as well as bring back some consistency in style and presentation. What else can I do to help this community effectively?

Tutorial 13b: Interfacing the Comparator A+ and Timer A Modules

The idea behind the capacitance meter is simple, but (as may be evidenced in part by the time it took me to get to this) there are some particulars that need to be resolved.

First: how do we minimize any delay in the timing due to delays from carrying out instructions? If we're not careful, a non-negligible amount of time can pass between when we start the capacitor discharge and the timer, or between the comparator trigger and the timer capture.

Second: how do we determine what capacitances can be measured for a given configuration? Smaller capacitors will discharge more quickly, leading to shorter measurement times (meaning more error due to the digital nature of the timer). Larger capacitors take more time to charge up, and may not be fully charged when we start discharging.

The first issue is easily resolved by using features built into the Timer_A module. The second is less easily resolved, but easily understood, so we will know in advance the limitations of our code. There are a couple of things we'll be able to do to improve it generally, but for our purposes here we won't be too concerned about it.

New Feature of the Timer_A Module: Output

Let's introduce here two features in Timer_A we haven't used yet. First off, let's look at how we can use the timer to change an output. Recall that the Timer_A module has a certain number of "capture/compare" registers built into each MSP430 device. (The G2211 and G2231 have two.) Each of these registers can drive their own output; we can program the MSP430 to adjust the output every time the timer reaches the value stored in the register. For example, we can set the output TA0.1 to set the output (to 1, that is) every time the timer reaches the value set in TACCR1. Or we can toggle the output TA0.0 every time the timer reaches the value set in TACCR0. We also have modes that allow us to use both registers on the same output, giving one result at TACCR1 and another at TACCR0. (This ability is used for pulse width modulation, or PWM. We'll talk about that in an upcoming tutorial!)

Take a look at table 12-2 in you x2xx Family User's Guide:
This table lists all of the possible modes we can use to work with the timer outputs.

New Feature of the Timer_A Module: Capture

So far we have only discussed uses of the timer in compare mode. The other mode, capturing, can be used to do precise timing of events. In capture mode, the timer records the value in TAR into TACCRx at the moment when the capture is triggered. This trigger can come externally, or it can come from internal connections to other modules, including the comparator. By configuring the timer in this way, we can record the timer value when the comparator output provides either a rising edge (going from 0 to 1) or a falling edge (from 1 to 0).

Putting It All Together

Here's the general concept used in the capacitance meter. Note that accurate timing requires a calibrated clock, so we'll use the calibrated 1 MHz DCO for this project. First, we connect the resistor to a timer output. (For this purpose, we'll use the TA0.0 output.) The junction between the resistor and capacitor is tied to a comparator input, and the other end of the capacitor is connected to ground. We start charging the capacitor by setting TA0.0, and wait some specified amount of time for the capacitor to charge. The output is then reset (grounded) at the time specified in TACCR0. While the capacitor's voltage is above the reference voltage, the output is set at 1 (assuming we tied the RC circuit to V+ and the reference to V-). When it drops below that value, the comparator output falls, triggering a capture in the timer, recorded in TACCR1. The difference in time between TACCR1 and TACCR0 is an accurate measurement of the decay time of the RC circuit from Vcc to Vref. (Note that if TACCR0 is 0, no subtraction is needed.)

Obviously the longer the time it takes to fall, the more accurate our timing measurement will be overall. But what happens if the time is longer than 2^16 microseconds? TAR rolls over, and starts counting over again; so in our code, we'll need to account for any rollovers that may occur.

Let's examine the comparator configuration used in the code:

void CAinit(void) {
    CACTL1 = CARSEL + CAREF_1;  // 0.25 Vcc ref on - pin.
    CACTL2 = P2CA4 + CAF;       // Input CA1 on + pin, filter output.
    CAPD = AIN1;                // disable digital I/O on P1.1 (technically
                                // this step is redundant)
} // CAinit

This sets up the comparator to use CA1 on the V+ input. If you check the MSP430G2211 datasheet, CA1 is connected to P1.1. Looking up the register description in the Family User's Guide, we configure for CA1 on V+ by setting P2CA4. (P2CA0 also controls V+, and for CA1 should be clear.)

Now let's look at the timer configuration:
void TAinit(void) {
    TACTL = TASSEL_2 + ID_0 + MC_0;     // Use SMCLK (1 MHz Calibrated), no division,
                                        // stopped mode
    TACCTL0 = OUTMOD_1 + CCIE;          // TA0 sets VCTL at TACCR0
    TACCTL1 = CCIS_1 + SCS + CAP + CCIE;       // Use CAOUT for input, synchronize, set to 
                                        // capture mode, enable interrupt for TA1.
                                        // NOTE: Capturing mode not started.
} // TAinit

The timer is set up without starting. Setting TACCTL0 to OUTMOD_1 sets the output TA0.0 when TAR reaches TACCR0, which is 0 by default. Enabling the interrupt lets us keep track of overflows. In TACCTL1, we change to capture mode by setting CAP. To know how to connect the comparator, we need to check the device datasheet. Find the table called "TIMER_A2 SIGNAL CONNECTIONS" and make sure you're looking at the one specific to devices with COMP_A+. In the Device Input Signal column, find CAOUT (internal), and note the Module Input Name in the column next to it: CCI1B. The CCISx bits in TACCTLx select the input, and in the Family User's Guide, we see that these two bits should be set to 0b01 to select CCIxB. In the device's header file, we find that we can set these bits with CCIS_1.

Also note that by setting SCS, we synchronize the capture to the timer clock. We haven't started capturing yet, just as we haven't started the timer. The code is set up to wait for the user to push the button connected to P1.3. Doing so exits LPM0, and continues the main code. The following then happens:
First, the timer is turned on. When the timer rolls over the first time, TA0.0 (on P1.5 in this code) is set, charging the capacitor. We want to wait long enough for the capacitor to charge. The code is set to wait for 10 overflows, which corresponds to about 655 ms. At this point, the comparator is turned on, and the timer is configured to reset TA0.0 at the next overflow (so we've actually charged for 11 overflows at this point). We let the timer capture the next event, or when the voltage at the capacitor (on P1.1/CA1) drops to the value at Vref, or 1/4 Vcc. At this point, an interrupt is triggered. The interrupt routine turns off the captures and the timer and returns to the main code. The code loops back, and starts the process again, waiting for the user to press the button to start a measurement.

Note: Before running the code as set up, keep in mind we're using P1.1; what else is this pin used for? You'll want to remove the TXD jumper to get the project to work properly. Thanks to RobG over at www.43oh.com for pointing this out to me... I was really puzzled by it for an embarrassingly long time!

Try running the code found in CMeterG2211.c. To do this, you'll need a resistor and a capacitor. Use a 10 kO resistor and a 100 nF capacitor (it will have a label that says 104 on it) if you can. In the debugger, set the code to run freely, and push the button. The led should switch from green to red, then back to green, indicating the measurement is done. The timer has captured the event and recorded the time in TACCR1. Unfortunately, there's no way to see this as is yet! Pause the debugger, and examine the timer_a2 registers. The time is recorded in TACCR1. For the suggests RC combination, you should have a value somewhere around 1400. (You can change from the default hex format to decimal by right-clicking the register and selecting decimal in the format menu.)

Try increasing R to 100 kO. You should see the time increase by a factor of 10. Try using a 1 uF capacitor. (You might need to increase the number of overflows to wait while charging to get something accurate here.) In the watch window, we can view the value in the overflows variable. To do this, click where the window says , and type in the variable name. With such a large capacitor, you should see the number of times the timer wrapped around before stopping. With the measured time and the known resistor value, you should be able to use the formula provided in the previous tutorial to calculate the value of the capacitor. Feel free to experiment with this program. In particular, how consistent are your timing measurements?

Aside from the lack of ability to see the timer value without using the debugger, there are a few issues to work out still in this meter. We'll take a careful look at some of these in the future, and bring back this code to demonstrate ways we can see data and ways we can improve the timer.

Reader Exercise: Given the discussion in the previous tutorial about the accuracy of the meter, and from your own experimentation with the program, where are the major sources of error in the measurement? How consistent is the timing? What might cause the inconsistency? What assumptions have we made in the way we measure the capacitance? Once you've built an instrument to make any kind of scientific measurement, it's important to identify all of these aspects. By doing so, we identify the limitations of the instrument, both those we can fix and those we have to live with. 

18 February 2011

Tutorial 13a: Combining Peripherals

The MSP430 peripherals are very useful tools in their own right, but when we're able to use two or more peripherals together, they become much more powerful for instrumentation.  This tutorial will go through one way that we can combine the Comparator_A+ and Timer_A peripherals.  In the next post, we'll use this combination to build a capacitance meter.

Background
Capacitors are one of the three fundamental, passive components that are used in nearly every electronic device out there.  When a voltage is applied to a capacitor, it will store a charge proportional to the applied voltage.  This proportion is called the capacitance.  These factors are all connected by the simple relationship Q = C V.  (Q is the charge, C the capacitance, and V the voltage.)  When the applied voltage is removed, the charge doesn't disappear immediately, but rather decays gradually by running a current through whatever resistance is present between the capacitor's two leads.

The Discharging Capacitor Equation
V_0 is the starting voltage.  In SI units, V is in volts, t in seconds,
R in ohms (Ω), and C in Farads. Equivalently, you can use t in μs and C in μF,
or t in ms, R  in kΩ, and C in μF. These are more useful in formulating
the calculation portion of the instrument. 
The way in which a capacitor's charge dissipates is simple to describe, but might not be what you expect if you haven't seen it before.  Right when we disconnect the charging voltage V, the voltage across the capacitor is still V because no charge has moved yet.  In that first moment, a little chunk of charge will flow as a current through the resistance, according to the well-known Ohm's Law: V = I R.  (Again, V is the voltage, I is the current, and R is the resistance.)  After that first moment, how much charge will move in the next moment?  A simple picture would be to guess that the same amount will move, however that's not what happens.  Since a little charge has already left the capacitor (Q is now smaller), the voltage across it now must be a little smaller too!  Since we have a slightly lower voltage, the next moment will have a little less current.  The following moment a little less still, and the next a little less, and so on.  This picture describes not a linear drop in the voltage, but rather an exponential change.  If you watch the voltage on the capacitor carefully (with an oscilloscope or some other device) you'll see that this is exactly what happens.

While it's not a linear change, it's still a simple description, and we can exploit this characteristic to find the value of the capacitance, C.  Assuming we know the resistance, all we need is to apply a voltage and time how long it takes for the voltage to decay to another known value.

Formulating the Capacitance Meter
The idea behind the instrument we are going to build is simple: we charge up a capacitor, then start the timer at the moment we start discharging.  We stop the timer when the capacitor has discharged to a known point, then plug in the values into the formula.

Formula needed to calculate C from the MSP430
C is in μF if t is in μs and R in Ω.  Alternatively, C is in nF if t is in μs and R is in kΩ  

The formula is easy to find.  When we invert the Discharging Capacitor Equation, we find that our measured value of C depends on the time for discharge, the resistance, and the fraction of the starting voltage to the ending voltage.  We can use Comparator_A+ to trigger the timer when we reach our chosen reference.  For this tutorial, we'll discharge the capacitor until it reaches 1/4 Vcc, so that we use f = 4.  This value is convenient, and minimizes any external components.

In the next tutorial, I'll show you how to set up the peripherals and suggest a few ways that you can read the obtained result with the MSP430.  You may wonder how accurate this setup will be.  The short answer is that it will be as accurate as you know the value of the resistor; if you use a 5% resistor, you'll be able to measure C to 5%.  A 1% resistor tolerance will give you close to 1% for C, but at that point some of the other factors become more important.  If you are interested, take a look at this description I've written on finding the error in the measurement.

29 December 2010

New Devices!

If you haven't already seen from some of the other websites in the LaunchPad community, TI is gearing up to release more MSP430 devices that are compatible with the LaunchPad.  Some of these will be 20-pin chips, and will make use of the entire board.  You can see details of the new devices on TI's website.

In regards to the new devices, some will include more of the MSP430 peripherals, most notably a hardware UART for serial communication.  The UART uses the same two pins that TI chose to use on the LaunchPad for the timer-based UART used in the demo program that comes with the G2231 chip.  Unfortunately, it swaps the transmit and receive functions on these pins.  TI is working on potentially re-designing the LaunchPad, and has asked for the community's views on how to approach this issue.  If you haven't already, go to the post on the E2E Community site, review the proposals they've given, and vote for the solution you think is best!

27 December 2010

Tutorial 12: Making Comparisons

As we've seen, microcontrollers have great usefulness in digital electronics. In the real world, and for scientific applications, however, digital is not always adequate. In this tutorial, we begin working with analog signals using a 1 bit analog to digital converter: the comparator.

Some MSP430 devices have a built-in comparator (called the Comparator_A+ module in the technical documentation, I'll refer to it as CA+ here), including the MSP430G2211 that comes with the LaunchPad kit. (See TI's website for other LaunchPad-compatible devices that include the CA+ module.) Up to this point, all of the tutorials could be used on both the G2211 and the G2231 chips in the LaunchPad kit by changing the #include header appropriately. For this tutorial, you will need to use the G2211.

Overview of the Comparator_A+ Module
Simplified diagram of the Comparator_A+ module.  Taken from the book
MSP430 Microcontroller Basics; I highly recommend getting a copy of this book!

The CA+ module is very flexible, allowing multiple GIO pins to be connected to its inputs and including a variety of useful internal voltage references. As you may recall, a comparator has two inputs, called inverting and non-inverting (often labeled V+ and V- respectively). The V+ input can be connected to three different pins for external signals, or any of three different internal reference signals. The V- input can be connected to seven different pins (two overlap with the V+ inputs) and any of the internal references. CA+ has an output that can be read in software, trigger the CA+ interrupt, and trigger a timer interrupt. All of these options give the CA+ module its flexibility and usefulness to us in developing instrumentation.


Take a look at the datasheet for the G2211, and find the page that shows the pinout diagram for the chip. The pins that can be connected to the CA+ inputs are labeled as CAx. Note that CA0-2 can be connected to V+, while CA1-7 can be connected to V-. Note also that in addition to providing the CA7 input, P1.7 can be configured to provide the output value CAOUT externally.


Configuring the Comparator_A+ module
The CA+ module has three different registers for its configuration: CACTL1, CACTL2, and CAPD. These registers are described on pages 19-10 to 19-13 of the x2xx Family Guide. We'll look at the basic pieces here.

CACTL1

  • The CAREFx and CARSEL bits (4-5 and 6) control the internal references for the comparator. Bits 4 and 5 select the reference value, while bit 6 selects which input is connected to the reference. There are three references provided in the module. Two of them are a fractional value of the voltage powering the MSP430: 1/2 Vcc and 1/4 Vcc. If you are powered from the USB (3.6 V), these references are 1.8 V and 0.9 V respectively. (These are accurate to about 1%.) A third reference is provided by the forward voltage of a transistor. This voltage is typically 0.55 V, but is less accurate and susceptible to temperature changes.
  • The CAIFG, CAIE, and CAIES bits (0-2) control the interrupt for the comparator. Bit 0 is the interrupt flag, which clears automatically when the interrupt is serviced. Bit 1 turns on the interrupt, and bit 2 selects whether an interrupt is triggered on a rising edge (low to high transition) or a falling edge (high to low transition).
  • The CAON bit (3) turns the comparator on when set, and off when cleared.
  • The CAEX bit (7) is used to exchange the two inputs; ie. the pins/references connected to V+ and V- are swapped. (In addition, the output is inverted to compensate for the change.) This ability is useful in examining values close together, but for basic functionality is not necessary.
CACTL2
  • The P2CAx bits (2-6) are used to select the pins connected to the comparator inputs. V+ is selected with P2CA0 and P2CA4. V- is selected with P2CA1-P2CA3. The x2xx Family Guide provides a table on page 19-12 that explains which bit configuration selects the various pins.
  • The CAF bit (1) puts the output through an RC filter to smooth out any rapid oscillations that might occur if the comparator inputs are very close together. It's not always necessary, but is a good idea to enable if you're using slowly-varying signals.
  • The CAOUT bit (0) is the output value only; you cannot write to this bit, but reading it will give you the current value of the comparator output.
  • The CASHORT bit (7) shorts the two comparator inputs together. While this might sound like an odd thing to do, it is useful under certain circumstances. Basic use of CA+ will not use this function.
CAPD
  • The CAPD register is analogous to the Port registers; each bit corresponds to the input pins CA0-CA7. The purpose of this register is to disconnect the digital circuitry for the GIO ports from the pins that are being used with analog signals. If an analog signal close to the transition voltage for the digital circuit is applied to the pin, the digital portion could oscillate between high and low fairly rapidly. This effect can cause degradation of the circuitry in the chip, and so it's best to disconnect it completely when analog signals are used. In fact, when a pin is connected to the comparator, it is automatically disconnected. The purpose of this register is to manually control the disconnect. Sometimes you may want to use the comparator on multiple signals; only one pin can be connected to the comparator at a time, but you can switch the input connection in the software. While the CAPD method of disconnecting the digital circuit is redundant when only one pin is used, enabling the CAPD bit for a pin connected to an analog signal prevents it from being reconnected to the digital circuit when the software causes the comparator to switch input pins.

Programming Example
To demonstrate the CA+ module, look at a basic comparison program in bcompG221.c. The idea in this program is to measure an analog voltage, and flash an LED if the voltage is above a particular reference, in this case 1/2 Vcc (1.8 V when running off the USB power). To do this, the program uses the Timer_A module to flash the LED, while the Comparator_A+ uses an interrupt to turn the flashing on and off.

The portion of the code that configures the CA+ module is as follows:

CACTL1 = CAREF1 + CARSEL + CAIE; // 0.5 Vcc ref on - pin, enable
                                 // interrupts on rising edge.
CACTL2 = P2CA4 + CAF;      // Input CA1 on + pin, filter output.
CAPD = AIN1; // disable digital I/O on P1.1 (technically
// this step is redundant)

The values used here can be found in the header file for the G2211. Setting CAREF1 alone selects 1/2 Vcc as the reference voltage and setting CARSEL connects the reference to the V- input. Setting P2CA4 alone selects CA1 (same pin as P1.1 for the G2211) as the V+ input. AIN1 was defined to be BIT1, so we permanently disable the digital circuit on P1.1 for this program. This step wasn't essential, since we don't change the inputs on the comparator in this program.

After all the peripherals are configured, the comparator is turned on with CACTL1 |= CAON (the |= operator is used to prevent changing any of the other configurations we put in at first) and the chip enters LPM0.

TimerA periodically triggers an interrupt and toggles the P1.0 output with the value stored in flash. When CAOUT is 0, flash is 0 and so the LED never turns on. When CAOUT is 1, however, flash is set to LED1 (defined to be BIT0) and the LED toggles on and off.

Now let's look at the Interrupt Service Routine for CA+:
#pragma vector = COMPARATORA_VECTOR
__interrupt void COMPA_ISR(void) {
if ((CACTL2 & CAOUT)==0x01) {
CACTL1 |= CAIES;    // value high, so watch for
                    // falling edge
flash = LED1;       // let LED flash
}
else {
CACTL1 &= ~CAIES;   // value low, so watch for
                    // rising edge
flash = 0;          // turn LED off
P1OUT = 0;
}
} // COMPA_ISR

None of the examples that TI provides on their website demonstrate how to use the Comparator_A+ interrupt. To find the proper syntax, I located the vector name in the msp430g221.h header file. (Remember, the vector name must be what the compiler expects (in this case, COMPARATORA_VECTOR). The header file is the safest place to locate the proper name.) The interrupt routine name, of course, can be named anything. Something descriptive is always helpful, though. For this program, I chose COMPA_ISR(). The service routine first examines the value of CAOUT. If it is 1, then the voltage on V+ is higher than the reference on V-. The next interrupt should be when the value drops below the reference again, so it sets the edge select to a falling edge. It then sets flash to a non-zero value so the LED will blink. If CAOUT is 0, then V+ is lower than the reference. The edge select is set to a rising edge, flash is set to zero so the LED won't blink, and the P1OUT is cleared to ensure the LED is off.

To test the program, you can connect a potentiometer (anything above 1 kΩ should work) between Vcc and ground, and connect the wiper to the P1.1 pin on the LaunchPad. Adjust the potentiometer to see the LED start blinking (indicating the voltage on the pin is above 1.8 V) and back again to see it turn off (indicating the voltage is below 1.8 V). If you don't have a potentiometer, you can try two resistors of different values. Connect one resistor between Vcc and P1.1, and the other between P1.1 and ground. If the smaller resistor is between Vcc and P1.1, the voltage should be more than 1/2 Vcc, and the LED blinks. If the larger is in that place, the voltage is less than 1/2 Vcc, and the LED turns off.  (Caution: If you use two resistors to try this, be wary of removing the resistors while the LaunchPad is powered.  You might not do any damage, but it's safer to power off a circuit before pulling pieces out.)

Reader Exercise: Change the program so that the LED doesn't blink, but is set on/off constantly for high/low values of CAOUT. Then use TimerA to periodically change the reference voltage between 1/2 Vcc and 1/4 Vcc. When comparing to 1/2 Vcc, it should turn the red LED on P1.0 on if the analog signal is above the reference. When comparing to 1/4 Vcc, it should turn the green LED on P1.6 on if the signal is above the reference. Turning the knob on the potentiometer, you should see the green LED light when the signal is above 1/4 Vcc, then the red LED light when above 1/2 Vcc.

12 December 2010

New Tutorials Coming Soon

I just wanted to put a quick post up letting people know that more tutorials are on their way.  I've been in Norway for the past long while doing my research for my Ph.D.  We launched our sounding rocket today, and I will be coming home in a few days.  At that point, I can get my hands on some hardware to do the tutorial I've been anxiously planning.  Should be a lot of fun; hope you're looking forward to it!

This post written from Longyearbyen, Svalbard; 78 degrees, 13 minutes North latitude!