08 June 2010

Crystal Timers

The MSP430 has great internal clocks, but for time-critical applications we need something more stable. Crystals are one of the best oscillators available, and are quite stable if they are handled correctly. While it would make more sense to look at timers starting with the internal clocks, I have an immediate need to work toward USB communication, which requires the use of crystals for timing.

MSP430's can have up to two crystals to set clocks externally. XT1 is typically a low frequency (< 1 MHz), which is why it is usually referred to as LFXT1 (low frequency crystal 1). All of TI's MCU's have pins that can be used with one of these low frequency crystals.  The chips can also be configured to use a high frequency crystal if needed.  Many MCU's also have an XT2 built specifically for HF oscillators.  The exact frequency chosen depends on the application, but a commonly used frequency is 32,768 Hz, often referred to as 32 kHz even though it is not a decimal kHz. It is, however, a binary kHz, which is why it is a convenient frequency for timing applications. In exactly 1 second, the crystal will go through 2**15 oscillations. When 15 bits roll over, the timer is reset to zero, and every reset happens at exactly 1 s intervals.

Connecting a crystal to an MSP430 is a little tricky. Fortunately, TI has provided some excellent documentation to help. Essentially, the crystal should be close to the chip and isolated from other signals in the circuit. Crystals have particular capacitances that need to be matched correctly in order to be accurate. The newer MSP430's (anything but the x1xx series, really) are able to set capacitors to a few values internally. The target board I received included a 32 kHz crystal with 12.5 pF capacitance. 12.5 pF is one of the values that can be set internally, so the crystal can be put on the board without needing external capacitors. It does require, however, setting the MCU software initially to have the right capacitance internally. This is done by setting the appropriate value to the XCAPx bits in BCSCTL3 (Basic Clock System Control 3). The header files include the values XCAP_x to help set the proper bits correctly. For my 12.5 pF crystal, XCAP_3 is the correct selection. Note in the code below rather than setting BCSCTL3 = XCAP_3, |= is used to only change the XCAPx bits in the register.

In the errata for the MSP430F2132, it mentions that the MCU sometimes has issues with crystals with an equivalent series resistance (ESR) less than 40 kΩ. The crystals I purchased have 30 kΩ ESR, but seem to work fine. I don't know if my fumbling soldering technique increased the resistance sufficiently or if it just appears to work and isn't perfectly accurate, but it seems close enough for now. Future workarounds are to pick a crystal with a higher ESR or to add a resistor into the circuit as explained in TI's application note about this particular erratum.

Once the crystal is in place, it should be checked to be certain it is oscillating. This post's program won't be able to prove accuracy of the crystal, but it at least shows that the crystal oscillates and can be used. The crystal's frequency is accessed with the auxiliary clock ACLK.

/* 32kcrystalF2132: quick program to test the functionality of a watch crystal
* soldered to the target board. Flashes an LED on P1.0 at 2 Hz.
*/

#include <msp430f2132.h>

#define LED BIT0

void main(void) {
    int i;                      // internal counter
    WDTCTL = WDTPW + WDTHOLD; // turn WDT off
    P1OUT = 0x00;
    P1DIR = LED;
    BCSCTL3 |= XCAP_3; // xtal has 12.5 pF caps
    TACCR0 = 16383; // f_xtal / 2 - 1 gives 2 Hz
    TACTL = TASSEL_1 + MC_1 + TACLR; // ACLK + Up Mode + Clear timer

    for (;;) {
        while ((TACTL & BIT0) == 0) { // wait for timer to reach TACCR0
    }
    TACTL &= ~BIT0;       // reset TAIFG
    P1OUT |= LED;                 // LED on
    for (i=0; i<0x314; i++) { // short delay
    }
    P1OUT &= ~LED; // LED off
    }

} // main

The comments in the code should help explain how the program works, but it's worth taking some time to explain some of the features of Timer A.
  • Any of the timers in an MSP430 can be configured to run off of any of the clocks (MCLK, SMCLK, ACLK) by setting the TASSELx bits in TACTL. TASSEL_1 in the header file configures the timer to run off the auxiliary clock connected to the crystal.
  • The MCx bits set the mode of the timer. These are initialized to 0 when the MCU is powered, keeping the timers turned off and conserving power. MC_1 in the header file configures the timer in "Up Mode", which counts upward until it reaches a value set in TACCR0. MC_2 sets the timer in "Continuous" mode, which counts upward until the counter rolls over (from 0x0000 to 0xFFFF). This code could use continuous mode, but would then only be able to flash the LED at exactly 1 Hz. Using up mode allows you to set the flash to exact values at frequencies higher than 1 Hz and up to 32 kHz.
  • The TACLR bit clears the timer so that it starts at 0 from wherever the bit is set. This is useful because the timer continues to run even when the code is not using it or looking at it. If an exact time is needed, the timer should be cleared to be certain it counts the right number of times before reaching TACCR0.
  • The TAIFG bit (this is bit 0 in TACTL) is set when the timer rolls over, either at the top in continuous mode or at TACCR0 in up mode. The code watches this bit to know when to flash the LED. Note that the flag must be reset manually. The timer continues to run while the code is turning on the LED, waiting briefly (0x314 is just a random value I picked for a short flash), and turning off the LED, so when the loop starts again, the timer has already been running. This feature is very useful for exact timing applications, because we don't need to be concerned about accounting for the processing time between loops. As long as the program takes less time to run than intervals between TAIFG being set, the program will execute at exactly the time we require.
One final note about the value set to TACCR0--Since the timer starts at 0, and 0xFFFF coresponds to 65,535, the timer can only trigger at integer values between these two.  For this crystal, 32,768 counts would correspond to 1 s, so by setting TACCR0 to 32767 we would trigger every second.  The correct way to get the exact timing is to count to f/n - 1 (using whole fractions of the oscillation frequency, i.e. 1/2 s., 1/3 s., 1/4 s., etc as the period between flashes), so 1/3 s would be TACCR0 = (1/3) / 32,768 - 1 = 10,922. As long as this value is less than 65,536, nothing other than setting this register needs to be done.

07 June 2010

Configuring Inputs & Outputs

The MSP430 becomes especially useful in the laboratory environment when it is used to collect information and send information in conjunction with equipment and measuring instruments. To do this, the chip needs an electrical connection with the transducers, or motors, or whatever other devices are being used. These connections are made through input and output ports.

All MSP430 microcontrollers have general input/output ports. The larger chips, of course, have more ports available, but even the smallest chips have pins for input and output. One of the nice features of these microcontrollers is that the pins can be used as an input or as an output; each port is normally associated with up to 8 pins, and each can individually be an input or an output, and can even change function in the middle of a program. The MSP430F2132 has 3 ports (24 pins) available that can be configured for general I/O.

Keep in mind that,while for low power systems the MSP430 is able to drive devices directly (assuming they run well at 3.3V), many devices will need to be controlled/sampled with transistors and amplifiers, or other intermediate components, to prevent damaging the MSP430 with high voltages or currents.
Part of the memory space in the MSP430 is set aside as specific registers, which are used to store information on how the chip should behave. The behavior of each pin on a port is controlled with the register P#DIR, where the # corresponds to the particular port being used. P#DIR is a 1 byte value with each bit corresponding to one pin for the port. For example, the 3rd bit on P1DIR controls P1.3. (Remember that the bits are numbered 0-7, not 1-8, so the 3rd bit is actually the 4th least significant digit.) When a bit in P#DIR is set to 0, the pin is configured as an input. When it is set to 1, the pin works as an output. As an example, if P3DIR = 0b01100101, then P3.0, P3.2, P3.5, and P3.6 are set to be outputs, while P3.1, P3.3, P3.4, and P3.7 are set to be inputs.

Setting the value on an output is done through the P#OUT register. This register is again a 1 byte value, each bit corresponding to each pin on a port. In the previous post, the LED connected to P1.0 was turned on and off by writing a value to the 0th bit of P1OUT. P1OUT = 0x01 (which corresponds to 0b00000001) turns on the LED by applying Vcc to the pin. P1OUT = 0x00 turns off the LED by grounding the pin. If we had set P1OUT = 0x03 (0b00000011), the LED would have turned on since bit 0 is set to be high. What about P1.1, since the second bit is high? In this case, since P1DIR was configured to have P1.1 an input, no voltage is applied to the pin, but the number is rather stored in a buffer. If we reconfigure P1.1 to be an output after setting P1OUT as above, then it starts with Vcc applied to the pin when switched. It is a good idea to always set P#OUT to the desired initial values before setting P#DIR to be certain the buffer values match what we want the pin behavior to be when the device is turned on. (It wouldn't be so good to turn on the controller and immediately start moving a motor before setting the output to keep the motor from turning.)

Reading inputs is done with the P#IN register. The values in this register correspond to the current voltage level on each pin in the port. Thus, for pins configured as outputs, the bits in P#IN and P#OUT are the same. When an MSP430 of any kind restarts, it defaults to setting the port pins as inputs. (There are exceptions for some pins, such as those intended to connect to a crystal oscillator. See your chips datasheet for details.)








The following program makes use of I/O ideas to turn the LED on P1.0 on and off by using a push-button switch on P3.3. The push button used is connected with a resistor to ground so that when unpressed the output doesn't float, but is tied to ground. When pressed, the output is connected to Vcc. This connection also causes a small current to flow through this "pull-down" resistor. A push button can also reverse this behavior by having the output tied with a "pull-up" resistor to Vcc and grounding the output when pressed. The output of the button can be connected to an input on the MSP430 in either case. For the pull-down setup, the input reads 0 when unpressed and 1 when pressed. I've done this with an external circuit, connecting my push buttons to Vcc and ground with external resistors enclosed in a small box. In the video below, the red button is tied to a pull-up resistor, and the black button to a pull-down resistor. (The black is used in the program below.) The MSP430 actually is built with resistors inside the chip, and each input pin can be set with pull-up or pull-down resistors individually without external pieces. We'll examine how to do that in another post soon.

A quick comment on some parts of the program: the header files include definitions for each individual bit. BIT0 is defined as 0b00000001, BIT1 as 0b00000010, and so on. I've used two definitions to make the program even more clear. I use LED to refer to bit 0 and BTN to refer to bit 3, since those are the bits used in the circuit design for the led and the button. The program also makes a function call. The purpose of the short delay function is to deal with switch bounce. Most mechanical switches will flip on and off a few times when pressed or released. To make certain the led doesn't rapidly turn on and off with the bouncing, a delay is used. The program constantly checks the current state of the button. Each check delays for a brief moment so that any bouncing occurs while the program is in the delay loop.

The method used for switching the output values is also very useful. Any bit and 0 returns 0, while any bit and 1 returns the original bit. ~LED gives the value 0b11111110, in this case, so bits 1-7 remain unchanged while bit 0 is set to 0 when you set P1OUT to P1OUT & ~LED. Any bit or 0 returns the original bit, while any bit or 1 returns 1. Setting P1OUT to P1OUT | LED has the opposite effect of setting bit 0 to 1.


/* buttonF2132: I/O configuration test that lights an LED when a push button is
* pressed. The LED is connected to P1.0, active high. BTN is connected to
* P3.3, active high (ie. when pushed gives a positive voltage, normally gnd.)
*
* Also demonstrates bit manipulation and function calling. The delay function
* accommodates switch bouncing.
*/


#include <msp430f2132.h>


#define LED BIT0 // P1.0
#define BTN BIT3 // P3.3


void delay(void);


void main(void) {

WDTCTL = WDTPW + WDTHOLD;
P1OUT &= ~LED; // initialize output by ensuring bit 0 is 0.
P1DIR = LED; // set bit 0 to output
P3DIR = 0x00; // unnecessary, but explicitly states P3 is all inputs.

for (;;) {

if ((P3IN & BTN) == 8) {
P1OUT |= LED; // set bit 0 to 1, turn on LED
delay(); // delay to prevent switch bounce
}
else {
P1OUT &= ~LED; // set bit 0 to 0, turn off LED
delay();
}
} // infinite loop
} // main


void delay(void) {
int i;
for (i=0; i<0xFF; i++) {
}
} // delay





Reader Exercise: Write a program that controls two LEDs as in the previous exercise. Use two other pins in port 1 as inputs for two buttons, one with a pull-up resistor and one with a pull-down resistor. Have each button control one of the two LEDs. Set one LED to be off unless its button is pressed, and set the other LED to be on unless its button is pressed.