First, let's examine some of the features of the ADC10 peripheral. ADC10 of course requires a clock, and can source from any of the three clocks in the MSP430 (and subsequently from a crystal, DCO, or VLO). In addition, ADC10 comes with its own internal clock that can be used independently of the system clocks. This clock is typically in the 5 MHz range, but is uncalibrated and thus varies from chip to chip, as well as with operating voltage and temperature. A major advantage to the internal oscillator is that it can remain in operation even when other clocks are powered down in an LPM.
ADC 10 can connect to up to 16 different inputs. Typically, 8 of these are external inputs, 4 are internal inputs, and 4 are other references (on some devices, they are extra external inputs for a total of 12). The G2231 device has 8 external inputs (on each of the pins in P1), and also has a temperature sensor built into the chip as an internal input (in addition to the other three internal inputs, which have to do with voltage reference comparisons).
Like the Comparator_A+, ADC10 requires a reference voltage for operation. In fact, it can operate with two reference voltages for the upper and lower bounds of conversion. The upper reference can be anywhere between 1.4 V and Vcc (up to 3.6 V). The lower reference can be between 0 and 1.2 V. There are two references available inside ADC10 at 1.5 V and 2.5 V, and it can also use Vcc in addition to an external reference.
Finally, the ADC10 also has 4 operating modes. Two of these modes sample only a single channel. The other two modes cycle through a specified set of the 16 possible inputs. Each single/sequence type can be done only once, or repeated. (Note: in a sequence mode, you must use the inputs in order. If you want to sample 3 inputs, you must use A0, A1, and A2. Unfortunately, the only way to sample arbitrary inputs is to use single channel mode and change channels in software.)
That covers the bulk of the dizzying ways to configure the ADC10; it's a lot to sort through, so keep in mind that we're only going over it to have the different things you can do in the back of your mind. The best way to learn how to use all of the features is by example, so let's look at a simple example by modifying the capacitance meter project to a voltage meter. This meter will be restrictively useful, as it will only be able to measure voltages between 0 and 3.3 V, but it will illustrate the idea. We'll display the output on the LCD as before, but the code can easily be modified to pause in the debugger to find the result as was done at first with Comp_A+ if you don't have an LCD. For the LCD display, we'll use the single-channel mode and repeat the measurement in software, which makes it easier to use the debugger to see the result.
The x2xx User's Guide gives a set of diagrams to explain the process used in each of the four modes. For example, in the repeat single-channel mode, the peripheral is turned on and enabled. The ADC10 is triggered to start a conversion, which is stored upon completion. If interrupts are being used, the flag is set, and the ADC10 returns to on of three steps, depending on just how we set it up. Keep in mind this all happens within the ADC10 module itself, leaving the MSP430 free to perform any other actions it needs to. You can use the ADC10 interrupts to do something with the code after samples are taken.
Our code will instead use single-channel mode, which is very similar to the repeat single-channel mode, but without the repeat part. =) I've chosen this mode because I won't be using a low power mode, and it's easier to coordinate timing so that a sample isn't taken and finished while waiting for the LCD to update. While a new conversion is occurring, the code will trap in a loop before writing the measured sample to the LCD for display. Once that's finished, a new conversion will be started to update the measurement.
There are 8 registers associated with ADC10; of these, 4 are used to configure the peripheral. One is used to store the individual samples, and three are used to control transferring the sample data for storage. (More on this later; for now we're going to keep it simple and only worry about 5 registers!)
While this sounds like a lot of configuration, fortunately two of the registers are used solely for configuring the inputs. ADC10AE0 enables the ADC function of the external pins being used. (This is necessary, because P1SEL changes the operation of those pins to a function other than ADC; since it's a binary value, P1SEL can only configure two different operations. This register frees up those pins for uses other than just ADC!) ADC10AE1 performs a similar function, but only for devices with more than 8 analog inputs.
We'll look at the other two configuration registers in more detail. ADC10CTL0 handles some of the base configurations of the peripheral-- the voltage references, sampling time and rate, and handling power and interrupts for the ADC. ADC10CTL1 controls the inputs, clock, mode, and data formatting. Here are the essential pieces for each register (we won't cover all of them today):
- SREFx (Bits 15-13): These select one of 8 different configurations for the upper and lower references for the ADC.
- SHTx (Bits 12-11): These select 4 different sampling times for the ADC. The voltage is held constant during conversion by charging a capacitor; these control the amount of time you allow for charging. Obviously more time ensures a more accurate sample, but limits the sampling rate achievable by the device and risks having the voltage being measured change during the sampling time. You can select 4, 8, 16, or 64 clock cycles (of ADC10CLK).
- REF2_5V, REFON (Bits 6,5): Selects between 1.5 V and 2.5 V references and turns the reference on/off.
- ADC10ON, ENC,ADC10SC (Bits 4,1,0): Turns on the ADC, Enables Conversion, and Starts Conversion respectively.
- ADC10IE, ADC10IFG (Bits 3,2): Interrupt enable and flag.
- INCHx (Bits 15-12): In single channel mode, selects the channel to sample. In sequence mode, selects the highest channel to sample.
- ADC10DF (Bit 9): change between straight binary data and 2's complement data.
- SSELx, DIVx (Bits 4-3,7-5): chose the clock source and divide the clock frequency by 1-8.
- CONSEQx (Bits 2-1): Select the sequence mode.
- BUSY (Bit 0): a read-only flag that indicates when the ADC is in the middle of a sample/conversion cycle.
Last of all, we'll mention the ADC10MEM register. When conversion takes place, the value is stored and read from here. If ADC10DF is cleared (value 0), we can read this straight away: 0x00 is equivalent to the lower reference, 0x3FF is equivalent to the upper reference, and the intermediate values are a line between the two points. If ADC10DF is set (value 1), the value is stored in 2's complement. This can be useful for transferring data in some configurations, but we'll not need it today.
That does it for a brief (but long!) summary of the basics. Let's look at the simple volt meter now. The code for this project can be seen in VMeterG2231.c. It will require the simple_LCM library from the previous tutorial. There's very little that's new here, and the code should be clear by itself. It uses input A1 on P1.1. You can test the code by using a potentiometer connected between Vcc and ground and connecting the wiper to P1.1. When you turn the potentiometer, you should see the corresponding value change on the LCD.
So much for the basics; next time we'll look at how to store the data for later analysis and start working on an actual experiment.
Reader Exercise: How can you use this same code to measure a larger voltage range? Hint: a simple way to do it uses only two passive components. A trickier task is to be able to measure positive and negative voltages; can you think of a way to do this even though the MSP430 can't use a negative voltage reference? Hint: an op amp might help.