\documentstyle[11pt]{article}

\setlength{\oddsidemargin}{-5mm}
\setlength{\evensidemargin}{-5mm}
\setlength{\parindent}{0mm}
\setlength{\parskip}{2mm}
\setlength{\footskip}{1.5cm}
\setlength{\textwidth}{16cm}
\setlength{\textheight}{22cm}
\setlength{\headheight}{0cm}
\setlength{\topmargin}{0cm}

\begin{document}

\begin{center}
{\Large ANALOG I/O BOARD FOR PC'S}
\end{center}
\vspace{2mm}
\begin{center}
Jos Groot (InterNet: jos.groot@fel.tno.nl) \\
September 24, 1992
\end{center}
\vspace{10mm}

This note describes how to build a low cost extension board containing an 
analog-to-digital (ADC) and a digital-to-analog (DAC) converter,
for use in a standard PC XT extension slot. The board utilizes the
8-bit AD7569 IC, containing a 1 $\mu$s DAC, a 2 $\mu$s 
ADC and a track/hold circuit with 200 kHz bandwidth. The part
costs amount to 80-100 US\$, approximately. The board can for example be used
to sample sound with the ADC and play it back through the DAC, possibly after 
some `on-the-fly' digital signal processing. Example Turbo Pascal routines for
programming the board are included in this description, of which two implement
electric guitar sound effects.

\section{Operation}

This part explains how the card operates (see accompanying electronic
diagram contained in the ADDA10.ZIP archive).

\subsection{Buffering}

The card is put in a standard 62-contact XT extension slot. The slot
is drawn in the upper left of the diagram.

The data lines SD0-SD7 are buffered by a bidirectional 3-state 74LS245.
The buffer direction is determined by the DIR input connected to
$\overline{\rm IOR}$ of the slot. It is from B to A during
an I/O read ($\overline{\rm IOR}$=DIR low), and from A to B during an I/O
write ($\overline{\rm IOR}$=DIR low). Both ports are in a high-impedance state
(virtually disconnected from the circuit) when their is no access to the card.

The control lines $\overline{\rm IOR}$, $\overline{\rm IOW}$,
RESET and AEN are buffered by the unidirectional 3-state buffer 74LS244. It is
always enabled because $\overline{\rm 1G}$ en $\overline{\rm 2G}$ are
low.

The address lines SA2-SA9 are unbuffered because these are only loaded by
the 8-bit 74LS688 comparator. The unbuffered address lines SA0 en SA1 are
loaded by 2 Schottky TTL loads each, while a maximum of 1 is recommended.
This will cause no problems in general, certainly not when not all extension 
slots are used.

\subsection{Address decoder}

The address decoder section consists of an 8-bit comparator 74LS688, a
74LS02 containing 4 NOR gates and a 74LS139 containing 2 2-to-4 decoders 
(A and B). The address lines SA2-SA9
constitute an 8-bit input byte compared by the 74LS688 to a second
byte determined by an 8-fold dipswitch. This selects the base 
of the 4-byte I/O address space of the card. It can be \$0, \$4, \$8, \$C etc. 
The addresses \$300-\$31F are reserved for a prototype card. The base address
\$300 (binary 11,0000,0000) is selected with bits 1100,0000 for connections
1,2,$\ldots$,8 of the dip-switch. In the remainder this base address
will be assumed. The enable input $\overline{\rm G}$ of the comparator is 
connected to the AEN line. This accomplishes that the card is not selected
during DMA transfers.

On selection of one of the addresses \$300 $\ldots$ \$303 the 74LS688 output
$\overline{\rm P=Q}$ becomes low. This line is input to the two NOR gates
A and B of the 74LS02. The truth table of a NOR gate is:

\begin{table}[h]
\centering
\begin{tabular}{|c|c|c|} \hline
X & Y & $\overline{\rm X+Y}$ \\ \hline
0 & 0 & 1 \\
0 & 1 & 0 \\
1 & 0 & 0 \\
1 & 1 & 0 \\ \hline
\end{tabular}
\caption{NOR gate truth table}
\label{tab:nor}
\end{table}

A NOR gate with X=Y acts like an inverter. It follows that the enable
$\overline{\rm G}$ of the A-part (B-part) of the decoder 74LS139 is
low when both inputs of 74LS02A(B) are low. This happens when one of the
addresses \$300 $\ldots$ \$303 is selected, while at the same time 
$\overline{\rm IOR}$ ($\overline{\rm IOW}$) is low. Because SA0 and SA1
are connected to the A and B inputs of the decoders, $\overline{\rm Y0}, 
\overline{\rm Y1}, \overline{\rm Y2}$ or $\overline{\rm Y3}$ of the
74LS139A(B) will become low during an I/O read (write) operation on
\$300 $\ldots$ \$303, respectively. So only one of the eight
decoder outputs is low at a time. The remaining seven output are high.

\subsection{AD7569 converter}

The AD7569 contains an ADC and a DAC. The jumpers JP1 and JP2
are used to select the range and data format of both converters, according
to the next table.

\begin{table}[h]
\centering
\begin{tabular}{|c|c|l|l|} \hline
JP1 (RANGE) & JP2 (V$_{ss}$) & voltage range & DB0-DB7 data format \\ 
\hline
0 V & 0 V  & 0 $\rightarrow$ +1.25 V     & binary \\
5 V & 0 V  & 0 $\rightarrow$ +2.5 V      & binary \\
0 V & -5 V & -1.25 $\rightarrow$ +1.25 V & 2s complement \\
5 V & -5 V & -2.5 $\rightarrow$ +2.5 V   & 2s complement \\ \hline
\end{tabular}
\caption{Selectable voltage ranges and data formats}
\label{tab:ranges}
\end{table}

The inverted RESET of the XT bus is connected to the AD7569's
$\overline{\rm RESET}$ input. The clock (CLK) is connected to an
RC circuit, enabling the conversion frequency to be adjusted with the
variable 10K resistor. A value of 6.8 k$\Omega$ corresponds to an
AD conversion time of $\approx 2\ \mu$s. The analog input and output
voltage are connected to a 9-pin hooked SUB-D connector.

\subsubsection{DA conversion}

The 74LS08A AND port enables the AD7869 by making input $\overline{\rm CS}$
low as soon as a read or write takes place on address \$301. A DA conversion 
is initiated by writing a byte to \$301, because
$\overline{\rm Y1}$ of the 74LS139A decoder is tied to the $\overline{\rm WR}$
line of the converter.

\subsubsection{AD conversion} 

Reading a byte from \$301 starts an AD conversion, because the 
$\overline{\rm RD}$ and $\overline{\rm ST}$ (start conversion) lines become low
simultaneously. The byte obtained from the next read (more than 
$\approx$ 2 $\mu$s later) is the conversion result, and a new conversion
is started immediately. This works out because the result of an AD conversion 
is stored in a latch on the AD7569. Only after completion of the next 
conversion the latched result is replaced by the new result.

The least significant bit of the byte read from \$300 is the by the 74LS240B 
inverted $\overline{\rm BUSY}$ signal of the AD7569. So bit 0 of address
\$300 becomes 0 upon completion of an AD conversion. The 3-state 74LS240B 
is enabled (puts its data on the bus) as soon as a read from \$300 takes place.

\clearpage
\section{Construction}

I built the circuit on a double sided full length card for an XT slot
(62 contacts), with 3-hole copper patches. A card like this, eventually
including buffering and address decoding circuitry, is also called a prototype
card. Included in the ADDA10.ZIP archive is a board layout sketch, showing the 
approximate IC positions (if I should build the board a second time, I would
shift the whole setup to the right, creating more space for input signal
shaping circuitry close to the connector).
I wire-wrapped the board. Because the holes in 
the card were too large for standard wire-wrap pins I used parts of 36-pins 
rectangular SIL blocks. The circuit occupies about one third of the card space,
leaving plenty of room for the addition of a programmable amplifier, a 
multiplexer or analog signal shaping circuitry (e.g., filters). These 
additional components can be programmed from the unused I/O addresses \$302 and
\$303.

To minimize noise, correct grounding is important. The AD7569 has one digital 
ground (DGND), and two analog ones ($\rm AGND_{DAC}\ and\ AGND_{ADC}$). These
have to be connected to each other as close to the IC as possible. The
common connection is called "STAR GND" in the diagram. This prevents the 
fluctuating supply current from influencing the 
$\rm AGND_{DAC}\ and\ AGND_{ADC}$ grounds. Other connections to the analog 
grounds are made directly to the pins. It is possible that using IC's from
the HCT instead of the LS series reduces noise because of the much reduced 
power consumption.

The 5 V power supply is decoupled to ground in some places with 100 nF ceramic
capacitors, and all unused inputs are tied low.

\subsection{Component list}

\begin{tabbing}
{\it Resistors:} \hspace{7mm} \=  8-fold 10K, 2 $\times$ 10K, potmeter 10K \\
{\it Capacitors:}   \>  68 pF, 4 $\times$ 100 nF (ceramic) \\
{\it Digital IC's:} \> 74LS02, 74LS08, 74LS139, 74LS240, 74LS244, 74LS245,
74LS688 \\
{\it Linear IC's:}  \>AD7569 JN \\
{\it IC sockets:}   \> 2 $\times$ 14-pins, 16-pins, 4 $\times$ 20-pins,
24-pins \\
{\it Miscellaneous:} \> 8-fold dip-switch, 6 $\times$ 36-pins rectangular
SIL block, 2 $\times$ 3-pins jumper, \\
                     \> 9-pins hooked SUB-D connector, 
1 $\times$ prototype card, wire-wrap wire
\end{tabbing}

I paid about 100 US\$ for the complete board (prototype card 30 US\$, 
AD7569 20 US\$, SIL blocks 20 US\$, remaining parts 30 US\$). Soldering instead
of wire-wrapping saves the costs of the SIL blocks, reducing the costs to 
80 US\$. The prices are computed with an exchange rate of 1.70 Dutch guilders
per US\$.

\clearpage
\section{Programming examples}

All the figures quoted below were obtained from measurements with a
33 MHz 80386 based PC with its ISA (AT) I/O bus running at 11 MHz. The
card was operated with the -1.25 $\rightarrow$ 1.25 V range. The 
corresponding 2s complement format (see Table \ref{tab:ranges})
is the same as that of a Turbo Pascal ShortInt. 

The programming examples are taken from the Turbo Pascal 6.0 source ADDA.PAS 
included in the ADDA10.ZIP archive. The part defining global constants and 
variables is:

\begin{verbatim}
program ADDA(Input, Output);

{ This program is to be used in conjunction with the analog extension
  board described in the note "ANALOG I/O BOARD FOR PC'S". It is assumed
  that the AD7569 is operated in one of its two bipolar modes (-1.25 V --> 
  +1.25 V or -2.5 V --> +2.5 V). }

uses Dos, Crt, Graph;

const Title= 'ADDA V1.0 - Jos Groot (September 19, 1992)';

{$R-} { this prevents Turbo Pascal from complaining about putting a Byte
        into a ShortInt type variable }

const Status = $300 ;  { bit 0 is 1 when an AD conversion is going on and
                        becomes 0 upon completion of the conversion }
      ADC    = $301 ;  { read : get result of most recently completed AD
                        conversion and start the next }
      DAC    = ADC  ;  { write: start DA conversion }
      Max_Sam= 60000;  { maximum number of samples }

var Buf: array[0..Max_Sam] of ShortInt; { global array receiving samples }
\end{verbatim}

\subsection{Basic use}

The card is very simple to use as can be seen from the next procedure which
takes a number of samples:

\begin{verbatim}
procedure Get_Samples(Samples: Word);

{ reads as fast as possible samples 0,1,...,Samples into array Buf. Sample
  Buf[0] should not be used, because this is the ADC result of a conversion
  started at an unknown earlier time. }

var i: Word;
    Pause: Integer;

begin
  for i:= 0 to Samples do { start at 0, 1 is the first good sample to use }
  begin
    asm   { small delay to enable the ADC to complete a conversion before  }
      nop { reading the result. The necessity and length of this delay may }
      nop { vary for different AD7569's. }
    end;

{   for Pause:= 1 to 50 do; } { add this loop to decrease sampling frequency }

    Buf[i]:= Port[ADC] { get and store sample & initiate next conversion }
  end
end;
\end{verbatim}

This procedure accomplishes a sample frequency of about 440 kHz (the AD7569 
datasheets guarantee the maximum sampling frequency
to be between 385 and 625 KHz with the internal clock, and at least 500 kHz
with an external clock). In still faster systems or machinecode routines one 
can test bit 0 of port \$300 to check for conversion completion. During 
conversion this bit is 1, upon completion it becomes 0.

A procedure to copy the ADC input to the DAC is:

\begin{verbatim}
procedure ADC_To_DAC;

{ reroutes ADC input directly to DAC output }

begin
  repeat
    Port[ADC]:= Port[DAC]
  until KeyPressed
end;
\end{verbatim}

\subsection{Digital guitar effects}

I used the following setup for experiments with real time digital signal 
processing to produce the `guitar effects' distortion/compression and 
echoing:

{\it electric guitar $\rightarrow$ pre-amplifier $\rightarrow$ ADC input 
$\rightarrow$ PC + Turbo Pascal program $\rightarrow$ DAC output $\rightarrow$
guitar amplifier}

Care should of course be taken that the maximum ratings of the ADC, the guitar
amplifier input etc. are not exceeded. The procedures are:

\begin{verbatim}
procedure Distortion;

{ reads ADC values, and outputs 100 to the DAC for the ones with absolute
  value>= Clip_Level. This produces a compressed and heavily distorted
  sound. }

const Clip_Level= 10; { should at least exceed the maximum value of absolute
                        noise samples }

var s: ShortInt;
    Table: array[-128..127] of ShortInt; { lookup table for fast execution }

begin
  for s:= -128 to 127 do
    if s>  Clip_Level then Table[s]:= 100 else
    if s< -Clip_Level then Table[s]:= 100 else { -100 for softer distortion }
                           Table[s]:= Abs(Round(s/Clip_Level*100));

  repeat
    Port[DAC]:= Table[ShortInt(Port[ADC])]
  until KeyPressed
end;

{ ******* }

procedure Echo;

{ produces an echo by adding ADC samples from some time ago to the present
  samples, and outputting the result to the DAC }

var i, j, d: Word;
    k, s, Pause, Buffers: Integer;
    Table: array[-128..127] of Integer; { lookup table for fast execution }
    Dr: Real;

begin
  Pause  := 20   ; { Pause determines the sampling frequency (40 kHz)       }
  d      := 20000; { d and Pause determine the delay time (20E3/40E3=0.5 s) }
  Dr     := 0.5  ; { Dr is inversely proportional to the decay rate         }
  Buffers:= 0    ; { number of Max_Sam byte Buffers processed               }

  for i:= 0 to Max_Sam do Buf[i]:= 0;            { clear buffer }
  for k:= -128 to 127 do Table[k]:= Round(Dr*k); { fill table }

  WriteLn; WriteLn; WriteLn;
  Write('Number of ', Max_Sam:1, ' byte buffers processed: ');

  repeat
    GotoXY(41,16);    { print the number of processed buffers indicating }
    Write(Buffers:1); { the sampling frequency }
    Inc(Buffers);

    for i:= 0 to Max_Sam do
    begin
      for k:= 1 to Pause do;                      { lower sampling frequency }
      if i>=d then j:= i-d else j:= i-d+Max_Sam+1; { j= index delayed sample }
      s:= ShortInt(Port[ADC]) + Table[Buf[j]];     { compute original + echo }
      if s<-128 then s:= -128 else if s>127 then s:= 127; { correct overflow }
      Buf[i]:= s;                                  { store compound sample   }
      Port[DAC]:= s                                { output sample to DAC    }
    end
  until KeyPressed
end;
\end{verbatim}

To get long delay times the loop creating a pause had to be included. The
fact that the sampling frequency is still as high as 40 kHz indicates that
more complex real time effects can be implemented on this kind of 80386
machines.

Some remarks about the noise and sound quality are in place here. The
board is used in an electrically noisy environment. This, together
with the large ADC input bandwidth causes `noisy' ADC output values.
Remember, when sampling at for example 40 kHz, all signals above
20 kHz manifest itself as noise in the ADC output. This is called
aliasing. A bandwidth limiting input filter should be used to limit this
kind of noise. A measure for the noise is the RMS (Root-Mean-Square) amplitude 
of the samples taken when only noise is input to the ADC. The RMS noise 
amplitude for the samples $s_1, s_2, s_3, \ldots, s_n$ is defined by

\begin{equation}
RMS_{noise} = \frac{1}{n} \sqrt{n \sum_{i=1}^n s_i^2 - \left( \sum_{i=1}^n s_i 
\right)^2}
\end{equation}

The smaller the noise, the smaller this value. Without noise (all samples
equal) the RMS noise is 0.

The RMS noise with the pre-amplifier volume set to zero is about 3-5. The 
figure depends
on the AD7569 clock frequency, which can be adjusted to minimize the noise.
By inserting a simple passive first-order (6 dB/octave) RC filter before
the ADC input with a 10 kHz cutoff frequency (estimated, not measured), the 
RMS noise drops to well below 1.

The sound quality obtained with only 8 bits is better than I expected.
Of course, more bits are better, but maybe the extra
(least significant) bits are completely dominated by the noise when
a wire-wrapped (non-ideally constructed) card like this is used. The board 
is in my opinion well suited for exploring the basics of real time digital 
signal/sound processing. For stage sound quality one should buy a dedicated 
effects processor.

\clearpage
\section{Excerpts from the AD7569 data sheets}

The AD7569 is a complete, 8-bit, analog I/O system on a single monolithic
chip. The AD7569 contains a high speed successive approximation ADC with
2 $\mu$s conversion time, a track/hold with 200 kHz bandwidth, a DAC
and output buffer amplifier with 1 $\mu$s settling time. A temperature-
compensated 1.25 V reference provides a precision reference voltage for
the ADC and the DAC.

A choice of analog input/output ranges is available. Using a supply voltage
of +5 V, input and output ranges of zero to 1.25 V and zero to 2.5 V may
be programmed using the RANGE input pin. Using a $\pm 5$ V supply, bipolar
ranges of $\pm 1.25$ V or $\pm 2.5$ V may be programmed.

Digital interfacing is via an 8-bit I/O port and standard microprocessor
control lines. Bus interface timing is extremely fast, allowing easy
connection to all popular 8-bit microprocessors. A separate start convert line
controls the track/hold and ADC to give precise control of the sampling period.

The AD7569 provides everything necessary to interface a microprocessor to the
analog world. No external components or user trims are required, and the 
overall accuracy of the system is tightly specified, eliminating the need to
calculate error budgets from individual component specifications.

Pin function description (the electronic diagram shows the pin numbers):

\begin{description}
\item{$\rm \bf AGND_{DAC}$} Analog ground for the DAC. Separate ground return
paths are provided for the DAC and ADC to minimize crosstalk.
\item{$\rm \bf V_{OUT}$} Output voltage. $\rm V_{OUT}$ is the buffered output
voltage from the AD7569 DAC. Four different output voltage ranges can be
achieved (see Table \ref{tab:ranges}).
\item{$\rm \bf V_{SS}$} Negative supply voltage (-5 V for dual supply or 0 V 
for single supply). This pin is also used with the RANGE pin to select the
different input/output ranges and changes the data format from binary
($\rm V_{SS}$=0 V) to 2s complement ($\rm V_{SS}$=-5 V) (see Table
\ref{tab:ranges}).
\item{\bf RANGE} Range selection input. This is used with the $\rm V_{SS}$
input to select the different ranges as per Table \ref{tab:ranges}. The
range selected applies to both the analog input voltage of the ADC and the
output voltage from the DAC.
\item{$\rm \bf \overline{RESET}$} Reset input (active low). This is an
asynchronous system reset which clears the DAC register to all 0s and clears
the $\rm \overline{INT}$ line of the ADC (i.e., makes the ADC ready for new
conversion). In unipolar operation this input sets the output voltage to
0 V; in bipolar operation it sets the output to negative full scale.
\item{\bf DB0-DB7} Data bits. DB0 is the least significant bit.
\item{\bf DGND} Digital ground.
\item{$\rm \bf \overline{WR}$} Write input (edge triggered). This is used in
conjunction with $\rm \overline{CS}$ to write data into the AD7569 DAC
register. Data is transferred on the rising edge of $\rm \overline{WR}$.
\item{$\rm \bf \overline{CS}$} Chip select input (active low). The device is
selected when this input is active. DB0-DB7 are in the high impedance state
when this input is high.
\item{$\rm \bf \overline{RD}$} Read input (active low). This input must be
active to access data from the part. It is used in conjunction with the
$\rm \overline{CS}$ input.
\item{$\rm \bf \overline{ST}$} Start conversion (edge triggered). This is used
when precise sampling is required. The falling edge of $\rm \overline{ST}$
starts conversion and drives $\rm \overline{BUSY}$ low. The $\rm \overline{ST}$
signal is not gated with $\rm \overline{CS}$
\item{$\rm \bf \overline{BUSY}$} BUSY status output (active low). When this pin
is active the ADC is performing a conversion. The input signal is held prior to
the falling edge of $\rm \overline{BUSY}$.
\item{$\rm \bf \overline{INT}$} INTERRUPT output (active low). 
$\rm \overline{INT}$ going low indicates that the conversion is complete.
$\rm \overline{INT}$ goes high on the rising edge of $\rm \overline{CS}$ or
$\rm \overline{RD}$ and is also set high by a low pulse on 
$\rm \overline{RESET}$.
\item{\bf CLK} A TTL compatible clock signal may be used to determine the ADC
conversion time. Internal clock operation is achieved by connecting a resistor
and capacitor to ground.
\item{$\rm \bf AGND_{ADC}$} Analog ground for the ADC.
\item{$\rm \bf V_{IN}$} Analog input. Various input ranges can be selected
(see Table \ref{tab:ranges}).
\item{$\rm \bf V_{DD}$} Positive supply voltage (+5 V).
\end{description}

Absolute maximum ratings:

\begin{tabbing}
$\rm V_{DD}\ to\ AGND_{DAC}\ or\ AGND_{ADC}$ \hspace{5mm} \= -0.3 V, +7 V \\
$\rm V_{DD}\ to\ DGND$                     \> -0.3 V, +7 V \\
$\rm V_{DD}\ to\ V_{SS}$                   \> -0.3 V, +14 V \\
$\rm AGND_{DAC}\ or\ AGND_{ADC}\ to\ DGND$ \> $\pm$5 V \\
Logic voltage to DGND                      \> -0.3 V, $\rm V_{DD}$+0.3 V \\
CLK input voltage to DGND                  \> -0.3 V, $\rm V_{DD}$+0.3 V \\
$\rm V_{OUT}\ to\ AGND_{DAC}$\footnotemark \> $\rm V_{SS}-0.3 V,\ V_{DD}+0.3 V$ \\
$\rm V_{IN}\ to\ AGND_{ADC}$               \> $\rm V_{SS}-0.3 V,\ V_{DD}+0.3 V$ \\
Power dissipation                          \> 450 mW
\end{tabbing}

\footnotetext[1]{The output may be shorted to any voltage in the range 
$\rm V_{SS}\ to\ V_{DD}$ provided that the maximum power dissipation 
(450 mW) of the package is not exceeded. Typical short circuit current 
for a short to AGND or $\rm V_{SS}$ is 50 mA.}

\clearpage

I did my utmost best to exclude all errors from the contents of the
ADDA10.ZIP archive. Because I am just like you only human, the described 
circuit might not work or, even worse, cause damage to other equipment. 
Nevertheless, I assume no liability for this. The only guarantee I can give 
you is that my board\footnote{I built the board with the electronic diagram 
included in this archive; I did not create the diagram after building 
the board} functions up to expectation. Of course any suggestions 
to improve the correctness and intelligibility of the description, diagrams 
and software are much appreciated, as are experiences of other people who 
built and used the circuit. These will have their impact on possible future 
versions of the archive.

\vspace{2cm}

Jos Groot (InterNet: jos.groot@fel.tno.nl)

van de Wateringelaan 4 \\
2274 CH  Voorburg \\
The Netherlands

\end{document}

