I am at the moment trying to use MCP3008 as an ADC, but for some reason it doesn't convert the output correctly. (A beginner project).
I provide it with an 3.3 V = vref = Vdd = ch0
But my output seem to never become => 1111111111 , but rather something like 1111010111…
I programming it on a FPGA, using VHDL.
FPGa CLK : 50 mhz.
Here is the code:
ibrary IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_logic_unsigned.all;
use ieee.numeric_std.all;
entity main is
Port ( MISO : in STD_LOGIC;
MOSI : out STD_LOGIC;
CS : out STD_LOGIC;
SCLK : out STD_LOGIC;
CLK : in STD_LOGIC;
);
end main;
architecture Behavioral of main is
constant N : integer := 4;
signal prescaler_counter : integer range 0 to 50000000 := 0;
signal newClock : std_logic := '0';
signal TX :std_logic_vector(N downto 0) := "11000";
signal RX : std_logic_vector(9 downto 0) := "0000000000";
type state_type is (start,state2,state3,state4,state5); --type of state machine.
signal state : state_type := start;
signal shift_counter: integer range 0 to 750:= N;
begin
prescaler01: process(clk, newClock)
begin
if rising_edge(clk) then
if prescaler_counter < 1000000 then
prescaler_counter <= prescaler_counter + 1;
else
newClock <= not newClock;
prescaler_counter <= 0;
end if;
end if;
end process;
SCLK <= newClock;
SPI_state: process(newClock)
begin
if falling_edge(newClock) then
case state is
when start =>
CS <= '1';
MOSI <= '0';
busy <= '1';
RX <= "0000000000";
state <= state2;
when state2 => -- Send init bits.
CS <= '0';
shift_counter <= shift_counter - 1;
TX <= TX(N-1 downto 0) & TX(N);
MOSI <= TX(N);
if shift_counter = 0 then
MOSI <= '0';
shift_counter<= 12;
state <= state3;
end if;
when state3 =>
--MOSI <= '0';
CS <= '0'; -- Last bit init bit;
state <= state5;
when state4=>
CS <= '0'; --T_sample from falling - falling
state <= state5;
when state5=>
CS <= '0'; -- Read
if shift_counter = 0 then
MOSI <= '0';
shift_counter<= N;
busy <= '0';
state <= start;
elsif shift_counter < 11 then
RX <= RX(8 downto 0) & MISO;
shift_counter <= shift_counter - 1;
else
shift_counter <= shift_counter - 1;
end if;
when others =>
state <= start;
end case;
end if;
end process;
I think my timing might be a bit off.. Eventhough i tweaked it in simulations.. So it doesn't make sense, why the output doesn't seem correct..
Help is very much appreciated :).
I know this question will get a lot of down votes, because of the level of difficulty of the question, but I have to start somewhere.
-edit-
I tried the simulation which Lincoln posted as an answer which shows that the timing, isn't off, I added a debug_tx which shows which state the program is in at the moment.
- debug_tx := "0001" – sets CS high, so input gets reset.
- debug_tx := "0010" – Send init bit "11000" => start bit+ peform ADC,
input CH0. - debug_tx := "0100" – delay – Time needed for the ADC
- Debug_tx := "1000" – delay – skip first nulbit.
- debug_tx := "1101" – read – 9 times and perform shift values to the
left as such.
I am pretty sure something is wrong with the way i am shifting things.. Or maybe something else..
RX <= RX(8 downto 0) & MISO;
Rx_Led shows the binary value of the output it reads..It seems like the last two shift gets stalled 2 clk periods each… Which seems weird..
Side note, I am only applying the system 3.3V, but that i have pre scaled the clock down to 5- 10 hz, so it should be a problem with the timing difference from applying it 5 V or 3 V.
Best Answer
I am the TA for a digital design class that uses the MCP3001 ( the single channel version of this adc) and have a testbench for debugging problems that students have with it. I modified it for your MCP3008 example. Please try testing your design with it.