I am trying to interface MCP3008 with basys 3 using SPI and store the values in a FIFO and transmit the values to PC using UART.
Initially, I designed for ADC to convert input waveform and display results by increment or decrements of LED's. The MCP3008 ADC clock is 1.3 MHz clock.
This works and led's increment as the amplitude of the input waveform is increased from signal generator . But when i receive through UART and plot on SerialPlot , the signal is distorted
please find the code for ADC below:
entity ADC is
port
(
-- command input
clock : in std_logic; -- 100MHz onboard oscillator
trigger : in std_logic; -- assert to sample ADC
diffn : in std_logic; -- single/differential inputs
channel : in std_logic_vector(2 downto 0); -- channel to sample
-- data output
Dout : out std_logic_vector(14 downto 0); -- data from ADC
OutVal : out std_logic; -- pulsed when data sampled
-- ADC connection
adc_miso : in std_logic; -- ADC SPI MISO
adc_mosi : out std_logic; -- ADC SPI MOSI
adc_cs : out std_logic; -- ADC SPI CHIP SELECT
adc_clk : out std_logic -- ADC SPI CLOCK
);
end ADC;
architecture behavioural ofADC is
-- clock
signal adc_clock : std_logic := '0';
-- command
signal trigger_flag : std_logic := '0';
signal sgl_diff_reg : std_logic;
signal channel_reg : std_logic_vector(2 downto 0) := (others => '0');
signal done : std_logic := '0';
signal done_prev : std_logic := '0';
-- output registers
signal val : std_logic := '0';
signal D : std_logic_vector(9 downto 0) := (others => '0');
-- state control
signal state : std_logic := '0';
signal spi_count : unsigned(4 downto 0) := (others => '0');
signal Q : std_logic_vector(9 downto 0) := (others => '0');
begin
-- clock divider
-- input clock: 100Mhz
--100MHz/1.3MHz = 74/2
-- adc clock: 1.3MHz
clock_divider : process(clock)
variable cnt : integer := 0;
begin
if rising_edge(clock) then
cnt := cnt + 1;
if cnt = 37 then
cnt := 0;
adc_clock <= not adc_clock;
end if;
end if;
end process;
-- produce trigger flag
trigger_cdc : process(adc_clock)
begin
if rising_edge(adc_clock) then
if trigger = '1' and state = '0' then
sgl_diff_reg <= diffn;
channel_reg <= channel;
trigger_flag <= '1';
elsif state = '1' then
trigger_flag <= '0';
end if;
end if;
end process;
adc_clk <= adc_clock;
adc_cs <= not state;
-- SPI state machine (falling edge)
adc_sm : process(adc_clock)
begin
if adc_clock'event and adc_clock = '0' then
if state = '0' then
done <= '0';
if trigger_flag = '1' then
state <= '1';
else
state <= '0';
end if;
else
if spi_count = "10000" then
spi_count <= (others => '0');
state <= '0';
done <= '1';
else
spi_count <= spi_count + 1;
state <= '1';
end if;
end if;
end if;
end process;
-- Register sample
outreg : process(adc_clock)
begin
if rising_edge(adc_clock) then
done_prev <= done;
if done_prev = '0' and done = '1' then
D <= Q;
Val <= '1';
else
Val <= '0';
end if;
end if;
end process;
-- LED outputs
PROCESS (adc_clock)
BEGIN
IF (adc_clock'EVENT AND adc_clock = '1') THEN
CASE D(9 DOWNTO 6) IS
WHEN "0001" =>
Dout <= "000000000000011";
WHEN "0010" =>
Dout <= "000000000000111";
WHEN "0011" =>
Dout<= "000000000001111";
WHEN "0100" =>
Dout <= "000000000011111";
WHEN "0101" =>
Dout <= "000000000111111";
WHEN "0110" =>
Dout <= "000000001111111";
WHEN "0111" =>
Dout <= "000000011111111";
WHEN "1000" =>
Dout <= "000000111111111";
WHEN "1001" =>
Dout <= "000001111111111";
WHEN "1010" =>
Dout <= "000011111111111";
WHEN "1011" =>
Dout <= "000111111111111";
WHEN "1100" =>
Dout <= "001111111111111";
WHEN "1101" =>
Dout <= "011111111111111";
WHEN "1110" =>
Dout <= "111111111111111";
WHEN "1111" =>
Dout <= "111111111111111";
WHEN OTHERS =>
Dout <= "000000000000001";
END CASE;
END IF;
-- END IF;
END PROCESS;
OutVal <= Val;
-- MISO shift register (rising edge)
shift_in : process(adc_clock)
begin
if adc_clock'event and adc_clock = '1' then
if state = '1' then
Q(0) <= adc_miso;
Q(9 downto 1) <= Q(8 downto 0);
end if;
end if;
end process;
-- Decode MOSI output
shift_out : process(state, spi_count, sgl_diff_reg, channel_reg)
begin
if state = '1' then
case spi_count is
when "00000" => adc_mosi <= '1'; -- start bit
when "00001" => adc_mosi <= sgl_diff_reg;
when "00010" => adc_mosi <= channel_reg(2);
when "00011" => adc_mosi <= channel_reg(1);
when "00100" => adc_mosi <= channel_reg(0);
when others => adc_mosi <= '0';
end case;
else
adc_mosi <= '0';
end if;
end process;
end behavioural;
--much of the code is of credit to micronova electronics.
For fifo, I use the Xilinx IP fifo generator with no FWFT working on 100Mhz clock both on write and read sides.
FIFO width = 10
Depth = 2046 and tried increasing upto 131072 with no progress.
This is my top level code with UART
entity top_module is
Generic (
PARITY_BIT : string := "none" -- type of parity
);
port(
clk, rst,trigger,diffn: in std_logic;
adc_mosi,adc_clk,adc_cs : out std_logic;
adc_miso : in std_logic;
channel : in std_logic_vector ( 2 downto 0);
wr_uart,uart_clk_en : in std_logic;
WriteEn , ReadEn : in std_logic;
full, empty : out std_logic;
--w_data: in std_logic_vector(7 downto 0);
Dout : inout std_logic_vector(9 downto 0);
busy : out std_logic;
tx,OutVal: out std_logic
);
end top_module;
architecture structural of top_module is
signal fifo_data_out : STD_LOGIC_VECTOR (9 downto 0);
component fifo is
port (
reset_rtl_0 : in STD_LOGIC;
clk_100MHz : in STD_LOGIC;
full_0 : out STD_LOGIC;
din_0 : in STD_LOGIC_VECTOR ( 9 downto 0 );
wr_en_0 : in STD_LOGIC;
empty_0 : out STD_LOGIC;
dout_0 : out STD_LOGIC_VECTOR ( 9 downto 0 );
rd_en_0 : in STD_LOGIC
);
end component fifo;
begin
MercuryADC : entity work.ADC
port map (
clock => clk,
trigger => trigger,
diffn => diffn,
channel => channel,
-- data output
Dout => Dout,
OutVal => Outval,
-- ADC connection
adc_miso => adc_miso,
adc_mosi => adc_mosi,
adc_cs => adc_cs,
adc_clk =>adc_clk
);
fifo_i: component fifo
port map (
clk_100MHz => clk,
din_0(9 downto 0) => Dout(9 downto 0),
dout_0(9 downto 0) => fifo_data_out(9 downto 0),
empty_0 => empty,
full_0 => full,
rd_en_0 => ReadEn,
reset_rtl_0 => rst,
wr_en_0 => WriteEn
);
uart_trx : entity work.UART_TX
Port map (
CLK => clk, -- system clock
RST => rst, -- high active synchronous reset
-- UART INTERFACE
UART_CLK_EN => uart_clk_en, -- oversampling (16x) UART clock enable
UART_TXD => tx, -- serial transmit data
-- USER DATA INPUT INTERFACE
DATA_IN =>fifo_data_out (9 downto 2) , -- input data
DATA_SEND => wr_uart,-- when DATA_SEND = 1, input data are valid and will be transmit
BUSY => busy -- when BUSY = 1, transmitter is busy and you must not set DATA_SEND to 1
);
end structural;
PFA the schematic of my design and waveform as well.
input is 650 hz and Vpp= 1.5V; continuous sine wave.
My output waveform appears to be distorted.
I'm not sure if there has to be a delay incorporated while sampling the input signal or a is the issue between FIFO and UART.
When WriteEn signal is asserted on FIFO, the full flag is asserted at the same instant, does that mean the size of FIFO is not enough.
Question
Archana Narayanan
Hello,
I am trying to interface MCP3008 with basys 3 using SPI and store the values in a FIFO and transmit the values to PC using UART.
Initially, I designed for ADC to convert input waveform and display results by increment or decrements of LED's. The MCP3008 ADC clock is 1.3 MHz clock.
This works and led's increment as the amplitude of the input waveform is increased from signal generator . But when i receive through UART and plot on SerialPlot , the signal is distorted
please find the code for ADC below:
entity ADC is port ( -- command input clock : in std_logic; -- 100MHz onboard oscillator trigger : in std_logic; -- assert to sample ADC diffn : in std_logic; -- single/differential inputs channel : in std_logic_vector(2 downto 0); -- channel to sample -- data output Dout : out std_logic_vector(14 downto 0); -- data from ADC OutVal : out std_logic; -- pulsed when data sampled -- ADC connection adc_miso : in std_logic; -- ADC SPI MISO adc_mosi : out std_logic; -- ADC SPI MOSI adc_cs : out std_logic; -- ADC SPI CHIP SELECT adc_clk : out std_logic -- ADC SPI CLOCK ); end ADC; architecture behavioural ofADC is -- clock signal adc_clock : std_logic := '0'; -- command signal trigger_flag : std_logic := '0'; signal sgl_diff_reg : std_logic; signal channel_reg : std_logic_vector(2 downto 0) := (others => '0'); signal done : std_logic := '0'; signal done_prev : std_logic := '0'; -- output registers signal val : std_logic := '0'; signal D : std_logic_vector(9 downto 0) := (others => '0'); -- state control signal state : std_logic := '0'; signal spi_count : unsigned(4 downto 0) := (others => '0'); signal Q : std_logic_vector(9 downto 0) := (others => '0'); begin -- clock divider -- input clock: 100Mhz --100MHz/1.3MHz = 74/2 -- adc clock: 1.3MHz clock_divider : process(clock) variable cnt : integer := 0; begin if rising_edge(clock) then cnt := cnt + 1; if cnt = 37 then cnt := 0; adc_clock <= not adc_clock; end if; end if; end process; -- produce trigger flag trigger_cdc : process(adc_clock) begin if rising_edge(adc_clock) then if trigger = '1' and state = '0' then sgl_diff_reg <= diffn; channel_reg <= channel; trigger_flag <= '1'; elsif state = '1' then trigger_flag <= '0'; end if; end if; end process; adc_clk <= adc_clock; adc_cs <= not state; -- SPI state machine (falling edge) adc_sm : process(adc_clock) begin if adc_clock'event and adc_clock = '0' then if state = '0' then done <= '0'; if trigger_flag = '1' then state <= '1'; else state <= '0'; end if; else if spi_count = "10000" then spi_count <= (others => '0'); state <= '0'; done <= '1'; else spi_count <= spi_count + 1; state <= '1'; end if; end if; end if; end process; -- Register sample outreg : process(adc_clock) begin if rising_edge(adc_clock) then done_prev <= done; if done_prev = '0' and done = '1' then D <= Q; Val <= '1'; else Val <= '0'; end if; end if; end process; -- LED outputs PROCESS (adc_clock) BEGIN IF (adc_clock'EVENT AND adc_clock = '1') THEN CASE D(9 DOWNTO 6) IS WHEN "0001" => Dout <= "000000000000011"; WHEN "0010" => Dout <= "000000000000111"; WHEN "0011" => Dout<= "000000000001111"; WHEN "0100" => Dout <= "000000000011111"; WHEN "0101" => Dout <= "000000000111111"; WHEN "0110" => Dout <= "000000001111111"; WHEN "0111" => Dout <= "000000011111111"; WHEN "1000" => Dout <= "000000111111111"; WHEN "1001" => Dout <= "000001111111111"; WHEN "1010" => Dout <= "000011111111111"; WHEN "1011" => Dout <= "000111111111111"; WHEN "1100" => Dout <= "001111111111111"; WHEN "1101" => Dout <= "011111111111111"; WHEN "1110" => Dout <= "111111111111111"; WHEN "1111" => Dout <= "111111111111111"; WHEN OTHERS => Dout <= "000000000000001"; END CASE; END IF; -- END IF; END PROCESS; OutVal <= Val; -- MISO shift register (rising edge) shift_in : process(adc_clock) begin if adc_clock'event and adc_clock = '1' then if state = '1' then Q(0) <= adc_miso; Q(9 downto 1) <= Q(8 downto 0); end if; end if; end process; -- Decode MOSI output shift_out : process(state, spi_count, sgl_diff_reg, channel_reg) begin if state = '1' then case spi_count is when "00000" => adc_mosi <= '1'; -- start bit when "00001" => adc_mosi <= sgl_diff_reg; when "00010" => adc_mosi <= channel_reg(2); when "00011" => adc_mosi <= channel_reg(1); when "00100" => adc_mosi <= channel_reg(0); when others => adc_mosi <= '0'; end case; else adc_mosi <= '0'; end if; end process; end behavioural; --much of the code is of credit to micronova electronics.
For fifo, I use the Xilinx IP fifo generator with no FWFT working on 100Mhz clock both on write and read sides.
FIFO width = 10
Depth = 2046 and tried increasing upto 131072 with no progress.
This is my top level code with UART
entity top_module is Generic ( PARITY_BIT : string := "none" -- type of parity ); port( clk, rst,trigger,diffn: in std_logic; adc_mosi,adc_clk,adc_cs : out std_logic; adc_miso : in std_logic; channel : in std_logic_vector ( 2 downto 0); wr_uart,uart_clk_en : in std_logic; WriteEn , ReadEn : in std_logic; full, empty : out std_logic; --w_data: in std_logic_vector(7 downto 0); Dout : inout std_logic_vector(9 downto 0); busy : out std_logic; tx,OutVal: out std_logic ); end top_module; architecture structural of top_module is signal fifo_data_out : STD_LOGIC_VECTOR (9 downto 0); component fifo is port ( reset_rtl_0 : in STD_LOGIC; clk_100MHz : in STD_LOGIC; full_0 : out STD_LOGIC; din_0 : in STD_LOGIC_VECTOR ( 9 downto 0 ); wr_en_0 : in STD_LOGIC; empty_0 : out STD_LOGIC; dout_0 : out STD_LOGIC_VECTOR ( 9 downto 0 ); rd_en_0 : in STD_LOGIC ); end component fifo; begin MercuryADC : entity work.ADC port map ( clock => clk, trigger => trigger, diffn => diffn, channel => channel, -- data output Dout => Dout, OutVal => Outval, -- ADC connection adc_miso => adc_miso, adc_mosi => adc_mosi, adc_cs => adc_cs, adc_clk =>adc_clk ); fifo_i: component fifo port map ( clk_100MHz => clk, din_0(9 downto 0) => Dout(9 downto 0), dout_0(9 downto 0) => fifo_data_out(9 downto 0), empty_0 => empty, full_0 => full, rd_en_0 => ReadEn, reset_rtl_0 => rst, wr_en_0 => WriteEn ); uart_trx : entity work.UART_TX Port map ( CLK => clk, -- system clock RST => rst, -- high active synchronous reset -- UART INTERFACE UART_CLK_EN => uart_clk_en, -- oversampling (16x) UART clock enable UART_TXD => tx, -- serial transmit data -- USER DATA INPUT INTERFACE DATA_IN =>fifo_data_out (9 downto 2) , -- input data DATA_SEND => wr_uart,-- when DATA_SEND = 1, input data are valid and will be transmit BUSY => busy -- when BUSY = 1, transmitter is busy and you must not set DATA_SEND to 1 ); end structural;
PFA the schematic of my design and waveform as well.
input is 650 hz and Vpp= 1.5V; continuous sine wave.
My output waveform appears to be distorted.
Kindly help, any inputs will be appreciated.
MCP3008(3).pdf
Link to comment
Share on other sites
4 answers to this question
Recommended Posts
Archived
This topic is now archived and is closed to further replies.