\documentclass[12pt]{article}

\usepackage{epsf,doublespace,fancyheadings,simplemargins,verbatim}

\pagestyle{fancyplain}
\lhead{Laas}
\chead{Pitch Shifter}
\rhead{April 5, 1999}
\cfoot{}

\begin{document}

\title{Lab 3: Digital Pitch Shifter}
\author{Chris Laas \\ Recitation 3, TR1}
\date{Monday, April 5, 1999}
\maketitle

% Abstract
\begin{section}{Abstract}
\label{sec:abstract}

This report describes the design and construction of a digital pitch
shifter.  The device takes as input an analog audio waveform and
outputs an approximation to the input, shifted up or down in
frequency.  By means of various switches, the pitch can be increased
or decreased, and the device can be configured to output the original
signal, the shifted signal, or both.  There also exist switches which
select the sampling speed, and which select the internal buffer size.

\end{section}
\newpage

% Table of Contents
\pagenumbering{roman}
\cfoot{\thepage}
\tableofcontents
\newpage

% List of Figures
\listoffigures
\newpage

% Overview
\pagenumbering{arabic}
\cfoot{Page \thepage{} out of \pageref{end}}
\begin{section}{Overview}
\label{sec:overview}

The operation of the pitch shifter is conceptually simple.  Upon a
reset (initiated by pulsing {\tt /reset} low), the pitch shifter is
initialized to a 1:1 shifting ratio; pressing the {\tt pitchup} and
{\tt pitchdown} switches gradually increase or decrease the ratio.  If
the {\tt passorig} switch is true, the original signal is output, and
if the {\tt shift} switch is true, the shifted signal is output; if
both are true, then the signals are added and the sum is output.  The
{\tt sampsel} and {\tt bufsel[3:0]} switches set various internal
parameters.

The algorithm used to shift the pitch is this: samples from the audio
in are continually stored in a ``sampling buffer'', and samples are
read from a ``shifting buffer'' at a rate determined by the current
pitch multiplier.  When the sampling buffer is full, the roles of the
buffers are reversed, and the process continues.

\begin{figure}
\epsfbox{mainblock.eps}
\caption{Main Block Diagram}
\label{fig:mainblock}
\end{figure}

Internally, the design of the device (see figure \ref{fig:mainblock})
centers about its two main features: the audio data samples flow down
the 8-bit main data bus (at left) and the chip control signals are
provided by the Microprogrammed Control Unit (at right).

A cycle of operation is trigged by a rising edge on the sampling clock
{\tt SAMPCLK}, which runs at about 7 or 14 KHz.  One sample is read
from the analog-to-digital converter AD670, which places the value on
the data bus; the sample is written to the next element of the
sampling buffer in the 6264 SRAM, and is loaded into the accumulator
if the {\tt passorig} switch is true.  Then, one sample is read from
the shifting buffer (also in the SRAM), which places the value on the
data bus.  If {\tt shift} is true, that value is added into the
accumulator.  Next, the value of the accumulator is latched into the
AS558 digital-to-analog converter, which outputs that value to the
analog out.  Finally, the addresses in the sampling and shifting
buffers are incremented, the sampling address by one and the shifting
address by the pitch multiplier; if the shifting address overflows, it
is reset, and if the sampling address overflows, the buffers are
swapped and both addresses are reset.

\end{section}
\newpage

% Description
\begin{section}{Description}
\label{sec:description}

\subsection{Timing and Synchronizer Module}

\begin{figure}
\epsfbox{time_sync.eps}
\caption{Timing and Synchronizer Module Block Diagram}\label{fig:time_sync}
\end{figure}

This design requires both a fast (roughly 900 KHz) system clock and a
selectable, slow (about 14 or 7 KHz) sampling clock.  Also, like any
digital system which must interface with external inputs, this device
has a synchronizer to align input changes along clock edges.

The timing module consists of a roughly 1.8 MHz crystal oscillator
whose output clocks one half of a LS393 dual four-bit counter.  Four
half-LS393s are chained together to form a sixteen-bit counter, the
low two bits of which osciallate at about 14 and 7 KHz, respectively.
Because of the availability of only four PALs (two 20V8 and two 22V10)
on a 6.111 labkit, the 2-to-1 mux used to select the sampling clock
speed from these two low bits, is incorporated into the 20V8 PAL which
implements the synchronizer.

The synchronizer merely uses D flip flops to align the {\tt /reset},
{\tt shift}, and {\tt passorig} inputs along clock edges.  However,
its handling of the {\tt pitchup} and {\tt pitchdown} inputs is
somewhat more complicated.  The {\tt pitchclk} input internally drives
a {\tt pitchff} flip-flop to divide the frequency still further, to
about 3.5 KHz; either the 7 KHz or 3.5 KHz clock is selected by the
{\tt pitchsel} input.  The values of {\tt pitchup} and {\tt pitchdown}
are passed through only when there is a rising edge on that slow
clock; otherwise, the values of {\tt pitchup} and {\tt pitchdown} are
zero.  This serves to convert those two inputs into a series of slow
pulses when asserted, so that the pitch multiplier increases or
decreases at a reasonable rate.

\subsection{Analog-to-Digital Module}

\begin{figure}
\epsfbox{a2d-timing.eps}
\caption{A2D Timing Diagram}\label{fig:a2d-timing}
\end{figure}

Since the audio input to the pitch shifter is an analog signal, it
must be converted to a digital value before it can be processed.  The
AD670 chip is wired (see figure \ref{fig:mainblock}) to continually
convert its input while the {\tt R/W} input is held low.  To initiate
a read cycle on the A2D (see figure \ref{fig:a2d-timing}), the {\tt
R/W} line is brought and held high.  When the {\tt STATUS} output of
the A2D goes low, the data bus will be valid for reading.

\subsection{Storage Unit}

\begin{figure}
\epsfbox{sram.eps}
\caption{Storage Unit}\label{fig:su}
\end{figure}

The Storage Unit implements both the sampling buffer and the shifting
buffer.  It consists of a C372i CPLD and a 6264 SRAM whose chip select
inputs are tied such that it is always selected.

The CPLD's equivalent circuit is shown in figure \ref{fig:su}.  The
11-bit sampling counter provides the address for the sampling buffer;
it is cleared when {\tt clearsamp} (from the MCU) is asserted, and
incremented by one when {\tt count} (from the MCU) is asserted.  The
pitch multiplier counter is an eight-bit up-down counter, which counts
up on {\tt pitchup} or down on {\tt pitchdown}.  (On reset, the pitch
multiplier counter is initialized to 1.0, or {\tt 01000000}.)  The
17-bit shifting counter provides the address for the shifting buffer;
it is cleared when {\tt clearshift} (from the MCU) is asserted, and
incremented by {\tt pitchmult} when {\tt count} is asserted.  The {\tt
shiftcount} input selects which of the sampling counter or the 11 high
bits of the shifting counter is output to the low 11 bits of the SRAM
address bus {\tt memaddr}.

The high bit of the SRAM address bus, {\tt buf}, selects which buffer
is being written to or read from.  This is accomplished by XORing an
internal {\tt bufsel} flip flop with the {\tt shiftbuf} input; thus,
conceptually, pulling {\tt shiftbuf} high selects the shifting buffer,
which pulling it low selects the sampling buffer.  A high on {\tt
swapbuff} toggles the value of {\tt bufsel}; this has the effect of
reversing the roles of the two buffers.

Finally, a ``full detector'' outputs a 1 to the {\tt full} output when
the value on {\tt memaddr} is higher than a value specified by the
four buffer size selector switches.  In this implementation, the full
detector uses a logarithmic scale: if the value on {\tt
buf\_size[3:0]} is N, then {\tt full} is 1 if any of the 10-N
high-order bits of {\tt memaddr} is not zero.  Since there are only
eleven bits in {\tt memaddr}, this scheme will not work for $10 \le N
\le 16$; thus, for those values of {\tt buf\_size}, {\tt full} is 1 if
{\tt memaddr} is equal to {\tt 11111111111}.

Due to limitations of the MCU, this design had to conserve control
signal pins.  Thus, the {\tt shiftbuf} and {\tt shiftcount} were tied
together internally in the CPLD, to the value of {\tt shiftbuf}; also,
the {\tt swapbuff} and {\tt clearsamp} were externally both tied to
the same output pin of the MCU.  Neither of these changes resulted in
any performance change, because one would never want to assert one
signal in a pair without asserting the other.

\subsection{Accumulator Module}

The 8-bit accumulator module's operation is externally simple.  All
operations are synchronous to the system clock.  If the {\tt clr}
input is asserted over a rising clock edge, the value of the
accumulator is reset to zero; if the {\tt ld} input is asserted, the
value on {\tt input[7:0]} is added to the current value of the
accumulator.  The current value is always output to the {\tt reg[7:0]}
pins.

Internally, to simplify wiring, the accumulator is implemented as a
pair of PALs, one 20V8 for the low four bits and one 22V10 for the
high four bits.  This allowed a much cleaner protoboard layout and
prevented wiring mistakes due to the tricky pinouts of the LS283 and
LS374.  The disadvantage, however, was that the original design did
not fit into the one 20V8 and one 22V10 that were available, even
after splitting the accumulator into two halves (with a carry bit).
However, by hand optimizing the design equations, it became possible
to fit the low half of the accumulator into a 20V8.  (See sections
\ref{sec:accum_lo.vhd}, \ref{sec:accum_lo.pal}, and
\ref{sec:accum_hi.vhd} for source listings.)  The wiring of the two
halves is self-evident: the clk, clr, and ld inputs come from the same
sources, and the carry\_out output on the low half is tied to the
carry\_in input on the high half.

\subsection{Digital-to-Analog Module}

\begin{figure}
\epsfbox{d2a-timing.eps}
\caption{D2A Timing Diagram}\label{fig:d2a-timing}
\end{figure}

Since the output of the pitch shifter is an analog audio signal, the
processed digital value in the accumulator must be converted to an
analog signal.  This operation is performed by the AD558 D2A, wired as
shown in figure \ref{fig:mainblock} to produce an output in the range
0 to 2.55 V.  When the {\tt /CE} signal to the D2A is pulsed low, the
D2A latches on to the accumulator output and puts its latched value
on the analog output.  The operation of the accumulator-D2A pair is
shown in figure \ref{fig:d2a-timing}.

\subsection{Microprogrammed Control Unit}

\begin{figure}
\epsfbox{mcu.eps}
\caption{MCU Block Diagram}\label{fig:mcu}
\end{figure}

The Microprogrammed Control Unit's purpose is to act as a sequencer
for the pitch shifter: it executes a sequence of instructions of the
form ``place this value on this control signal'', ``go to this
instruction number'', or ``go to this instruction number if this
status signal is true''.

The Microprogrammed Control Unit consists of two chained LS163s acting
as an eight-bit, loadable, clearable counter; an LS151; two 28F256
PROMs storing a program of 16-bit-wide instruction words; and a 22V10
PAL acting as assertion logic.  (See figure \ref{fig:mcu}.)

The current instruction address is the value of the 2 LS163s.  It is
reset to zero if {\tt /RESET} goes low, effectively jumping to the
beginning of the program.  The instruction address is placed on the
low eight bits of the PROMs address busses.  (The high-order bits can
be used to select an alternate program to execute.)  The MSB of the
instruction fetched from the PROM is the ``opcode'': it determines the
operation the MCU will perform.

If the opcode is 0, then the operation is a conditional jump.  Since
the opcode is wired to the {\tt /EN} input of the LS151, and the next
three bits are wired to the selector input, the mux will only output a
0 (negative true) if opcode is 0 {\em and} the selected input is 1.
(Since input number 7 is tied high, an unconditional jump can be
performed by putting {\tt 0111} in the high four bits of the
instruction.)  If that occurs, the value on the {\tt /LD} inputs to
the LS163s will go low, which will cause the counters to load the
value from the low eight bits of the instruction.  Effectively, the
program executes a ``jump'' to the instruction address in the low
eight bits.  (See section \ref{sec:mcode.sp} for the codes for the
various status signals.)

If the opcode is 1, then the operation is an assert.  Since the LS151
will be disabled, the LS163s do not perform a load.  However, the
assert logic implemented in the 22V10 PAL will be enabled by the 1 on
the assert\_in pin.  The PAL, which effectively acts as a 10-bit RAM,
is programmed to load the value on the {\tt level} input (from the
second most significant bit of the instruction) into the registered
output selected by the value of the {\tt value[3:0]} input (from bits
8 to 11 of the instruction).  For example, if the instruction is {\tt
1000101000000000,} then the value 0 replaces the previous value on the
{\tt ACCUM\_CLR} output pin of the PAL.  (See section
\ref{sec:mcode.sp} for the respective values for the assertion logic
outputs.)

\subsection{MCU Microcode}

The microcode programmed into the MCU PROMs directs the sequence of
operations the device performs on each sample.  The overall sequence
of operations is this:

\begin{enumerate}
\item Wait for a rising edge on {\tt SAMPCLK}.
\item Read a value from the audio in.
\item Write that value into the sampling buffer.
\item IF {\tt passorig} is true, load that value into the accumulator.
\item IF {\tt shift} is true, read a value from the shifting buffer,
and add that value into the accumulator.
\item Load the accumulator value into the DAC, and thus output it to
audio out.
\item Count up the sampling and shifting buffer addresses.
\item IF the shifting address is greater than the buffer size, reset it.
\item IF the sampling address is greater than the buffer size, swap
buffers and reset both addresses.
\end{enumerate}

The MCU orchestrates the accomplishment of all these tasks by sending
the appropriate control signals to various modules of the device at
the appropriate times.  In detail, the instruction sequence is described
below.  (See figure \ref{fig:mainflow} for a flow chart of the
sequence of instructions, and see section \ref{sec:mcode.lst} for a
complete listing of the microcode.)

\begin{figure}
\epsfbox{mainflow.eps}
\caption{Main Microcode Flow Chart}
\label{fig:mainflow}
\end{figure}

\begin{enumerate}

\item Wait for a rising edge on {\tt SAMPCLK}.
\begin{enumerate}
\item \label{step:begin} If {\tt SAMPCLK} is true, go to step \ref{step:begin}.
\item \label{step:waitclk} If {\tt SAMPCLK} is true, go to step
\ref{step:doconv}.
\item Go to step \ref{step:waitclk}.
\end{enumerate}

\item Read a value from the audio in.
\begin{enumerate}
\item \label{step:doconv} Assert {\tt ADC\_RW} high to put the A2D
into read mode.
\item \label{step:waitadc} If {\tt ADC\_STATUS} is true, go to step
\ref{step:waitadc}.
\end{enumerate}

\item Write that value into the sampling buffer.
\begin{enumerate}
\item Pulse {\tt RAM\_N\_WE} low (i.e. assert it low and then assert
it high).
\end{enumerate}

\item IF {\tt passorig} is true, load that value into the accumulator.
\begin{enumerate}
\item Pulse {\tt ACCUM\_CLR} high to clear the accumulator.
\item If {\tt PASSORIG} is false, go to step \ref{step:noaddorig}.
\item Pulse {\tt ACCUM\_LD} high to add the value on the bus (from the
A2D) into the accumulator.
\item \label{step:noaddorig} Assert {\tt ADC\_RW} low to make the A2D
give up the bus.
\end{enumerate}

\item IF {\tt shift} is true, read a value from the shifting buffer,
and add that value into the accumulator.
\begin{enumerate}
\item Assert {\tt SU\_SHIFTBUF} to put the shifting buffer address on
the RAM address lines.
\item If {\tt ADDSHIFTED} is false, go to step
\ref{step:noaddshifted}.
\item Assert {\tt RAM\_N\_OE} low to retrieve the stored shifted value
from the shifting buffer.
\item Wait a few cycles.  (Performing null operations.)
\item Pulse {\tt ACCUM\_LD} high to add the value on the bus (from the
RAM) into the accumulator.
\item Assert {\tt RAM\_N\_OE} high to take the SRAM out of read mode.
\end{enumerate}

\item Load the accumulator value into the DAC, and thus output it to
audio out.
\begin{enumerate}
\item \label{step:noaddshifted} Pulse {\tt DAC\_N\_CE} low to latch the
accumulator value into the D2A.
\label{step:cleanup}
\end{enumerate}

\item Count up the sampling and shifting buffer addresses.
\begin{enumerate}
\item Pulse {\tt SU\_COUNT} high.
\end{enumerate}

\item IF the shifting address is greater than the buffer size, reset it.
\begin{enumerate}
\item If {\tt SU\_FULL} is false, go to step \ref{step:shiftnotfull}.
\item Pulse {\tt SU\_CLEARSHIFT} high.
\end{enumerate}

\item IF the sampling address is greater than the buffer size, swap
buffers and reset both addresses.
\begin{enumerate}
\item \label{step:shiftnotfull} Assert {\tt SU\_SHIFTBUF} low to place
the sampling buffer address on the RAM address lines.
\item If {\tt SU\_FULL} is false, go to step \ref{step:begin}.
\item Pulse {\tt SU\_SWAPBUFF} high.
\item Pulse {\tt SU\_CLEARSHIFT} high.
\item Go to step \ref{step:begin}.
\end{enumerate}
\end{enumerate}

\begin{figure}
\epsfbox{timing.eps}
\caption{Overall Timing Diagram when PassOrig? and Shift? are asserted}
\label{fig:timing}
\end{figure}

The timing diagram in figure \ref{fig:timing} shows the overall
sequence of data-bus-related signals after a rising edge on {\tt
SAMPCLK}, when both {\tt passorig} and {\tt shift} are true.  The
``cleanup'' instructions after step \ref{step:cleanup} are omitted,
because they are uninteresting.

\end{section}
\newpage

% Conclusion
\begin{section}{Conclusion}
\label{sec:conclusion}

The practical implementation of this project was, like any typical
digital project, not the ideal design.  Due to the limitations of the
parts available, the conceptually separate timing and synchronizer
Modules were somewhat combined, and the conceptually monolithic
accumulator module was split into two PALs.  However, neither of these
affected system performance or debugging time, and so are forgivable
flaws.

The eight-bit accumulator overflowed when both {\tt shift} and {\tt
passorig} were asserted and when both signals were at greater than
half max value.  This could have been averted by using a nine-bit
accumulator and some multiplexing circuitry, but would have been more
complicated and largely unneccessary, as turning down the volume on
the input suffices as a quick-and-dirty fix.

The performance of the pitch shifter depended largely upon the sample
clock select and buffer size switches.  At high sample clock speeds,
performance was poor: there were high-frequency random samples
introduced at some point into the pipeline.  I conjecture that this
may have been due to a lack of time for the instruction sequence to
execute between samples.  At very low buffer size, there was little
pitch-shifting effect, because at least a wavelength of the signal
needed to be stored in order to reconstruct a shifted signal.  When
the buffer size was set to maximum, the pitch shifting effect was very
clear.

Some buffer sizes produced interesting side effects: in particular,
size number 6 produced a sequence of step-like transitions from
frequency to frequency when the pitch was continually raised.  The
effect was very much like a musical scale.  I have guessed that this
was due to some sort of resonance effect of the input sine wave with
the size of the buffer.

Despite a few initial difficulties with the VHDL compiler software and
with debugging the wiring (made easier by careful layout of busses),
designing and implementing this device was mostly hassle-free.  The
digital pitch shifter meets or exceeds its specifications, and has a
fairly elegant and simple design.  Also, in the future, the eight-bit
accumulator module and the MCU module could be reused in other
designs.  To conclude, the project was a complete success.

\end{section}
\newpage

% Appendices
\begin{section}{Appendix I:
                {\normalsize Synchronizer VHDL file {\tt sync.vhd}}}
\label{sec:sync.vhd}
{\small \verbatiminput{../sync/sync.vhd}}
\end{section}

\begin{section}{Appendix II: {\normalsize CPLD VHDL file {\tt mar.vhd}}}
\label{sec:mar.vhd}
{\small \verbatiminput{../mar/mar.vhd}}
\end{section}

\begin{section}{Appendix III: {\small Low Half of Accumulator VHDL file
                {\tt accum\_lo.vhd}}}
\label{sec:accum_lo.vhd}
{\small \verbatiminput{../accum/accum_lo.vhd}}
\end{section}

\begin{section}{Appendix IV: {\normalsize Low Half of Accumulator PAL file
                {\tt accum\_lo.pal}}}
\label{sec:accum_lo.pal}
{\small \verbatiminput{../accum/accum_lo.pal}}
\end{section}

\begin{section}{Appendix V: \\ {\normalsize High Half of Accumulator VHDL file
                {\tt accum\_hi.vhd}}}
\label{sec:accum_hi.vhd}
{\small \verbatiminput{../accum/accum_hi.vhd}}
\end{section}

\begin{section}{Appendix VI: {\normalsize Assertion Logic VHDL file
                {\tt alogic.vhd}}}
\label{sec:alogic.vhd}
{\small \verbatiminput{../alogic/alogic.vhd}}
\end{section}

\begin{section}{Appendix VII:
                {\normalsize MCU Specification file {\tt mcode.sp}}}
\label{sec:mcode.sp}
{\small \verbatiminput{../mcode/mcode.sp}}
\end{section}

\begin{section}{Appendix VIII:
                {\normalsize MCU Microcode listing file {\tt mcode.lst}}}
\label{sec:mcode.lst}
{\small \verbatiminput{../mcode/mcode.lst}}
\end{section}

\begin{section}{Appendix IX: {\normalsize Pinouts for Programmable Logic}}
\label{sec:pinouts}
{\small
\verbatiminput{../sync/sync.pinout}
\verbatiminput{../alogic/alogic.pinout}
\verbatiminput{../accum/accum_hi.pinout}
\verbatiminput{../accum/accum_lo.pinout}
\verbatiminput{../mar/mar.pinout}}
\end{section}

\label{end}

\end{document}
