I have some troubles with my nexys 3 vhdl driver for the Pmod TMP. I would like to communicate with via SPI 3 wire (Clock, Reset and DQ (MISO/MOSI)) so I've wrote some code lines and test it using the leds to display receive data. But That don't work and I don't know why... I've made a state machine that, if it's the first time, send the configuration data and then send the word "start" to start convert, then I pass in receive configuration and take the convert data (temperature in binary) and finally send the "stop" word. And that start again without the send configuration because it's not the first time.
My state machine don't work, there is not receive data and I don't know why.
I'll be glad if you could help me.
Best regards.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity SPI is
port(
CLK : in std_logic;
RST : in std_logic;
SPI_SCK : out std_logic;
SPI_DQ: inout std_logic;
SPI_RST : out std_logic;
LED : out std_logic_vector(7 downto 0) :="00000000"
);
end entity SPI;
architecture behavioral of SPI is
type State is ( IDLE , sendConf, sendBit , receiveBit, clockHigh , resetHigh);
signal States : State := IDLE;
signal Counter : integer range 0 to 15 := 0;
signal data_reg : std_logic_vector(15 downto 0):="0000000000000000";
signal data : std_logic_vector(8 downto 0):="000000000";
signal data_trans : std_logic_vector(7 downto 0):="00000000";
signal first_time : std_logic := '1';
signal send : std_logic := '0';
signal receive : std_logic := '0';
signal right : std_logic := '0';
begin
process(CLK, RST)
variable conf : std_logic_vector(15 downto 0):= "0000110000000011";
variable start: std_logic_vector(7 downto 0):= "01010001";
variable stop : std_logic_vector(7 downto 0):= "00100010";
begin
if rising_edge(CLK) then
if RST = '1' then
States <= IDLE;
first_time <= '1';
else
case States is
when IDLE =>
SPI_RST <= '1';
SPI_SCK <= '0';
Counter <= 0;
if first_time = '1' then
data_reg <= conf;
send <= '1';
first_time <= '0';
States <= sendConf;
else
if send = '1' then
data_trans <= start;
send <= '0';
receive <= '1';
right <= '0';
States <= sendBit;
elsif receive = '1' then
receive <= '0';
right <= '1';
States <= receiveBit;
elsif send = '0' and receive = '0' then
data_trans <= stop;
send <= '1';
right <= '0';
States <= sendBit;
end if;
end if;
when sendConf =>
SPI_SCK <= '0';
SPI_DQ <= data_reg(15);
data_reg <= data_reg(14 downto 0) & "0";
States <= clockHigh;
when sendBit =>
SPI_SCK <= '0';
SPI_DQ <= data_trans(7);
data_trans <= data_trans(6 downto 0) & "0";
States <= clockHigh;
when receiveBit =>
SPI_SCK <= '0';
data <= data(7 downto 0) & SPI_DQ;
States <= clockHigh;
when clockHigh =>
SPI_SCK <= '1';
if first_time = '1' then
if Counter = 16 then
States <= resetHigh;
else
Counter <= Counter + 1;
States <= sendConf;
end if;
else
if right = '1' then
if Counter = 9 then
States <= resetHigh;
else
Counter <= Counter + 1;
States <= sendBit;
end if;
else
if Counter = 8 then
States <= resetHigh;
else
Counter <= Counter + 1;
States <= sendBit;
end if;
end if;
end if;
when resetHigh =>
SPI_RST <= '0';
States <= IDLE;
end case;
end if;
end if;
end process;
end architecture behavioral;`
The Maxim DS1626 does not communicate via SPI interface. So please look into data sheet pages 4, 5 and 10, 11. These timing diagrams are very different from SPI or I²C or whatever.
Related
Please forgive myself if you will find some trivial errors in my code .. I'm still a beginner with VHDL.
Well, I have to deal with a serial interface from an ADC. The interface is quite simple ... there is a wire for the serial data (a frame of 24 bits), a signal DRDY that tells me when the new sample data is available and a serial clock (SCLK) that push the bit into (rising edge). Everything is running continuously...
I need to capture correctly the 24 bit of the sample, put them on a parallel bus (shift register) and provide a "data valid" signal for the blocks that will process the samples ...
Due to the fact that my system clock is x4 the frequency of the serial interface, i was thinking that doing the job with a FSM will be easy ...
When you look into the code you will see a process to capture the rising edges of the DRDY and SCLK.
Then a FSM with few states (Init, wait_drdy, wait_sclk, inc_count, check_count).
I use a counter (cnt unsigned) to check if I've already captured the 24 bits, using also to redirect the states of the FSM in "check_count" state.
Here a picture:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity serial_ads1675 is
Port (
clk : in STD_LOGIC;
reset : in STD_LOGIC;
sclk : in std_logic;
sdata : in std_logic;
drdy : in std_logic;
pdata : out std_logic_vector(23 downto 0);
pdready : out std_logic
);
end serial_ads1675;
architecture Behavioral of serial_ads1675 is
-- Internal declarations
signal ipdata : std_logic_vector (23 downto 0);
signal ipdready : std_logic;
signal tmp1, tmp2, tmp3, tmp4 : std_logic;
signal rise_drdy, rise_sclk : std_logic;
signal cnt : unsigned (4 downto 0);
type state is (init, wait_drdy, wait_sclk, inc_count, check_count);
signal actual_state, next_state : state;
begin
-- Concurrent statements
pdata <= ipdata;
pdready <= ipdready;
rise_drdy <= '1' when ((tmp1 = '1') and (tmp2 = '0')) else '0';
rise_sclk <= '1' when ((tmp3 = '1') and (tmp4 = '0')) else '0';
-- Process
process (clk, reset)
begin
if(reset = '0') then
tmp1 <= '0';
tmp2 <= '0';
tmp3 <= '0';
tmp4 <= '0';
elsif (falling_edge(clk)) then
tmp1 <= drdy;
tmp2 <= tmp1;
tmp3 <= sclk;
tmp4 <= tmp3;
end if;
end process;
process (reset, clk)
begin
if (reset = '0') then
actual_state <= init;
elsif (rising_edge(clk)) then
actual_state <= next_state;
end if;
end process;
process (rise_sclk, rise_drdy) -- Next State affectation
begin
case actual_state is
when init =>
next_state <= wait_drdy;
ipdata <= (others => '0');
ipdready <= '0';
cnt <= (others => '0');
when wait_drdy =>
if (rise_drdy = '0') then
next_state <= actual_state;
else
next_state <= wait_sclk;
end if;
cnt <= (others => '0');
when wait_sclk =>
if (rise_sclk = '0') then
next_state <= actual_state;
else
next_state <= inc_count;
end if;
ipdready <= '0';
when inc_count =>
next_state <= check_count;
cnt <= cnt + 1;
ipdready <= '0';
ipdata(23 downto 1) <= ipdata(22 downto 0);
ipdata(0) <= sdata;
when check_count =>
case cnt is
when "11000" =>
next_state <= wait_drdy;
ipdready <= '1';
when others =>
next_state <= wait_sclk;
ipdready <= '0';
end case;
when others =>
next_state <= init;
end case;
end process;
end Behavioral;
My problem is during the check_count state ...
I'm expecting that this state should last one system clock cycle, but actually it last much more.
Here a snapshot of the behavioral simulation:
Due to the fact that this state last more than expected, i miss the following SCLK pulse and don't record the next bit ...
I don't understand why this state last so many system clock cycles instead of just one ...
Anyone has some clues and bring some light in my dark night ?
Thanks in advance.
Edit: I've tried to change the signal cnt for an integer variable internal to the process of the FSM ... Same results
The error is this:
process (rise_sclk, rise_drdy) -- Next State affectation
begin
-- code omitted, but does generally this:
next_state <= SOME_VALUE;
end process;
Because the sensitivity list includes only the signals rise_sclk and rise_drdy, the process is "executed" only if any of these signals changes. You can follow this in the wave diagram.
You don't have a synchronous design running on clk. Put clk on the sensitivity list and base the decisions on the levels of rise_sclk and rise_drdy. As an excerpt:
process (clk) -- Next State affectation
begin
if rising_edge(clk) then
case actual_state is
when init =>
next_state <= wait_drdy;
-- and so on
end case;
end if;
end process;
I'm making a custom hardware ARINC 429 Core.
For now I have described the module in transmission (TX-FSM), according to the ARINC 429 standard and a FIFO in transmission from which it takes the data and sends them to the outside.
The FIFO works at a frequency of 2MHz (clk2M), while TX-FSM can generate a frequency of 100kb / s or 12.5kb / s (clk429) from 2MHz as per standard.
Since the FIFO works at a higher frequency (2 MHz), and the TX-FSM works at a lower frequency (100 kb/s), when the TX-FSM requests a data from the FIFO by raising the "TX_FIFO_rd" signal ("rd_en" on FIFO ), the FIFO supplies all the data contained within it, since in the FIFO clock domain the "rd_en" signal remains high for several cycles.
The FIFO should only provide one data at a time. Once the data has been transmitted, the TX-FSM will request the next data.
How can I make the FIFO and TX-FSM work in sync using a single clock?
FIFO VHDL code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FIFO is
generic (
FIFO_WIDTH : natural := 32;
FIFO_DEPTH : integer := 10;
ALMOST_FULL_LEVEL : integer := 8;
ALMOST_EMPTY_LEVEL : integer := 2
);
port (
reset : in std_logic;
clk : in std_logic;
-- FIFO Write Interface
wr_en : in std_logic;
wr_data : in std_logic_vector(FIFO_WIDTH-1 downto 0);
ALMOST_FULL : out std_logic;
FULL : out std_logic;
-- FIFO Read Interface
rd_en : in std_logic;
rd_data : out std_logic_vector(FIFO_WIDTH-1 downto 0);
ALMOST_EMPTY : out std_logic;
EMPTY : out std_logic
);
end FIFO;
architecture rtl of FIFO is
type t_FIFO_DATA is array (0 to FIFO_DEPTH) of std_logic_vector(FIFO_WIDTH-1 downto 0);
signal r_FIFO_DATA : t_FIFO_DATA := (others => (others => '0'));
signal r_WR_INDEX : integer range 0 to FIFO_DEPTH -1 := 0;
signal r_RD_INDEX : integer range 0 to FIFO_DEPTH -1 := 0;
-- # Words in FIFO, has extra range to allow for assert conditions
signal r_FIFO_COUNT : integer range -1 to FIFO_DEPTH+1 := 0;
signal w_FULL : std_logic;
signal w_EMPTY : std_logic;
begin
-- FIFO process
-------------------------------------------------------------------
-------------------------------------------------------------------
WRITE_INDEX : process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
r_WR_INDEX <= 1;
else
if (wr_en = '1' and w_FULL = '0') then
if r_WR_INDEX = FIFO_DEPTH-1 then
r_WR_INDEX <= 1;
else
r_WR_INDEX <= r_WR_INDEX + 1;
end if;
end if;
end if;
end if;
end process;
READ_INDEX : process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
r_RD_INDEX <= 0;
else
if (rd_en = '1' and w_EMPTY = '0') then
if r_RD_INDEX = FIFO_DEPTH-1 then
r_RD_INDEX <= 0;
else
r_RD_INDEX <= r_RD_INDEX + 1;
end if;
end if;
end if;
end if;
end process;
COUNT_INDEX : process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
r_FIFO_COUNT <= 0;
else
if (wr_en = '1' and rd_en = '0') then
r_FIFO_COUNT <= r_FIFO_COUNT + 1;
elsif (wr_en = '0' and rd_en = '1') then
if r_FIFO_COUNT > 0 then
r_FIFO_COUNT <= r_FIFO_COUNT - 1;
end if;
end if;
end if;
end if;
end process;
Write_Data : process (clk) is
begin
if rising_edge(clk) then
if wr_en = '1' then
r_FIFO_DATA(r_WR_INDEX) <= wr_data;
end if;
end if;
end process;
rd_data <= r_FIFO_DATA(r_RD_INDEX);
w_FULL <= '1' when r_FIFO_COUNT = FIFO_DEPTH else '0';
w_EMPTY <= '1' when r_FIFO_COUNT = 0 else '0';
ALMOST_FULL <= '1' when r_FIFO_COUNT > ALMOST_FULL_LEVEL else '0';
ALMOST_EMPTY <= '1' when r_FIFO_COUNT < ALMOST_EMPTY_LEVEL else '0';
FULL <= w_FULL;
EMPTY <= w_EMPTY;
end rtl;
TX-FSM code
-- Arinc 429 trasmitter interface
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Tx is
port
(
--INPUT
clk2M : in std_logic; -- clock signal
reset : in std_logic; -- reset signal
enable : in std_logic; -- enable signal
en_parity : in std_logic; -- enable parity bit
parity : in std_logic; -- odd/even parity
speed : in std_logic; -- speed 100kbps or 12.5kbps
gap : in std_logic; -- gap between two messages: 4 or 64 bit of gap
TX_FIFO_ep : in std_logic; -- TX FIFO EMPTY
a429TX_in : in std_logic_vector (31 downto 0); -- data in
--OUTPUT
a429TX_outA : out std_logic; -- positive out
a429TX_outB : out std_logic; -- negative out
TX_FIFO_rd : out std_logic -- TX FIFO READ
);
end entity;
architecture RTL_A429TX of Tx is
-- FSM state name
type state_type is (IDLE,START, PAR,TRANSMITTING,WAITING);
signal state : state_type;
-- FSM register
signal shift_reg : std_logic_vector (31 downto 0);
signal shift_counter : std_logic_vector (4 downto 0);
signal gap_counter : std_logic_vector (6 downto 0);
-- speed clock register
signal clk429 : std_logic;
signal clk429_counter : integer;
signal clk429_max_count : integer;
signal clk429_half_count : integer;
begin
-- speed clock process
-------------------------------------------------------------------
-------------------------------------------------------------------
-- select speed process
process (speed)
begin
if (speed = '1') then
clk429_max_count <= 19; -- 100kbs/s
clk429_half_count <= 10;
else
clk429_max_count <= 159; -- 12.5kbs/s
clk429_half_count <= 80;
end if;
end process;
-- clock429 generate speed process
process (clk2M, reset)
begin
if (reset = '1') then
clk429 <= '0';
elsif rising_edge(clk2M) then
if (clk429_counter <= clk429_half_count ) then
clk429 <= '1';
else
clk429 <= '0';
end if;
end if;
end process;
-- counter activity process
process (clk2M, reset)
begin
if (reset = '1') then
clk429_counter <= 0;
elsif rising_edge(clk2M) then
if (clk429_counter >= clk429_max_count) then
clk429_counter <= 0;
else
clk429_counter <= clk429_counter + 1;
end if;
end if;
end process;
-------------------------------------------------------------------
-------------------------------------------------------------------
-- a429TX interface process
process (clk429, reset)
variable p : std_logic;
begin
if reset = '1' then
state <= IDLE;
shift_reg <= (others => '0');
shift_counter <= (others => '0');
gap_counter <= (others => '0');
a429TX_outA <= '0';
a429TX_outB <= '0';
TX_FIFO_rd <= '0';
elsif rising_edge(clk429) then
case state is
when IDLE => -- idle state
if (enable = '1') then
if (gap = '1') then
gap_counter <= "0000100"; -- 4
else
gap_counter <= "1000000"; -- 64
end if;
if TX_FIFO_ep = '0' then
TX_FIFO_rd <= '1';
state <= START;
else
state <= IDLE;
end if;
else
state <= IDLE;
end if;
when START =>
-- data formatting
TX_FIFO_rd <= '0';
shift_reg <= a429TX_in(31 downto 8)& a429TX_in(0) & a429TX_in(1) & a429TX_in(2) & a429TX_in(3) & a429TX_in(4) & a429TX_in(5) & a429TX_in(6) & a429TX_in(7);
shift_counter <= "11111";
if ( en_parity = '1') then
state <= PAR;
else
state <= TRANSMITTING;
end if;
when PAR => -- parity state
--TX_FIFO_rd <= '0';
p := '0';
for I in 31 downto 0 loop
p := p xor shift_reg(I);
end loop;
if (parity = '1') then
shift_reg(31) <= p; -- odd
else
shift_reg(31) <= not p; -- even
end if;
state <= TRANSMITTING;
when TRANSMITTING => -- transmission state
--TX_FIFO_rd <= '0';
a429TX_outA <= shift_reg(0);
a429TX_outB <= not shift_reg(0);
shift_reg <= shift_reg(0) & shift_reg(31 downto 1);
if (shift_counter = "00000") then
state <= WAITING;
else
shift_counter <= shift_counter -1;
state <= TRANSMITTING;
end if;
when WAITING => -- wait state. generate gap
a429TX_outA <= '0';
a429TX_outB <= '0';
if (gap_counter > 0) then
gap_counter <= gap_counter - 1;
state <= WAITING;
else
state <= IDLE;
end if;
when others => -- default
state <= IDLE;
end case;
elsif falling_edge (clk429) then
a429TX_outA <= '0';
a429TX_outB <= '0';
end if;
end process;
clk429 <= clk429;
end architecture;
Thanks for your help.
Run both FIFOs at the 2 MHz clk2M, and then generate a single cycle enable indication on TX_FIFO_rd when FIFO read data transfer is required.
Thereby you can get the benefit from synchronous design, without the hazzle of handling multiple clock domains.
Also, it is not good (but actually very bad :-) synchronous design practice to generate internal clock like the clk429, since it results in error prune design and more complex timing closure with Static Timing Analysis (STA). Instead make an enable signal that is asserted a single cycle, run the design on the clk2M, and the only update the relevant state when the enable signal is high.
I'm newbie in FPGAs and VHDL. This time, I m trying to send Data from FPGA to TTL. I' m using GPIO pins for TX and GND and Data can be changed with switch on FPGA. My issue is whenever i press the button on FPGA, I always see FF on terminal. I couldn't find where the problem is.
Here is TX code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
entity UART_Tx is
port(
CLK : in std_logic;
Reset : in std_logic;
Button : in std_logic;
Data : in std_logic_vector(7 downto 0);
Out_Tx : out std_logic
);
end entity;
Architecture Behavioral of UART_Tx is
constant Baudrate : integer := 9600;
constant CLK_Hiz : integer := 50000000;
constant CLK_Bit : integer := (CLK_Hiz / Baudrate) + 1;
signal tx_Data_ind : integer range 0 to 7;
signal counter_baud : integer range 0 to (CLK_Bit - 1) := 0;
signal shift_button : std_logic_vector (3 downto 0) := (others => '0');
signal button_out : std_ulogic := '1';
signal baud_pulse : std_ulogic := '0';
signal tx_enable : std_ulogic := '0';
signal tx_Data : std_logic_vector (7 downto 0) := (others => '0');
signal tx_cikis : std_ulogic;
signal tx_tamam : std_ulogic := '0';
signal counter_sil : std_ulogic := '0';
begin
process(CLK, Reset)
begin
if (Reset = '0') then
baud_pulse <= '0';
counter_baud <= 0;
elsif (rising_edge(CLK)) then
if (counter_baud < (CLK_Bit - 1)) then
counter_baud <= counter_baud + 1;
baud_pulse <= '0';
else
counter_baud <= 0;
baud_pulse <= '1';
end if;
if (counter_sil = '1') then
counter_baud <= 0;
end if;
end if;
end process;
process(CLK, Reset)
begin
if (Reset = '0') then
tx_Data <= (others => '0');
tx_data_ind <= 0;
tx_enable <= '0';
elsif (rising_edge(CLK)) then
tx_cikis <= '1';
out_tx <= tx_cikis;
shift_button(3) <= button;
shift_button(2 downto 0) <= shift_button(3 downto 1);
if shift_button(3 downto 0) = "001" then
button_out <= '0';
end if;
if (button_out = '0') then
counter_sil <= '1';
tx_cikis <= '0';
if (tx_cikis = '0') then
tx_enable <= '1';
end if;
if (tx_enable = '1') then
counter_sil <= '0';
tx_Data <= Data;
if (baud_pulse = '1') then
tx_cikis <= tx_Data(tx_Data_ind);
if (tx_data_ind < 7) then
tx_Data_ind <= tx_Data_ind + 1;
else
tx_tamam <= '1';
end if;
if (tx_tamam = '1') then
tx_Data <= (others => '0');
tx_Data_ind <= 0;
tx_enable <= '0';
button_out <= '1';
tx_cikis <= '1';
end if;
end if;
end if;
end if;
end if;
end process;
end Architecture;
Here is Testbench code:
library ieee;
use ieee.std_logic_1164.all;
entity tb_UART_Tx is
end tb_UART_Tx;
architecture tb of tb_UART_Tx is
component UART_Tx
port (CLK : in std_logic;
Reset : in std_logic;
Button : in std_logic;
Data : in std_logic_vector (7 downto 0);
Out_Tx : out std_logic);
end component;
signal CLK : std_logic:='0';
signal Reset : std_logic:='1';
signal Button : std_logic:='1';
signal Data : std_logic_vector (7 downto 0);
signal Out_Tx : std_logic;
constant TbPeriod : time := 20 ns;
signal TbSimEnded : std_logic := '0';
begin
dut : UART_Tx
port map (CLK => CLK,
Reset => Reset,
Button => Button,
Data => Data,
Out_Tx => Out_Tx);
clk_process: process
begin
CLK <= '0';
wait for TbPeriod/2;
CLK <= '1';
wait for TbPeriod/2;
end process;
stimuli : process
begin
Reset <= '0';
wait for 20 ns;
Button <= '1';
Data <= "00110000";
wait for 30 ns;
Button <= '0';
wait for 50 ns;
Button <= '1';
wait for 1000 ns;
-- Button <= '0';
-- wait for 30 ns;
-- Button <= '1';
TbSimEnded <= '1';
wait;
end process;
end tb;
configuration cfg_tb_UART_Tx of tb_UART_Tx is
for tb
end for;
end cfg_tb_UART_Tx;
Added Testbench results
EDIT: HERE is the working code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
entity UART_Tx is
port(
CLK: in std_logic;
nReset: in std_logic;
nButton: in std_logic;
Data: in std_logic_vector (7 downto 0);
Data_Tx: out std_logic
);
end UART_Tx;
architecture Behavioral of UART_Tx is
constant Baudrate: integer:= 9600;
constant CLK_Hiz: integer:= 50000000;
constant CLK_Bit: integer:= (CLK_Hiz / Baudrate) + 1;
signal tx_counter: integer range 1 to 9:= 1;
signal counter_baud: integer range 0 to (CLK_Bit - 1):= 0;
signal shift_nButton:std_logic_vector (3 downto 0):= (others => '1');
signal tx_reg: std_logic_vector (7 downto 0):= (others => '0');
signal nButton_out: std_ulogic:= '1';
signal baud_pulse: std_ulogic;
signal tx_out: std_ulogic:= '1';
signal counter_del: std_ulogic;
signal start_bit: std_ulogic:='0';
signal data_bit: std_ulogic:='0';
signal stop_bit: std_ulogic:='0';
begin
process(CLK,nReset)
begin
if(nReset = '0') then
baud_pulse <= '0';
counter_baud <= 0;
elsif(rising_edge(CLK)) then
if(counter_baud < (CLK_Bit - 1)) then
counter_baud <= counter_baud + 1;
baud_pulse <= '0';
else
counter_baud <= 0;
baud_pulse <= '1';
end if;
if(counter_del = '1') then
counter_baud <= 0;
end if;
end if;
end process;
process(CLK, nReset)
begin
Data_Tx <= tx_out;
if(nReset = '0') then
tx_reg <= (others => '0');
tx_counter <= 1;
elsif(rising_edge(CLK)) then
shift_nButton(3) <= nButton;
shift_nButton(2 downto 0) <= shift_nButton(3 downto 1);
if shift_nButton(2 downto 0) = "001" then
nButton_out <= '0';
counter_del <= '1';
start_bit <= '1';
end if;
if(nButton_out = '1') then
tx_out <= '1';
elsif(nButton_out = '0') then
counter_del <= '0';
if(start_bit = '1') then
tx_out <= '0';
tx_reg <= Data;
if(baud_pulse = '1') then
start_bit <= '0';
data_bit <= '1';
end if;
end if;
if(data_bit = '1')then
if(tx_counter > 0 and tx_counter < 10) then
tx_out <= tx_reg((tx_counter)-1);
if(baud_pulse = '1') then
tx_counter <= tx_counter + 1;
if(tx_counter = 9)then
data_bit <= '0';
stop_bit <= '1';
end if;
end if;
end if;
end if;
if(stop_bit = '1') then
tx_out <= '1';
tx_counter <= 1;
if(baud_pulse = '1') then
stop_bit <= '0';
nButton_out <= '1';
tx_reg <= (others => '0');
end if;
end if;
end if;
end if;
end process;
end Behavioral;
i'm trying to make my own I2C communication and i have a problem with multiply drivers, it's not like i don't understand them i just don't see them (i'm still fresh at vhdl), so please just take a look at my code and tell mi why is there such mistake.
i try to operate on flags to have multiple signal drivers on bus but there's just something not right. The multiple drivers are on scl, sda, start_clk and stop_clk. Is it because those flags are for example in two different processes?
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity I2C_com is
port (
reset_en: in std_logic;
clk: in std_logic;
sda: inout std_logic;
scl: out std_logic;
RD:in std_logic;
WR: in std_logic;
addr: buffer std_logic_vector(7 downto 0)
);
end I2C_com;
architecture MAIN of I2C_com is
signal data :std_logic_vector (12 downto 0):="0000000000010";
signal i2c_clk: std_logic ;
signal clk_count : unsigned(19 downto 0):="00000000000000000100";
type program_state is (start,init,error_rd_wr,slave,ack);
signal state: program_state;
signal write_data: std_logic_vector (7 downto 0):=(others => '0');
signal read_data: std_logic_vector (7 downto 0):=(others => '0');
signal clk_enable: std_logic;
signal reset: std_logic:='1';
signal start_clk: std_logic:= 'Z';
signal stop_clk: std_logic:= 'Z';
signal strech: std_logic := '0';
signal cnt_addr: integer := 0;
signal ack_error: std_logic;
signal sda_data: std_logic;
signal start_data: std_logic:= 'Z';
begin
i2c_clock: process(clk,reset_en,reset)
begin
if reset_en = '1' or reset = '1' then
elsif falling_edge(clk) then
if clk_count < unsigned(data) then
clk_count <= clk_count + 1;
clk_enable <= '1';
else
clk_count <= x"00000";
clk_enable <= '0';
end if;
i2c_clk <= clk_enable;
if start_clk = '1' then
sda <= '0';
scl <= '0';
start_clk <= '0';
end if;
if stop_clk = '1' then
sda <= '0';
scl <= '0';
stop_clk <= '0';
end if;
end if;
end process i2c_clock;
--
process(i2c_clk,reset_en,reset)
begin
if reset_en = '1' or reset = '1' then
reset <= '0';
cnt_addr <= 0;
state <= init;
elsif rising_edge(i2c_clk) then
case state is
when init =>
if RD = '1' or WR = '1' then
state <= start;
else
state <= error_rd_wr;
end if;
when start =>
start_clk <= '1';
state <= slave;
when slave =>
start_data <= '1';
if cnt_addr < 8 then
sda_data <= addr(cnt_addr);
cnt_addr <= cnt_addr + 1;
else
cnt_addr <= 0;
state <= ack;
end if;
when error_rd_wr =>
reset <= '1';
when ack =>
start_data <= '0';
ack_error <= sda;
if ack_error = '1' then
stop_clk <= '1';
reset <= '1';
else
end if;
if RD = '1' then
elsif WR = '1' then
else
stop_clk <= '1';
reset <= '1';
end if;
end case;
end if;
end process;
sda <= sda_data when start_data = '1' else 'Z';
scl <= i2c_clk when start_clk = '0' and stop_clk = '0' else 'Z';
end MAIN;
A signal for synthesis can be driven from only one process or one continuous assign; for simulation multiple drivers are possible using resolved signals like std_logic.
The scl and sda are driven both from the i2c_clock process and the continuous assign in the end of the file.
The start_clk and stop_clk are driven both from the i2c_clock process and the other unnamed process.
One possibility for scl and sda is to only drive these from the continuous assign, since synthesis tools often prefer tri-state output to be written like:
q <= value when en = '1' else 'Z';
I am new to VHDL. I need to write a module to do filtering of data. My module structure is:
a_rst - async reset
clk - clock
s_rst - sync reset
valid_in - 0 - no data, 1 - where is data
data_in - [7 downto 0]
Out signals:
valid_out - 0 - no data, 1 - where is data
data_out - [7 downto 0]
I write testbeanch which puts to data_in of my module: 00,01,02,03,0A,02,00,01,02,0F.
But my module returns: 00,01,AA,03,0A,02,00,01,AA,0F
insted of: 00,01,AA,03,0A,02,00,01,02,0F.
I tried to do this:
--libraries
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--entity
entity ex6_v03 is
port
(
a_rst : in std_logic;
clk : in std_logic; -- 200 MHz
s_rst : in std_logic;
valid_in : in std_logic;
data_in : in std_logic_vector (7 downto 0);
valid_out : out std_logic;
data_out : out std_logic_vector (7 downto 0)
);
end entity ex6_v03;
architecture behavior of ex6_v03 is
signal st : integer := 0;
begin
process(a_rst, clk)
begin
-- asynchronous reset
if (a_rst = '1') then
data_out <= x"00";
valid_out <= '0';
-- synchronous reset
elsif rising_edge(clk) then -- clk
if (s_rst = '1') then
valid_out <= '0';
data_out <= x"00";
else
-- normal activity
if(valid_in = '1') then
-- main logic
if(data_in = x"00") then
st <= 1;
valid_out <= '1';
data_out <= data_in;
elsif(st = 1 and data_in = x"01") then
st <= 2;
valid_out <= '1';
data_out <= data_in;
elsif(st = 2 and data_in = x"02") then
st <= 3;
valid_out <= '1';
data_out <= x"AA";
elsif(st = 3 and data_in = x"03") then
valid_out <= '1';
data_out <= data_in;
st <= 0;
else
st <= 0;
valid_out <= '1';
data_out <= data_in;
end if;
-- end main logic
else
valid_out <= '0';
data_out <= x"00";
end if;
end if;
end if;
end process;
end architecture behavior;
But my module do not wait for 0x03 and instantly sends 0xAA. How to fix this?
You need to add a 1 clock cycle buffer so you know if the next input is 03 before you choose whether to send 02 or AA. Of course, this means the output wont appear until 2 cycles after the input instead of only one. See revised code:
--libraries
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--entity
entity ex6_v03 is
port
(
a_rst : in std_logic;
clk : in std_logic; -- 200 MHz
s_rst : in std_logic;
valid_in : in std_logic;
data_in : in std_logic_vector (7 downto 0);
valid_out : out std_logic;
data_out : out std_logic_vector (7 downto 0)
);
end entity ex6_v03;
architecture behavior of ex6_v03 is
signal st : integer := 0;
signal bvalid : std_logic := '0'; --is buffer valid?
signal data_buffer : std_logic_vector (7 downto 0); --data from previous cycle
begin
process(a_rst, clk)
begin
if (a_rst = '1') then -- asynchronous reset
data_out <= x"00";
valid_out <= '0';
bvalid <= '0';
elsif rising_edge(clk) then -- clk
if (s_rst = '1') then --sync reset
valid_out <= '0';
bvalid <= '0';
data_out <= x"00";
else -- normal activity
if(valid_in = '1') then --fill buffer
if(data_in = x"00") then
st <= 1;
data_out <= data_in;
elsif(st = 1 and data_in = x"01") then
st <= 2;
data_out <= data_in;
elsif(st = 2 and data_in = x"02") then
st <= 3;
else
st <= 0;
end if;
data_buffer <= data_in;
bvalid <= '1';
else
bvalid <= '0';
end if;
if(bvalid = '1') then --use buffer to populate output
valid_out <= '1'
if(st = 3 and data_in = x"03" and valid_in = '1') then --EDIT: make sure the x"03" sitting on the input is actually valid
data_out <= x"AA"; --output for the previous cycle (buffer contains x"02")
else
data_out <= data_buffer;
end if
else
valid_out <= '0';
data_out <= x"00";
end if;
end if;
end if;
end process;
end architecture behavior;