Data Acquisition Using Analog to Digital Conversion
Using the QVGA Controller for precise analog measurement and data logging
This page shows how to use the 24 channels of analog input/output on the QVGA Controller including its high performance 8-channel 12-bit analog to digital (A/D) converter. The 12-bit A/D can be configured to convert 8 channels of single-ended inputs or 4 channels of differential signal inputs, or combinations of single-ended and differential signals. The input voltages can be unipolar, with a range from 0 to 5 volts, or bipolar, with a nominal range from -5 to +5 volts. This voltage range can be adjusted using low and high reference voltages. The demonstration code for this chapter in the ANALOGIO.C file also shows how to use C arrays and FORTH_ARRAYS as buffers, and describes how to store semi-permanent information in the QVGA Controller’s Electrically Erasable PROM (EEPROM).
This document describes the analog I/O devices available on the QED Board, explains how to connect the converters to external signals, and details the built-in driver routines that make analog I/O easy to use. Simple code is presented to calculate measured voltages based on A/D readings and to calculate the digital values required to instruct a DAC to output a specified voltage. At the end of the chapter, sample circuitry and code is presented to convert a pair of 8 bit DACs into a high resolution DAC.
Data acquisition using the QVGA controller
Many instrument applications require monitoring of analog signals and generation of analog control voltages. Analog to digital (A/D) converters and digital to analog converters (DACs) can perform these functions. An A/D converter samples analog signals and converts them to digital values that can be stored, processed, or displayed. A DAC generates an analog voltage whose value is proportional to a specified digital number.
The resolution of an A/D or DAC is specified in bits. For example, an 8-bit DAC can output any of 28 or 256 distinct analog levels; 256 is the maximum number of levels representable by an 8 bit binary number. Similarly, a 12-bit A/D converts an analog signal into one of 4096 discrete digital numbers.
Available Analog I/O Lines | |||
---|---|---|---|
I/O Lines | Type | Port Address | Comments / Alternate Uses |
8 | 8-bit 0-5 V analog inputs | PE 0-7 | Alternately may be used as digital inputs. |
8 | 12-bit analog inputs | 8 channels single-ended or 4 channels differential, unipolar (0-5 V) or bipolar (±5 V). | |
8 | 8-bit analog outputs | Multiplying, cascadable, 0-3V output DACs. | |
24 | Analog I/O lines |
The QVGA Controller hosts both analog to digital and digital to analog converters to address a wide variety of instrumentation and control applications. It includes three 8-channel analog I/O devices:
- An 8-channel 8-bit analog to digital (A/D) converter that is built into the 68HC11 processor chip converts unipolar signals with a nominal 0 to +5 volt range;
- An 8-channel 12-bit A/D converter; and,
- An 8-channel 8-bit digital to analog converter (DAC), discussed in the next Chapter.
The 16 analog inputs and 8 analog outputs are brought out to a 40 pin analog connector (H2) on the QED-Flash Board (the smaller of the two boards of the QVGA Controller); the connector diagrams in an Appendix [pkc2]specify the pin assignments.
The 8 bit A/D converter
The 8 bit A/D converter in the processor converts unipolar signals with a nominal 0 to +5 volt range, and conversion results are returned in registers in the 68HC11. The analog inputs are connected to the PORTE pins on the processor; these can be used as digital inputs if the 8 bit A/D is disabled.
The 12 bit A/D converter
The 12 bit A/D converter is interfaced to the processor via the fast serial peripheral interface (SPI). Its chip select is a memory-mapped signal generated by the onboard logic. The 12 bit A/D can be configured to convert 8 channels of single ended inputs or 4 channels of differential signal inputs, or combinations of single-ended and differential signals. The input voltages can be unipolar, with a range from 0 to 5 volts, or bipolar, with a nominal range from -5 to +5 volts. This voltage range can be adjusted via the low and high reference voltages named VRL and VRH.
Examining the demonstration program
The code discussed in this section is located in the file named ANALOGIO.C
in the \MOSAIC\DEMOS_AND_DRIVERS\MISC\C EXAMPLES
directory. Most of the functions in this file are interactive versions of functions declared in the ANALOG.H
file in the \MOSAIC\FABIUS\INCLUDE\MOSAIC
directory; they are described in detail in the Control-C Glossary.
We recommend that you compile and download the ANALOGIO.C
program now so that you can interactively work through the exercises in this chapter. Simply use your TextPad editor to open ANALOGIO.C
, and click on the Make Tool (the Make icon) to create the download file named ANALOGIO.DLF
. Then enter the Mosaic Terminal program, and type:
WARM↓
or:
COLD↓
to terminate any prior multitasking program that might be running, and select the "Send Text File" menu item to send ANALOGIO.DLF
to the QVGA Controller.
Fundamentals of analog to digital conversion
An analog to digital converter samples an analog signal and outputs a digital number that is proportional to the analog signal. The A/D converters on the QVGA Controller sample input voltages and communicate the digital result to the 68HC11 processor.
The analog input signal must be within the input range of the A/D converter. On the QVGA Controller, the lower bound of the range is equal to the voltage on VRL (voltage reference/low) and the upper bound of the allowable input range is equal to the voltage on VRH (voltage reference/high). The VRL and VRH references are brought out to the 40 pin Analog I/O connector and control the input voltage range of both the 8 bit and 12 bit A/D converters. Their default values are 0 Volts (analog ground) and 5.0 Volts (analog +5V), respectively. They can be driven to different voltages by external circuitry as described below.
The converter measures the input voltage with a certain specified resolution. The resolution is the granularity with which the measurement is performed. It can be specified as a number of bits or as a voltage increment. For example, an A/D converter with only 1 bit of resolution and a 5 Volt input range would classify all voltages from 0 to just under 2.5 Volts as the digital value 0, and voltages from 2.5 Volts to 5 Volts as the digital value 1. This converter has a resolution equal to 1 bit, which corresponds to 2.5 Volts per count.
The converter measures the input voltage with a specified accuracy. The accuracy tells how close the measured value is to the actual voltage. A typical 8 bit A/D converter is accurate to within plus or minus one least significant bit.
Determining the resolution of an A/D converter
The VRL and VRH analog input reference pins define the lower and upper voltages that can be converted by both the 8 bit A/D and the 12 bit A/D. The resolution depends on the input voltage range. The measurement resolution of a B-bit A/D, expressed in Volts per count, is
Resolution = (VRH - VRL) / 2B [Volts per count]
where 2B is the number of counts that can be represented by a B-bit number. From this equation we see that resolution becomes finer (better) as B grows larger or as the reference voltage range (VRH - VRL) gets smaller. For the 8 bit A/D the resolution is
8 bit Resolution = (VRH - VRL)/256 [Volts per count]
and for the 12 bit A/D the resolution is
12 bit Resolution = (VRH - VRL)/4096 [Volts per count]
With the default VRL and VRH of 0 V and 5 V, respectively, the resolution of the 8 bit converter is 19.5 mV per count, and the resolution of the 12 bit converter is 1.22 mV per count. The finer resolution of the 12 bit converter combined with its higher accuracy yields a more precise measurement of the analog input.
Converting an A/D count into a voltage
To convert the 8-bit count returned by the A/D converter into an equivalent voltage, use the formula
Input Voltage = VRL + ( Count * Resolution)
Combining this with the above expression for resolution yields,
Input Voltage = VRL + Count * (VRH - VRL) / 2B
This conversion function for the 8-bit A/D is illustrated in the following graph:
Using the 8-bit A/D
Initializing the 8-bit A/D
The 8 bit A/D is inside the 68HC11 processor chip, and is accessed via PORTE . This 8 bit port can be used as either an 8 channel A/D or as an octal digital input port. When the QVGA Controller is first powered up, or after a reset or restart, the 8 bit A/D converter is disabled and PORTE is configured as a digital input port. To turn on the A/D converter, a program must call the function:
AD8On()
Another function named AD8Off() is available to turn off the 8 bit A/D so that PORTE once again acts as a digital input port.
The function named
InitAnalog()
defined in the ANALOGIO.C
file calls AD8On() . If you interactively execute InitAnalog()
, as,
InitAnalog( )↓
the 8 bit A/D converter will be turned on and ready for use.
In an autostarting application you should include InitAnalog()
in your start-up code.
Hardware connections
To sample an analog voltage, attach a voltage with a value between zero and +5 Volts to the 8 bit A/D channel 0 input named AN0
. For example, try connecting the 1.5Vref signal (pin 37 on the Analog I/O connector) to the AN0
input (pin 10 on the Analog I/O connector). See tbe Appendix for connector diagrams.
The 8 bit A/D inputs are the PortE signals named PE0/AN0 through PE7/AN0 available at pins 3 through 10 on the Analog I/O connector (see Appendix A). Each analog signal is converted to a number between 0 and 255 indicating its value relative to VRL (the low voltage reference) and VRH (the high voltage reference). The default values are VRL = 0 Volts (analog ground) and VRH = 5 Volts (the analog +5 Volt supply, designated +5VAN). The exact voltage difference between VRH and VRL varies slightly from board to board; it is a good idea to measure the value on your board to obtain the most exact voltage equivalents of the measured A/D results.
8-bit A/D reference voltage
You may connect circuitry to the VRL and VRH pins to drive these references to desired levels between 0 and 5 Volts. For example, in some applications it may be possible to increase the resolution of the conversion by reducing the input voltage range (VRH-VRL) as specified by Figure 9-1.
Motorola’s data books specify some restrictions on the values of the reference signals VRL and VRH (MC68HC11F1 Technical Data Manual, p.13-10) for the 8 bit A/D. First, VRL and VRH must be less than +5.1 Volts and greater than 0 Volts. Second, the voltage on VRL must be less than the voltage on VRH. Third, the difference between the voltages, (VRH - VRL), should be greater than 3 Volts if the converter is to meet all of its stated specifications. Also note that VRH and VRL are connected to both the 8 bit A/D and the 12 bit A/D, so changing the references affects both converters.
Interactively perform the conversion
The Convert8()
function is defined near the middle of the ANALOGIO.C
file; you can see from its definition that it is simply an interactively callable version of the AD8Sample() function. Now that you have connected an input voltage to channel AN0
, you can type from your terminal:
Convert8( int 0)
The printed return value summary displays the conversion count; you’ll see a printout that looks something like this:
Rtn: -30722 77 =0x87FE004D =fp: -3.822E-34
We know that this function returns an integer, so we identify "77" (hex 0x004D) as the return value; the other numbers in the summary are irrelevant. If the input is 1.5 volts, the result should be approximately 77 counts (256 * 1.5 / 5.0). If the input voltage equals VRL (the low reference voltage, typically at 0 Volts), the result will equal 0. If the input is within 1 bit of VRH (the high reference voltage, typically at 5.0 Volts), the result will equal decimal 255. If the input is exactly half of (VRH - VRL), the result will equal decimal 128.
Multiple 8-bit A/D conversions with results xtored into a C array
The function AD8Multiple() which is defined in the ANALOG.H
file expects as inputs a buffer xaddress (32 bit extended address), a sampling interval parameter, the number of samples, and a channel number. When called, it performs the specified number of conversions and saves the results as single bytes in the specified buffer. As explained in the Glossary, the sampling interval parameter specifies the timing of the samples, with 0 representing the fastest sampling, and 65,535 representing the slowest sampling. You can sample at up to 100 kHz (100,000 samples per second) using the 8-bit A/D, and sample at up to 36 kHz using the 12-bit A/D, provided the processor is devoted to this single task.
The AD8ToCArray()
function defined in ANALOGIO.C
uses a standard C one-dimensional array named results_8
as the data buffer. The function accepts a channel number as input, performs conversions at the fastest sampling speed (100 kHz), and places the results in the array. The number of samples is specified by the DEFAULT_NUMSAMPLES
constant which equals 16. Because we have connected the channel 0 input (AN0) to 1.5VREF, let’s perform the multiple conversion on this channel. Type at your terminal:
AD8ToCArray( int 0)↓
remembering to type at least one space after the ( character. This function does not return a value, so the printed return value summary is not relevant. To see the results of the conversion, you could write a simple C function that prints the contents of results_8
; this is left as an exercise for you. You can also use the debugging routine named DUMP to view a hexadecimal dump of the buffer. To do this, type at your terminal:
results_8 0 16 DUMP↓
DUMP is a QED-Forth function that expects as inputs an address (in this case, results_8
puts the address on the data stack), a page (0, representing the common page), and the number of bytes to be dumped (16). You should see a printout similar to this:
pg addr 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF 00 8E2D 4D 4D 4D 4D 4D 4D 4D 4D 4D 4D 4D 4D 4D 4D 4D 4D MMMMMMMMMMMMMMMM
This tells us that the contents of the 16 bytes starting at address 0x8E2D (which is the address of results_8)
all equal 0x4D. To the right of the hex dump the ascii equivalent of the memory contents is displayed; this is not relevant for the numerical data here. We conclude that the A/D conversion result was 0x4D, equivalent to decimal 77; this is the same value returned by the Convert8()
function above. Your results may vary slightly depending on the exact value of supply voltage on the QVGA Controller – the +5V supply is used as the default reference voltage.
For experts: using additional features of the 8-bit A/D
The built-in driver routines for the 8 bit A/D are easy to use and address the requirements of most applications. If you wish to gain a detailed understanding of the operation of the 8 bit A/D, or need to use one of its special modes, the information in Appendix H may prove useful. For example, one of the operating modes allows the 8 bit A/D converter to continuously sample four different analog inputs in rapid succession. Appendix H describes the operation of the 68HC11’s A/D and presents sample code to control the 8 bit A/D.
Using the 12-bit A/D
Initializing the 12-bit A/D
The 12-bit A/D is interfaced to the 68HC11F1 via the high speed serial peripheral interface (SPI). The function:
InitAD12andDAC()
initializes the SPI to be compatible with operation of the 12-bit A/D and the digital to analog converter (DAC).
To initialize the hardware now so that you can interactively perform conversions, type the following command lines at your terminal:
DECIMAL ↓ InitEEChar( char 10, numsamples)↓ InitAnalog( )↓
Remember to include a space after each ( character. The first command ensures that the number base is decimal, and the second command initializes a variable located in the EEPROM which specifies the number of 12 bit samples stored in the FORTH_ARRAY buffer; this will be discussed in more detail later in the chapter. The InitAnalog( )
function calls InitAD12andDAC() , and also dimensions and zeros some buffers that will hold A/D conversion results.
Specifying the conversion type
The function
AD12Sample( int flag, uint channel)
expects a configuration flag and a channel number as inputs, performs a single conversion using the 12 bit A/D, and returns the conversion result. The meaning of the flag is as follows:
Flag value | Type of conversion |
---|---|
-1 | single ended, unipolar |
0 | differential, unipolar |
1 | single ended, bipolar |
2 | differential, bipolar |
Hardware connections
To sample an analog voltage, attach a ground-referenced voltage in the range between zero and +5 Volts to the 12 bit A/D channel 0 input named 12AN0
. For example, try connecting the 1.5Vref signal (pin 37 on the Analog I/O connector) to the 12AN0
input (pin 18 on the Analog I/O connector). See the Appendix for connector diagrams, and see Figure 1-3 in Chapter 1 to identify the Analog I/O connector on the QVGA Controller.
If the input voltage equals VRL (the low reference voltage, typically at 0 Volts), the result will equal 0. If the input is within 1 bit of VRH (the high reference voltage, typically at 5.0 Volts), the result will equal decimal 4095. If the input is exactly half of (VRH - VRL), the result will equal decimal 2048. If the input is 1.5 volts, the result should be approximately 1230 counts.
To provide a default 0 to 5.0 Volt conversion range, the VRL and VRH references are tied to AGND and +5VAN through 1 kohm resistors; while this is fine for casual testing as we’re doing now, you’ll want to make the following connections for your actual design project:
To achieve full 12 bit accuracy, you must connect the low reference VRL signal and the high reference VRH signal to low-impedance supplies such as Analog Ground (AGND) and Analog +5V (+5VAN), respectively. This is accomplished by connecting VRL (pin 1) to AGND (pin 19), and connecting VRH (pin 2) to +5VAN (pin 20) on the Analog I/O connector of the QED Board.
Interactively perform the conversion
The Convert12()
function is defined near the top of the ANALOGIO.C
file. It is defined using the _Q specifier so that it can be interactively called from your terminal. Convert12()
simply calls the conversion function AD12Sample() with the specified channel number and a flag = -1 (meaning that a single-ended unipolar conversion is performed). Now that you have connected an input voltage (1.5Vref) to channel 12AN0, you can interactively type from your terminal:
Convert12( int 0)↓
As usual, remember to include a space after the ( character. The printed return value summary displays the conversion count; you’ll see a printout that looks something like this:
Rtn: -30722 1237 =0x87FE04D5 =fp: -3.822E-34
We know that this function returns an integer, so we identify "1237" as the return value. (In hexadecimal notation, this is 0x04D5 which is the lower half of the hexadecimal summary value; the other numbers in the return value summary are irrelevant.) If the input is 1.5 volts, the result should be approximately 1230 counts. If the input voltage equals VRL (the low reference voltage, typically at 0 Volts), the result will equal 0. If the input is within 1 bit of VRH (the high reference voltage, typically at 5.0 Volts), the result will equal 4095. If the input is exactly half of (VRH - VRL), the result will equal 2048.
Multiple 12-bit A/D conversions with results stored into a FORTH ARRAY
The function AD12ToBuffer() which is defined in the ANALOG.H
file expects as inputs a pointer to a FORTH_ARRAY, a sampling interval parameter, the number of samples, a conversion-type flag, and a channel number. When called, it performs the specified number of conversions and saves the results as integers in the specified FORTH_ARRAY. As explained in the Control-C Glossary, the sampling interval parameter specifies the timing of the samples, with 0 representing the fastest sampling, and 65,535 representing the slowest sampling. The conversion-type flag is the same as the flag for AD12Sample() as described above:
Flag value | Type of conversion |
---|---|
-1 | single ended, unipolar |
0 | differential, unipolar |
1 | single ended, bipolar |
2 | differential, bipolar |
The AD12ToForthArray()
function defined in ANALOGIO.C
is an interactive version of AD12ToBuffer() . It accepts a channel number as input, performs unipolar conversions at the fastest sampling speed, and places the results in the FORTH_ARRAY named results_12
. The number of samples is specified by the variable named
numsamples
which is located in EEPROM. You’ll remember that when we initialized the 12-bit A/D we also initialized numsamples = 10
, with the statement,
InitEEChar( char 10, numsamples)↓
so we expect that 10 samples will be stored in the results_12 array
. Because we have connected the channel 0 input (12AN0) to 1.5Vref, let’s perform the multiple conversion on this channel. Type at your terminal,
AD12ToForthArray( int 0)↓
remembering to type at least one space after the ( . This function does not return a value, so the printed return value summary is not relevant. To see the results of the conversion, we can print the contents of the results_12
array by typing from the terminal:
PrintForthArray( int 0, results_12)↓
where results_12
is the name of the FORTH_ARRAY to be printed, and the 0 parameter is a flag that tells the function that the results_12 array
does not contain floating point data. You should see the conversion results printed as a column of data on your terminal screen.
Bipolar conversions
You can instruct the 12-bit A/D to interpret the input as a unipolar signal in the range 0-5 volts, or a bipolar signal in the range -5 to +5 volts. Even without an external negative supply, voltages as low as -4.0 or -4.5 V can be converted. This is achieved by using a negative voltage generator on the Maxim RS-232 chip. This negative voltage is connected to the V- supply input of the 12 bit A/D chip, and is also accessible at pin 39 on the Analog I/O connector, labeled "Analog Bus V-". Drawing current out of this "Analog Bus V-" pin to power external circuitry is not recommended, as the RS-232 chip cannot source much current, the output impedance is hundreds of ohms, and the voltage is poorly regulated. Instead, to achieve clean rail-to-rail -5.0 V to +5.0 V conversions, connect an external -5 V supply to "Analog Bus V-" at pin 39 on the Analog I/O connector.
The drivers for the 12-bit A/D converter are:
FastAD12Sample() AD12Sample() FastAD12Multiple() AD12 Multiple ()
The configuration flag passed to these routines lets you select unipolar or bipolar conversion as discussed above, in addition to single-ended (ground-referenced) or differential conversions.
Running the sample program
We have worked through much of the ANALOGIO.C
file. Its routines that use the digital to analog convertor (DAC) to output voltages are discussed in the next Chapter[pkc6], and its use of EEPROM to store nonvolatile variables is discussed in the Chapter Making Effective Use of Memory[pkc7].
Let’s run the program, which both acquires data an outputs a voltage. If you have a valid voltage input such as 1.5Vref (pin 37 on the Analog I/O connector) attached to 12AN0 (pin 18), AN0 (pin 10), and Vin1 (pin 21), then the main
function will work properly. To initialize the analog converters, acquire multiple samples from channel 0 of each A/D, and to establish 2.5 volts at the output of DAC channel 1, simply type:
main↓
at your terminal. The function prints the results of the multiple 12 bit conversions, and you can check the DAC channel 1 output with your voltmeter. To change the number of samples acquired from the 12 bit A/D to 20, you can interactively type:
DECIMAL InitEEChar( char 20, numsamples)↓
which modifies the contents of the numsamples
variable in EEPROM. When you again execute
main↓
you will notice that 20 values are now printed at your terminal.