Testing of an Analog-to-Digital Converter using VHDL |
One of the problems we encountered while trying to test our ADC design was that we could not determine if the wrong outputs generated from the ADC were coming from the hardware circuit or the VHDL code written.
To ensure success in the entire design, we needed to be able to guarantee either the correctness of the hardware design or the accuracy of the VHDL program that ran the circuit. This student application note will not focus on the hardware implementation of an analog to digital converter (ADC) but rather, on the testing of an ADC using just the Altera board and VHDL code to simulate the entire circuit (ADC and Sample&Hold chips are not used at all). The correct simulation of the code will ensure the correctness of the VHDL code and hence, that eliminates the fact that the wrong outputs that may be generated are coming from inaccuracy in VHDL coding.
Test Procedure: |
1) Determine the number of output bits required. Also, the availability of the chips from Morris is an essential not to mention, a convenience too.
2) Design the hardware using the chips while paying careful attention to the specifications sheets.
3) Determine all the input and output of the chips and whether or not to ground/power each individual pin signal.
4) Write a VHDL code for the ADC to control the various input and output signals coming from and out of the ADC and the sample-and-hold chip. For now, we can ignore the two stages of the amplifier. We are not concern about the operational amplifiers at this present moment.
Basically, a state machine is implemented to enable the control of various signals. Here, we have used the outputs and inputs of the ADC0809 and the SMP-11 chips.The code below, test_ADC.vhd can be used as an example:
------------------------------------------------------------------
LIBRARY ieee; USE ieee.std_logic_1164.all;
LIBRARY work; use work.clk_div_pkg.all; -- using a clock_divider to slow down the clock (program below)
ENTITY test_ADC IS
generic ( ad_bits : positive := 8 );
port ( clock : IN STD_LOGIC; -- regular clock
slow_clock : buffer STD_LOGIC; -- clock generated by the clock_divider
nreset : IN STD_LOGIC; -- reset is active low hence the name (set as such due to active low push button on Altera board)
nend_of_conv : IN STD_LOGIC; -- end of conversion signal of the ADC chip
sample : OUT STD_LOGIC; -- signal connecting the S&H chip to the FPGA
bits : IN STD_LOGIC_VECTOR(ad_bits - 1 downto 0); -- Bits coming out from the a/d to the FPGA
data_out : OUT STD_LOGIC_VECTOR(ad_bits - 1 downto 0); -- Cleaned and clocked bits of the ADC
start_of_conv : OUT STD_LOGIC); -- start of conversion signal coming from the FPGA to the ADC chip
END input_reader;
ARCHITECTURE a OF test_ADC IS
-- declaration of states. we have 4 states here.
TYPE STATE_TYPE_CONV IS (sample_conv, start_conv, in_conv,end_conv,read_conv);
SIGNAL next_state, state: STATE_TYPE_CONV;
SIGNAL GND : STD_LOGIC ;
SIGNAL dummy_bit: STD_LOGIC_VECTOR(ad_bits - 1 downto 0);
BEGIN
GND <= '0';
-- port mapping the component clock_divider
clkdiv: clock_divider
port map( clock => clock, slow_clock =>slow_clock, reset => GND );
PROCESS (slow_clock)
BEGIN
IF nreset = '0' THEN -- active low reset (set as such due to active low push button on Altera board)
next_state <= sample_conv; -- next state enters the first state of the state machine
ELSIF falling_edge (slow_clock) THEN
start_of_conv <= '0'; -- set start of conversion (SOC) to zero
sample <= '0'; -- set sample to zero
CASE state IS
WHEN sample_conv =>
sample <= '1'; -- set sample to one to start sampling the analog input
next_state <= start_conv; -- proceed to the next state to start conversion
WHEN start_conv =>
start_of_conv <= '1'; -- set SOC to one
sample <='0'; -- set sample to zero to hold sampled values
next_state <= in_conv;
WHEN in_conv =>
start_of_conv <= '0'; -- set SOC to zero. The part when the SOC signal drops to zero from one is when the conversion starts in the ADC chip
IF nend_of_conv = '1' THEN -- End of conversion (EOC) will go to one if conversion is done
next_state <= end_conv; -- proceed to next state of finite state machine
ELSE next_state <= in_conv; -- else if conversion on done, remain in the conversion state
END IF;
WHEN end_conv =>
next_state <= read_conv; -- after end of conversion, proceed on to the next state to read in new signals
WHEN read_conv =>
dummy_bits <= bits; -- assign bits to dummy_bits. dummy_bits is a dummy variable that will transfer the contents of bits to data_out later
sample <= '1'; -- start sampling once more
next_state <= sample_conv; -- proceed to the sampling state
END CASE;
END IF;
state <= next_state;
END PROCESS;
fifo: PROCESS(hold_out)
BEGIN
WAIT UNTIL rising_edge(clock); -- clock is rising edge triggered
data_out <= dummy_bits; -- assign dummy_bits to data_Out
END PROCESS fifo;
END a;
-- end of program
------------------------------------------------------------------------
A clock divider is incorporated into this program in order to enable our naked eyes to see the blinking lights on the Altera board when the analog signal changes. The VHDL program for the clock divider, clock_divider.vhd is shown below:
-----------------------------------------------------------
USE ieee.std_logic_1164.all;
-- make clock_divider into a package to enable the use of this component outside this program
package clk_div_pkg is
component clock_divider
generic ( divisor : positive := N); -- slows down the clock by a factor of 2*N
port ( clock : IN STD_LOGIC;
slow_clock : OUT STD_LOGIC;
reset : IN STD_LOGIC );
end clock_divider;
ARCHITECTURE a OF clock_divider IS
signal int_slow_clock : STD_LOGIC;
begin
slow_clock <= int_slow_clock;
clock_divide : process(clock) is
variable fast_counter : natural range 0 to divisor;
begin
wait until rising_edge(clock);
if reset = '1' then -- active high reset
fast_counter := 0; -- assign counter to zero first
int_slow_clock <= '0';
else fast_counter := (fast_counter+1); -- increment counter by one
if fast_counter = 0 then -- when counter has a value of zero (i.e. when reset)
int_slow_clock <= not int_slow_clock;
end if;
end if;
end process clock_divide;
end;
-- end of program
------------------------------------------------------------------------
4) Save the codes in two different filenames using the entity name as the filename. Compile the VHDL codes in MaxPlus2 and simulate waveforms to ensure correctness of code. Note that attention has to be drawn to the fact that the push buttons on the Altera board is active low. Moreover, the behaviour of every signal coming from/into the chip has to be analysed properly from the specification sheets.
5) Perform pin assignments on the Altera board.
Signal Name | Pin Number | Hole Number |
bits(0) | 55 | 23 |
bits(1) | 56 | 24 |
bits(2) | 61 | 25 |
bits(3) | 62 | 26 |
bits(4) | 63 | 27 |
bits(5) | 64 | 28 |
bits(6) | 65 | 29 |
bits(7) | 66 | 30 |
data_out(0) | 72 | 35 |
data_out(1) | 73 | 36 |
data_out(2) | 74 | 37 |
data_out(3) | 75 | 38 |
data_out(4) | 76 | 39 |
data_out(5) | 78 | 40 |
data_out(6) | 79 | 41 |
data_out(7) | 80 | 42 |
clock | 91 | - |
slow_clock | 101 | 56 |
nreset | 28 (push button) | - |
start_of_conv | 82 | 44 |
end_of_conv | 81 | 43 |
sample | 83 | 45 |
6) Connect the data_out(0-6) bits from the Altera board to the LEDs. The bits(0-6) will be connected to the switches on the board. Use the board we used for EE280 if difficulty is encountered with the switches on the Altera board. The inputs are entered manually here. The SOC, EOC, clock can be connected to a bread board and probed with the pointer (of an oscilloscope) to check for the outputs. When the EOC signal is set to high, the state should transfer from one state machine to the other continuously. When EOC is set to low, the state machine will remain at state in_conv. Reset will be high but when the push button is pressed, the current state will revert back to the initial state of sample_conv.
7) The simulation waveforms are as follows:
Waveform 1 shows the simulation under normal conditions and when conversion is continuossly performed without any reset or EOC signal interference.
Waveform 2 shows the simulation waveform when the EOC signal is set to zero in the middle of the conversion. Note that state machine remains at state in_conv as long as the EOC signal is set to zero. Once again, remember that the EOC signal is active low.
Waveform 3 shows the simulation waveform the signal EOC is set to zero for the entire duration. Once again, the state machine remains at state in_conv.
Waveform 4 shows the simulation waveform when reset is set to zero. Note that reset is active low. The state machine returns to the initial state, start_conv after the reset push button is pressed down.
Note : Hold the 'shift' key and right click the mouse to view the waveforms.
References |
- Microelectronic Circuits - Sedra & Smith
- Student Application Notes (semester-winter1999)- Audio Adc
- National Semiconductor, "Data Acquisition Databook", National Semiconductor
- http://www.ee.ualberta.ca/~elliott/ee552/reports.html
- ADC Datasheet
Last updated: November 9, 1999