Documentation: ADC Components for the MSP430    
Author: Jan Hauer
Date: 13.5.04     
       
There are two ways to use MSP430's ADC12: Either via the well-known 
interfaces ADC and ADCControl which are provided by ADCC or via the 
interfaces MSP430ADC12External, MSP430ADC12Internal and MSP430ADC12Advanced, 
which are provided by MSP430ADC12C. The difference between the configurations is 
that MSP430ADC12C offers true MSP430-specific services (e.g. switching to one of 
our conversion modes), while ADCC is used to have the MSP430 stay compatible 
with the old interfaces. Because MSP430ADC12C offers much more functionality 
than ADCC, new applications written (only) for MSP430 should use MSP430ADC12C. 
Also, because MSP430ADC12C parameterizes the control-commands, components can 
choose their individual settings independent of other components (i.e. there is 
no ADCControl anymore that changes global settings).

ATTENTION: Currently ADCC or MSP430ADC12C/MSP430ADC12M should never be used in 
the same application - make sure that no lower component accidentally wires to 
MSP430ADC12M (e.g. radio measuring RSSI) when some other component uses the 
ADCC.

Because the commands in the ADCControl-interface have a slightly 
different meaning than in the original interface the ADCC is explained in more 
detail in the following section a). MSP430ADC12C is explained in section b).
Generell information about the ADC12 can be found in "MSP430 User's Guide" 
Chapter 17. 


a) ADCC 
To use the ADCC you need to do some initialization first, then 
conversions can be made. 
Initialization involves the following two steps: 
First "ADCControl.init()" has to be called, which initializes some internal 
settings (it may be called multiple times). Then "ADCControl.bindPort(uint8_t 
port, uint8_t adcPort)" needs to be called once for each (external) port that is 
to be sampled during runtime. This binds a port-number ("port") to the actual 
input-channel and some other settings coded in "adcPort". The reason for this 
is, that any subsequent calls to "ADC.getData()" will only require the 
port-number to identify the corresponding settings. Obviously the port-number is 
not passed as a parameter of "ADC.getData()", but it is the number of the 
ADC-interface instance (ADC is a parameterized interface). That's why it is 
NECESSARY to ALWAYS have the "port"-parameter in "ADCControl.bindPort(uint8_t 
port, uint8_t adcPort)" be the same as the interface parameter of the ADC 
interface through which your component is wired to ADCC. Actually this is how 
the interface ADCControl is supposed to be used anyway, see for example 
tos/sensorboards/micasb/PhotoTemp.nc.
The value for the "port" parameter depends on the channel number. External 
channels are named A0-A7. Which pins of the MSP430 they are mapped to
depends on the device, see the device-specific datasheet (e.g. for the 
MSP430F149 it's P6.0 - P6.7). To choose external channel Ax set "port" to x. 
Internal channels have fixed numbers 8 to 11. The following table gives an 
overview of all valid values for the "port"-parameter (analogous to the 
INCH-bits, User Guide 17-25):

  port  | Input channel
-------------------------------------------------------
   0    | A0
   1    | A1
   2    | A2
   3    | A3
   4    | A4
   5    | A5
   6    | A6
   7    | A7
   8    | VeREF+ (internal)
   9    | VREF-/VeREF- (internal)
  10    | Temperature diode (internal)
  11    | (AVcc-AVss)/2 (internal)
 
It is recommended to define some constants for your platform in your 
hardware.h that reflect the first eight entries of this table.
There is an enum in MSP430ADC12M.h for the last four entries.

The value for the "adcPort"-parameter represents the reference voltage used 
for the input channel. The valid values are shown in the following table 
(analogous to the SREF-bits, User Guide 17-25):

adcPort | reference (see the device-specific datasheet)
-------------------------------------------------------
   0    | VR+ = AVcc   and VR-= AVss
   1    | VR+ = VREF+  and VR-= AVss
   2    | VR+ = VeREF+ and VR-= AVss
   3    | VR+ = VeREF+ and VR-= AVss
   4    | VR+ = AVcc   and VR-= VREF-/VeREF-
   5    | VR+ = VREF+  and VR-= VREF-/VeREF-
   6    | VR+ = VeREF+ and VR-= VREF-/VeREF-
   7    | VR+ = VeREF+ and VR-= VREF-/VeREF-

There is an enum in MSP430ADC12M.h for this table.
All other commands in ADCControl and ADC have the same meaning as specified in 
the interface definitions.
   
EXAMPLE: You use the MSP430F149 and have a photo resistor on P6.2, 
which is input channel A2. The resistor is also connected to VREF+ and AVss. Now 
you want a single 12-bit conversion done. First define a constant that 
represents your port in some enum: TOS_ADC_LIGHT_PORT = 2. 
Wire your module to the ADC interface with parameter TOS_ADC_LIGHT_PORT (in 
the configuration): MY_MODULE.ADC = ADCC.ADC[TOS_ADC_LIGHT_PORT];
Then initialize and bind your interface instance to your port settings, e.g. 
in your StdControl.init() write:

  call ADCControl.init(); 
  call ADCControl.bindPort(TOS_ADC_LIGHT_PORT, REFERENCE_VREFplus_AVss);

Where REFERENCE_VREFplus_AVss is defined in MSP430ADC12M.h.
When you now start a conversion by calling ADC.getData(), you will get 
an event "ADC.dataReady(uint16_t data)". The lower 12 bits of parameter "data" 
are the conversion result.
This assumes that at the time of conversion the voltage generator is switched on 
(otherwise VREF is invalid, see RefVoltC.nc).
There are a whole lot of settings for MSP430's ADC that are set to default 
values and cannot be modified with the ADCC (that's what MSP430ADC12C is for). 
These default settings are specified in MSP430ADC12M.h.



b) MSP430ADC12C 
This configuration provides three ADC12-related interfaces that give you access 
to the full functionality of MSP430's ADC12. Here is a short overview (see the 
interface definitions for details): 
 
1) MSP430ADC12Internal: This interface can be used to convert a signal 
on an internal input channel (see first table above, last four entries). Note, 
that the interface is not parameterized in MSP430ADC12C, i.e. a conversion 
result is signalled to all components wired to this interface regardless of who 
called getData(). If you want to use the integrated temperature sensor, make sure 
the voltage genererator is switched on (RefVolt component)!

2) MSP430ADC12External: This interface can be used to convert a signal 
on an external input channels (A0 to A7 in first table above). It is 
parameterized and should be used with unique("MSP430ADC12External"). Before the 
first conversion, bind() needs to be called to associate the interface instance 
with some settings:

  externalChannel:  The input channel A0=0 ... A7=7, (see first table above)  
  referenceVoltage: The reference voltage. It is used analogous to "adcPort" 
                    (see above, second table).  
  sampleHold: The Sample-hold-time (sample duration) in clock cycles.
              How to calculate this value is explained in the User Guide, 17-9 
              (by default this should be SMCLK, check MSP430ADC12.h).         
               

SampleHold | Clock Cycles
-------------------------------------------------------
   0       |    4
   1       |    8
   2       |   16
   3       |   32
   4       |   64
   5       |   96
   6       |  128
   7       |  192
   8       |  256
   9       |  384
  10       |  512
  11       |  768
  12       | 1024
  
There is an enum in MSP430ADC12M.h for this table.

Example: You use the MSP430F149 and have a photo resistor on P6.2, 
which is input channel A2. The resistor is also connected to VREF+ and AVss. 
First define a constant that represents your port in some enum: 
TOS_ADC_LIGHT_PORT = 2. Then bind your interface instance to the settings and 
start a conversion:

   MSP430ADC12StandardSettings_t settings = {
             externalChannel: TOS_ADC_LIGHT_PORT,
             referenceVoltage: REFERENCE_VREFplus_AVss, 
             sampleHoldTime: SAMPLE_HOLD_64_CYCLES
             };
             
   call MSP430ADC12External.bind(settings);
   call MSP430ADC12External.getSingleData(); // trigger conversion

After bind() has been called for any subsequent conversions done via the 
interface instance the settings will be used (regardless of the settings other 
interface instances have called bind() on). All settings other than passed in
bind(), e.g. clock source, will be the default settings as specified in 
MSP430ADC12.h. For all other commands read MSP430ADC12External.nc.

3) MSP430ADC12Advanced: This interface can be used to convert a signal 
on an external input channel (A0 to A7 in first table above) but allows you to 
specify more details for the conversion than MSP430ADC12External. The main 
advantage is, that it allows you to define time intervals in between 
conversions. E.g. you can specify to do a sequence of, say, 8 conversions 
converted with a 30ms pause in between conversions. After 7*30ms (the first 
conversion is done right away) you will get ONE event signalling that the 
conversions have finished and the results are stored at a predefined 
memory location.
The interface is used analogous to MSP430ADC12External: First the interface 
instance has to be bound to some settings, then conversions can be made. Read 
MSP430ADC12Advanced.nc.
