A Virtual Peripheral ADC: Using Bitstream A-to-D Conversion

Introduction

This application note presents programming techniques for reading an external
voltage by employing bitstream continuous calibration in order to create
a simple, inexpensive 8-bit 1 analog to digital converter with an input range
of 0-5V. This implementation uses the SX's internal interrupt feature to
allow background operation of the code as a virtual peripheral, and uses
the Parallax demo board, taking advantage of Parallax' SX demo software user
interface and UART features to allow the SX to communicate simply and directly
with a personal computer via a serial RS232C port.

How the circuit and program work

The circuit is a simple resistor capacitor network on each adc port pin (see
figure 1). Essentially, the program code calculates the charge vs. discharge
rates of the capacitor, according to the voltage (0-5V) applied to the
corresponding adc input. Port pins RC.5 and RC.7 are both inputs which trigger
when the capacitor is half charged. This is because, using mode register
function 0Dh in the initialization section of the main program code, port
pin input and outputs on port RC are set CMOS levels.

The interrupt code segment uses the bitstream continuous calibration approach
to calculate the capacitor charge/discharge timing. The method is a rather
unique one, which uses one port to monitor the capacitor level, and another
as an output to charge and discharge the capacitor to keep it hovering at
the input trigger level. The charging and discharging times depend on the
voltage being applied to the corresponding adc input, and hence by measuring
the charge time vs. (charge + discharge) time ratio, we can determine the
voltage present at the adc input. The resolution of such a method is proportional
to the calibration frequency, and due to circuit noise, the last few bits
( + 1 or 2 LSB's) must usually be thrown away.

Using adco as our example, the adc routine keeps count in the adc0_acc register
of the number of times the adc input (port pin RC.5) is triggered high during
256 passes through the interrupt (the count of the number of passes being
kept in the adc0_count register). The ratio of these two values gives
the proportion of Vcc present at the adc0 input.

In this implementation, a sample is taken as soon as adc0_count rolls
over from 255 to 0, whereupon the value contained in adc0_acc is copied
to adc0. This value, ranging from 0-255 *, directly corresponds to
an input voltage of 0-5 volts, with a value of 0 representing 0 volts and
a value of 0FFh representing 5V. It should be noted that with no input voltage
present the input floats around (or very near to) a value of 7Fh, though
slight offsets may result due to variations between what should be equal
values for the resistors R3 and R4.

The resistor capacitor combination shown allows sampling of the incoming
signal by the bitstream continuous calibration method described above, yet
it also draws current from the input source in order to maintain the calibration
at 0.5V dd . The effect of this is equivalent to having the input source
connected through R4 (in this case a 10kW resistor) to 2.5 volts, so current
drain considerations on the input source should be kept in mind.

2Due to Nyquist's theorem, useful information can
only be obtained for frequencies £ half of the sampling (or, in this
case, the calibration) frequency.

For adc0, SX port pin RC.6 is essentially acting like a auto-calibrating
pulse width modulation output which keeps the capacitor at 0.5V cc using
real-time feedback from port pin RC.7. This method for analog to digital
conversion is effective for inputs whose highest frequency component is lower
than half2 of the lowest frequency component of the calibrating
pwm signal.

3 With an input voltage just under 5 volts, the pwm
calibration output will only toggle high for 1 out of every 256 interrupt
passes. With the input at (or over) 5 volts, the calibration output will
remain low. For an input voltage slightly over 0 volts, the pwm calibration
output will toggle low only 1 of every 256 passes, and with the input at
(or below) 0V, the calibration output will remain high.

The length of the pwm cycle varies, depending upon the voltage of the input,
but the worst case is a pwm that toggles only once every 256 interrupt passes
3.

We can calculate the period between interrupt passes as follows:

The interrupt is triggered each time the RTCC rolls over (counts
past 255 and restarts at 0). By loading the OPTION register with the appropriate
value, the RTCC count rate is set to some division of the oscillator frequency
(in this case they are equal), which is the external 50 MHz crystal in this
case. At the close of the interrupt sequence, a predefined value is loaded
into the W register using the RETIW instruction, which determines the period
of the interrupt in RTCC cycles.

So, for the worst case of 256 interrupt passes, at a crystal frequency of
50 MHz, in turbo mode, with a prescaler of 1, and with an RETIW value of
163, the lowest frequency present in the pwm signal is:

4In practice, even signals at or near this frequency
will not sample with 8 bits of resolution.

By this we can see that the adc will be able to monitor signals at or
below4 fadc_max = 1.2kHz / 2 = 600 Hz.

5For signals that vary within a minimal range about
the 1/2Vdd calibration point, higher frequencies may be successfully
monitored.

At frequencies above5 this, not only will the adc begin to provide
inaccurate information, but there will also be an increasing current drain
on the incoming signal as the impedance to ground of the RC combination
decreases.

Since timing is critical for accurate readings, all efforts should be made
to make sure that any code executed in the interrupt prior to the adc code
section maintains a uniform execution rate at all times. This can be done
by placing it before any varying-execution-rate, state-dependent code (it
should always come before the UART, for instance).

Modifications and further options

The Parallax demo board is designed so that port pins pwm0 and
pwm1 can be swapped for adc's simply by adjusting the program code
to remove the pwm interrupt section, adding code to the :adcs section
such that adc2 and adc3 use port RC pins for pwm0 and
pwm1, respectively, and by adjusting the register definitions
appropriately. An example of the code follows:

After you find an appropriate page, you are invited to
your
to this massmind site! (posts will be visible only to you before review)
Just type in the box and press the Post button.
(HTML welcomed, but not the <A tag:
Instead, use the link box to link to another page.
A tutorial is availableMembers can
login
to post directly, become page editors, and be credited for their posts.

Link? Put it here:
if you want a response,
please enter your email address:
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.