Synthesised Synthesis/Implementation - vhdl

I'm attempting to create an I2C Bus, however I've stumbled into a very awkward problem - during the mapping part of implementation I get the warning that MapLib:701 - Signal SDA connected to top level port SDA has been removed.
After digging back through, I found this was caused by a previous warning in the I2C Master itself: Xst:1293 - FF/Latch <sda_internal> has a constant value of 1 in block <IIC_MASTER>. This FF/Latch will be trimmed during the optimization process. On looking through, it seems that the entire state machine has been optimized away - why is this and how can I stop it? In the logic simulation below, it works as expected and I have no idea exactly what I've done that makes it think that the entire state machine is redundant!.
I've put the image of what I expect to see below, and then the two code blocks describing the I2C Master block and the top level block. Any help at all is massively appreciated!
Top Level
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY I2CBus IS
PORT(
SYSCLK_N : IN STD_LOGIC; --system 200MHz differential clock
SYSCLK_P : IN STD_LOGIC;
BTN : IN STD_LOGIC; -- to manually change reset
LED : OUT STD_LOGIC; --to observe reset value
SCL : OUT STD_LOGIC;
SDA : INOUT STD_LOGIC
);
END I2CBus;
ARCHITECTURE behavior OF I2CBus IS
-------------------DECLARE MASTER & SLAVE COMPONENTS------------------------
COMPONENT IIC_MASTER
PORT(SCL : IN STD_LOGIC;
SCL2X : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
ENA : IN STD_LOGIC;
ADR : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
REG : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
RW : IN STD_LOGIC;
DAT_WR : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
BUSY : OUT STD_LOGIC;
SDA : INOUT STD_LOGIC;
ACK_ERR : BUFFER STD_LOGIC);
END COMPONENT IIC_MASTER;
COMPONENT DCM
PORT(
SYSCLK_P : IN STD_LOGIC; -- CLOCK IN PORTS 200MHZ DIFFERENTIAL
SYSCLK_N : IN STD_LOGIC;
-- CLOCK OUT PORTS
SYSCLK : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT CLK_DIVIDER
GENERIC(INPUT_FREQ : INTEGER;
OUT1_FREQ : INTEGER;
OUT2_FREQ : INTEGER);
PORT(SYSCLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
OUT1 : OUT STD_LOGIC;
OUT2 : OUT STD_LOGIC);
END COMPONENT CLK_DIVIDER;
-------------------I2C MASTER ONLY SIGNALS-----------------
--Inputs
signal reset_n : std_logic; --active high
--Outputs
signal busy : std_logic;
signal ack_err : std_logic;
-----------------------------------------------------------
signal SCL_internal : std_logic;
signal SCL2X_internal : std_logic;
signal sysclk : std_logic;
BEGIN
--------------------I2C_master Instantiation-------------------
master : IIC_Master
port map(
SCL => SCL_internal, --map constant data to send over I2C for now
SCL2X => SCL2X_internal,
RESET_N => RESET_N,
ENA => '1', --hold enable on
ADR => "1011001", --keep address constant
REG => x"AA", --keep target register constant
RW => '0', --always read
DAT_WR => x"77", --keep data to send constant
BUSY => BUSY,
SDA => SDA,
ACK_ERR => ACK_ERR
);
DCM_CLK : DCM
port map(
SYSCLK_P => SYSCLK_P,
SYSCLK_N => SYSCLK_N,
SYSCLK => sysclk --generate 200 MHz clock from system clocks
);
Clk_Div : Clk_Divider --Divide 200MHz clock down to frequencies that can be
generic map( --seen on an oscilloscope
INPUT_FREQ => 200000000, --200 MHz input
OUT1_FREQ => 10, --10 Hz output
OUT2_FREQ => 20 --20 Hz output
)
port map(
SYSCLK => sysclk, --system clock
RESET_N => reset_n, --reset
OUT1 => scl_internal,
OUT2 => scl2x_internal
);
----------------Mappings---------------------------
reset_n <= not BTN; --reset low when button pressed
LED <= not reset_n; --light LED when reset
SCL <= 'Z' when scl_internal = '1' else scl_internal;
end behavior;
I2C Master Block
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity IIC_MASTER IS
PORT(SCL : IN STD_LOGIC; --SCL clock
SCL2X : IN STD_LOGIC; --SCL x2 rate clock
RESET_N : IN STD_LOGIC; --ACTIVE LOW
ENA : IN STD_LOGIC; --ENABLE ACTIVE HIGH
ADR : IN STD_LOGIC_VECTOR(6 DOWNTO 0); --TARGET ADDRESS
REG : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --TARGET REGISTER
RW : IN STD_LOGIC; --READ LOW, WRITE HIGH
DAT_WR : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --DATA TO WRITE TO SLAVE
BUSY : OUT STD_LOGIC; --HIGH WHEN BUSY
SDA : INOUT STD_LOGIC; --SERIAL DATA ON BUS
ACK_ERR : BUFFER STD_LOGIC); --FLAG IF WRONG ACK FROM SLAVE
END IIC_MASTER;
architecture BEHAVIORAL of IIC_MASTER is
type state is (begn, ready, start, command, cmd_ack, reg_cmd, reg_ack, wr, rd, data_ack, stop);
signal i2cstate : state;
signal sda_internal : std_logic := '1'; --internal SDA
signal scl_internal : std_logic;
signal scl2x_internal : std_logic;
signal addr_rw : std_logic_vector(7 downto 0); --latched address (6-0) + rw (7)
signal reg_tx : std_logic_vector(7 downto 0); --latched slave register
signal data_tx : std_logic_vector(7 downto 0); -- data to write to slave
signal bit_cnt : integer range 0 to 7 := 7; --number of bits sent in transaction
begin
------state machine logic & writing to SDA on data clk rising edge-----
state_machine : process(scl2x_internal)
begin
if falling_edge(scl2x_internal) then
if reset_n = '0' then --when reset is low, set to ready i2cstate <= ready; --NOT IN TEMPLATE
busy <= '1'; --set to busy
sda_internal <= '1'; --disable sda to Z
ACK_ERR <= '0'; --clear error/ack flag
bit_cnt <= 7; --reset bit count
i2cstate <= ready;
else
if scl_internal = '0' then --in middle of clock low
case i2cstate is
when begn => i2cstate <= ready; --unconditional transition
when ready => if ENA = '1' then
BUSY <= '1'; --set busy
addr_rw <= ADR & RW; --get address & rw (concatenate)
reg_tx <= REG; --get target register
data_tx <= DAT_WR; --Collect data to write from port
i2cstate <= start; --update state
else
BUSY <= '0'; --set not busy
i2cstate <= ready; --remain ready
end if;
when start =>
BUSY <= '1'; --ensure busy remains on
bit_cnt <= 7; --reset bit counter for bytes
ACK_ERR <= '0';
sda_internal <= addr_rw(bit_cnt); --put first command bit on bus
i2cstate <= command; -- also an unconditional transition
when command =>
if bit_cnt = 0 then
sda_internal <= '1'; --set high for acknowledge
bit_cnt <= 7; --reset bit counter for bytes
i2cstate <= cmd_ack;
else
bit_cnt <= bit_cnt - 1; --decrement bit count
sda_internal <= addr_rw(bit_cnt - 1); --send next address bit on bus
i2cstate <= command; --stay in this state until command is sent
end if;
when cmd_ack =>
sda_internal <= reg_tx(bit_cnt); --write first register bit
i2cstate <= reg_cmd; --go to register sending state
when reg_cmd =>
if bit_cnt = 0 then --register transmitted
sda_internal <= '1'; --release internal sda for acknowledgement
bit_cnt <= 7; --reset bit count
i2cstate <= reg_ack; --go to reg ack
else
bit_cnt <= bit_cnt - 1; --decrement
sda_internal <= reg_tx(bit_cnt - 1); --write next reg bit to bus
i2cstate <= reg_cmd; --keep writing
end if;
when reg_ack =>
if addr_rw(0) = '0' then -- if read/write is high, read
sda_internal <= data_tx(bit_cnt); --write first data bit
i2cstate <= wr; -- go to write state
else --else if low, write
sda_internal <= '1'; --release internal sda for reading
i2cstate <= rd; --go to read state
end if;
when wr =>
BUSY <= '1'; --ensure busy flag still high
if bit_cnt = 0 then --byte transmitted
sda_internal <= '1'; --release internal sda for acknowledgement
bit_cnt <= 7; --reset bit count
BUSY <= '0'; -- data all written, so lower busy to notify others
i2cstate <= data_ack; --go to slav ack
else
bit_cnt <= bit_cnt - 1; --decrement
sda_internal <= data_tx(bit_cnt - 1); --write next bit to bus
i2cstate <= wr; --keep writing
end if;
when rd => null;
when data_ack => --acknowledge write
if ENA = '1' then --continue transaction
BUSY <= '0'; -- accept continue by keeping busy low
addr_rw <= ADR & RW; --fetch next address & command
data_tx <= DAT_WR; --fetch next data to write
reg_tx <= REG; --fetch next register
if addr_rw = ADR & RW and reg_tx = REG then --if the same location
sda_internal <= DAT_WR(bit_cnt); --write first bit of data
i2cstate <= wr; --go to write state
else --continue next transaction with a new read/write or slave
i2cstate <= start; --continue from start
end if;
else
i2cstate <= stop; --transaction done, go to end
sda_internal <= '0';
end if;
when stop =>
BUSY <= '0'; --set not busy
i2cstate <= ready;
end case;
elsif scl_internal = '1' then --in middle of clock high
case i2cstate is
when start => sda_internal <= '0';
when stop => sda_internal <= '1';
when cmd_ack | reg_ack | data_ack =>
if (SDA /= '0' or ACK_ERR = '1') then
ACK_ERR <= '1'; --no acknowledge or prev. error
end if;
when others => null;
end case;
end if;
end if;
end if;
end process;
scl_internal <= '1' when SCL = 'Z' else SCL;
scl2x_internal <= '1' when SCL2X = 'Z' else SCL2X;
SDA <= 'Z' when sda_internal = '1' else '0';
end BEHAVIORAL;

scl_internal <= '1' when SCL = 'Z' else SCL;
scl2x_internal <= '1' when SCL2X = 'Z' else SCL2X;
You cannot test for equality to 'Z' and synth should warn about these. Simulation can, but there is no hardware block that works that way for synthesis to use.
I2C signals use a WIRED-OR convention, you drive 'Z' but you must test for '0' or '1' Specifically, logic high can be represented by either 'H' or '1', the former being a weak form of '1'. This means that testing for '1' may synthesise to the right thing, but simulation will no longer work...
So what's happening is that synthesis is seeing invalid logic for SCL, which allows it to delete the lot.
Solutions:
First, in your testbench, drive 'H' on SCL and SDA permanently. Because it's weak, (like a pullup), '0' can override it.
Secondly, either explicitly test for '0' :
scl_internal <= 0 when SCL = '0' else '1';
scl2x_internal <= '0' when SCL2X = '0' else '1';
or explicitly test for 'H' as well as '1'
scl_internal <= '1' when SCL = 'H' or SCL = '1' else SCL;
scl2x_internal <= '1' when SCL2X = 'H' or SCL2X = '1' else SCL2X;
or use the "to_01xz" function to collapse 'H' and '1' into the same value
scl_internal <= '1' when to_01xz(SCL) = '1' else SCL;
scl2x_internal <= '1' when to_01xz(SCL2X) = '1' else SCL2X;

Related

I2Cmaster with MPU6050 in VHDL not working

For my hobby project I try to make a quadcopter which balances itself with the MPU-6050. The flight controller shall be the FPGA Altera cyclone IV, because its fun. I'm coding it in VHDL.
Anyway I'm stuck on the I2C communication with the MPU-6050. As bases I used the I2C master VHDL code from: https://www.digikey.com/eewiki/pages/viewpage.action?pageId=10125324.
I try to read the gyro registers and print them out on 8 leds just to see if I have some communication coming in.
I have tried to run with a 1Hz prescaler all the I2C phases in the state machine and light up some leds just to see if all phases are run through. This is the case. I have assigned the pins 2.5V default, I use 10k pull up resistors. The MPU6050 works perferct on an arduino.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mpu6050_2 is
port( clk_50 : in std_logic;
areset : in std_logic;
i2c_SDA : INOUT STD_LOGIC;
i2c_SCL : INOUT STD_LOGIC;
leds : out std_LOGIC_VECTOR(7 downto 0)
);
end entity mpu6050_2;
architecture struc of mpu6050_2 is
component i2c_master is
GENERIC(
input_clk : INTEGER := 50_000_000;
bus_clk : INTEGER := 400_000);
PORT(
clk : IN STD_LOGIC;
reset_n : IN STD_LOGIC;
ena : IN STD_LOGIC;
addr : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
rw : IN STD_LOGIC;
data_wr : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
busy : OUT STD_LOGIC;
data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
ack_error : BUFFER STD_LOGIC;
sda : INOUT STD_LOGIC;
scl : INOUT STD_LOGIC);
end component ;
type machine is (config1, config2, gyroH, gyroL);
signal state : machine:= config1; --current state
signal SDA_int : std_LOGIC;
signal SCL_int : std_LOGIC;
signal i2c_ena : std_LOGIC;
signal i2c_busy : std_LOGIC;
signal busy_prev : std_LOGIC;
signal i2c_rw : std_LOGIC;
signal i2c_data_wr : STD_LOGIC_VECTOR(7 DOWNTO 0);
signal gyro_data : std_LOGIC_VECTOR(15 downto 0);
signal i2c_data_rd : std_LOGIC_VECTOR (7 downto 0);
signal i2c_addr : STD_LOGIC_VECTOR(6 DOWNTO 0);
begin
process(areset, clk_50)
VARIABLE busy_cnt : INTEGER := 0; --keeps track of i2c busy signals during transaction
begin
if areset = '0' then
busy_cnt := 0;
i2c_ena <= '0';
state <= config1;
elsif rising_edge(clk_50) then
case state is
when config1 =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"6B"; -- hex6B powermanagement
when 1 =>
i2c_rw <= '0'; --write
i2c_data_wr <= "00000000"; -- ON with internal clock
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
busy_cnt := 0;
state <= config2;
end if;
when others => NULL;
end case;
when config2 =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"1B"; -- Gyro config
when 1 =>
i2c_rw <= '0'; --write
i2c_data_wr <= "00000000"; -- 250 degree/sec, no self test
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
busy_cnt := 0;
state <= gyroH;
end if;
when others => NULL;
end case;
when gyroH =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"43"; -- hex43 GYRO_OUT[15:8]
when 1 =>
i2c_rw <= '1'; --read
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
gyro_data(15 downto 8) <= i2c_data_rd;
busy_cnt := 0;
state <= gyroL;
end if;
when others => NULL;
end case;
when gyroL =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"44"; -- hex44 GYRO_OUT[7:0]
when 1 =>
i2c_rw <= '1'; --read
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
gyro_data(7 downto 0) <= i2c_data_rd;
busy_cnt := 0;
state <= gyroH;
end if;
when others => NULL;
end case;
end case;
end if;
end process;
u0: i2c_master
port map(clk => clk_50, reset_n => areset, ena => i2c_ena, addr => i2c_addr, rw => i2c_rw, data_wr => i2c_data_wr, busy => i2c_busy, data_rd => i2c_data_rd
, sda => SDA_int, scl => SCL_int);
leds(7) <= gyro_data(0); --D4
leds(6) <= gyro_data(1); -- D5
leds(5) <= gyro_data(4); -- D6
leds(4) <= gyro_data(7); -- D7
leds(3) <= gyro_data(8); -- D8
leds(2) <= gyro_data(11); -- D9
leds(1) <= gyro_data(13); -- D10
leds(0) <= gyro_data(15); -- D11
i2c_SDA <= SDA_int;
i2c_SCL <= SCL_int;
end struc;
Result:
all the leds dont change status despite if i rotate the MPU6050. So no communication. Can anyone help me what i'm doing wrong?
First: I'm using the same component in one of my designs and do confirm it works.
I think you are just using the wrong i2c address to begin with.
In datasheets, i2c addresses are usually given including the read/write bit (for the MPU-6050, this is 0x68/01101000 and 0x69/01101001). The i2c master component used, however, expects to build the final i2c address by itself by appending (&) the i2c rw bit to the given address (see line 124 in the original sources), thus you must pass the address from the datasheet shifted by one bit.
Try using 0x34/0110100 as i2c address for read and write instead.
I only looked very briefly into the rest of your code (so there might be other culprits as well), but this should be enough to get you going.

using UART in VHDL

I'm trying to use UART communication with a Lattice machox3 and a ft232R. I am trying to use the VHDL file I found on eewiki(Here). For some reason I am not being able to get tx to work when I simulate it. what am I doing wrong? Is there a simple uart implementation I could use? I tried making it myself, scine I just want to transmit, but I wasnt unsuccessful.
here is the waveform Active hdl gives me
this is the top file I am using to get this component to work.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--library machXO3;
--use machXO3.all;
entity UART_TOP is generic (
divisor : integer := 2604 -- Set the Baud Rate Divisor here.
-- Some common values: 300 Baud = 83333, 9600 Baud = 2604, 115200 Baud = 217, 921600 Baud = 27
);
PORT(
reset_n : IN STD_LOGIC; --ascynchronous reset
tx_ena : IN STD_LOGIC; --initiate transmission load on H
tx_busy : OUT STD_LOGIC; --transmission in progress
tx : OUT STD_LOGIC;
CLOCK_UART : in STD_LOGIC;
DIN : IN STD_LOGIC_VECTOR(15 downto 0)
);
end UART_TOP;
architecture Behavior of UART_TOP is
SIGNAL INTERNAL_CLOCK : STD_LOGIC;
SIGNAL MUX_0 : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL MUX_1 : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL MUX_S : STD_LOGIC_VECTOR(1 downto 0);
SIGNAL txEN: STD_LOGIC_VECTOR(0 downto 0);
SIGNAL counter : STD_LOGIC;
SIGNAL DATAsnd : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL LOAD : STD_LOGIC;
---------------------------------------------------
-- Buffer Input --
---------------------------------------------------
COMPONENT NOTM is
PORT(
Input : in STD_LOGIC;
Output : out STD_LOGIC
);
END COMPONENT;
---------------------------------------------------
-- Buffer Input --
---------------------------------------------------
COMPONENT InputBuffer is
generic(n: natural);
PORT(
clk : in STD_LOGIC;
En : in STD_LOGIC; -- 0 is enabled
Input : in STD_LOGIC_VECTOR (n-1 downto 0);
Output : out STD_LOGIC_VECTOR (n-1 downto 0)
);
END COMPONENT;
---------------------------------------------------
-- MUX04_2_1 --
---------------------------------------------------
COMPONENT MUX421 is
generic (
DATAWIDTH : natural := 8
);
port(
A : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
B : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
C : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
D : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
S : in STD_LOGIC_VECTOR(1 downto 0);
O : OUT STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0)
);
END COMPONENT;
---------------------------------------------------
-- Binary Counter --
---------------------------------------------------
COMPONENT binary_counter is
generic(
MIN_COUNT : natural := 0;
MAX_COUNT : natural := 17
);
port(
clk : in std_logic;
reset : in std_logic;
enable : in std_logic; -- 0 is enabled
q : out STD_LOGIC_VECTOR(MAX_COUNT-1 downto 0)
);
END COMPONENT;
---------------------------------------------------
-- UART. Mach0X3 --
---------------------------------------------------
COMPONENT uart_c IS
GENERIC(
clk_freq : INTEGER := 50_000_000; --frequency of system clock in Hertz
baud_rate : INTEGER := 19_200; --data link baud rate in bits/second
os_rate : INTEGER := 16; --oversampling rate to find center of receive bits (in samples per baud period)
d_width : INTEGER := 8; --data bus width
parity : INTEGER := 1; --0 for no parity, 1 for parity
parity_eo : STD_LOGIC := '0'); --'0' for even, '1' for odd parity
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --ascynchronous reset
tx_ena : IN STD_LOGIC; --initiate transmission load on H
tx_data : IN STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data to transmit
rx : IN STD_LOGIC; --receive pin
rx_busy : OUT STD_LOGIC; --data reception in progress
rx_error : OUT STD_LOGIC; --start, parity, or stop bit error detected
rx_data : OUT STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data received
tx_busy : OUT STD_LOGIC; --transmission in progress
tx : OUT STD_LOGIC); --transmit pin
END COMPONENT;
begin
-- UART
DATAOUT: UART_c
PORT MAP ( CLK => CLOCK_UART, --system clock
reset_n =>reset_n, --ascynchronous reset
tx_ena => tx_ena,--txEN(0), --initiate transmission
tx_data => DIN(7 downto 0), --data to transmit
rx =>'0' , --receive pin
tx => tx, --transmit pin
tx_busy => tx_busy
);
--UART LOAD
--LOADER: NOTM
--PORT MAP (INPUT => LOAD, OUTPUT => counter);
-- DATA to MUX
--MUX: MUX421
--PORT MAP (s => MUX_S, A => MUX_0, B => MUX_1, C => X"0D", D => X"0A", O => DO-- DATAsnd
--); -- C => X"0D", D => X"0A" cartidge return and line feed
-- Counter to mux
--cntr: binary_counter
--generic map (MAX_COUNT => 2)
--PORT MAP (
--clk => counter,
--reset => RESET,
--enable => ENABLE,
--q => MUX_S
--);
-- Counter to load
--Load_UART: binary_counter
--generic map (MAX_COUNT => 1)
--PORT MAP (
--clk => CLOCK_UART,
--reset => RESET,
--enable => LOAD,
--q => txEN
--);
--DATA to UART
--UARTBUFFER_0: InputBuffer
--generic map (N => 8)
--PORT MAP ( clk => CLOCK_UART, En =>ENABLE, Input => DIN(15 downto 8), OUTPUT => MUX_0);
--DATA to UART
--UARTBUFFER_1: InputBuffer
--generic map (N => 8)
--PORT MAP ( clk => CLOCK_UART, En =>ENABLE, Input => DIN(7 downto 0), OUTPUT => MUX_1);
end Behavior;
this is the UART itself
--------------------------------------------------------------------------------
--
-- FileName: uart_c.vhd
-- Dependencies: none
-- Design Software: Quartus II 64-bit Version 13.1.0 Build 162 SJ Web Edition
--
-- HDL CODE IS PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
-- WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
-- BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
-- DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
-- PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
-- BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
-- ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
--
-- Version History
-- Version 1.0 5/26/2017 Scott Larson
-- Initial Public Release
--
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY uart_c IS
GENERIC(
clk_freq : INTEGER := 50_000_000; --frequency of system clock in Hertz
baud_rate : INTEGER := 19_200; --data link baud rate in bits/second
os_rate : INTEGER := 16; --oversampling rate to find center of receive bits (in samples per baud period)
d_width : INTEGER := 8; --data bus width
parity : INTEGER := 1; --0 for no parity, 1 for parity
parity_eo : STD_LOGIC := '0'); --'0' for even, '1' for odd parity
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --ascynchronous reset
tx_ena : IN STD_LOGIC; --initiate transmission
tx_data : IN STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data to transmit
rx : IN STD_LOGIC; --receive pin
rx_busy : OUT STD_LOGIC; --data reception in progress
rx_error : OUT STD_LOGIC; --start, parity, or stop bit error detected
rx_data : OUT STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data received
tx_busy : OUT STD_LOGIC; --transmission in progress
tx : OUT STD_LOGIC); --transmit pin
END uart_c;
ARCHITECTURE logic OF uart_c IS
TYPE tx_machine IS(idle, transmit); --tranmit state machine data type
TYPE rx_machine IS(idle, receive); --receive state machine data type
SIGNAL tx_state : tx_machine; --transmit state machine
SIGNAL rx_state : rx_machine; --receive state machine
SIGNAL baud_pulse : STD_LOGIC := '0'; --periodic pulse that occurs at the baud rate
SIGNAL os_pulse : STD_LOGIC := '0'; --periodic pulse that occurs at the oversampling rate
SIGNAL parity_error : STD_LOGIC; --receive parity error flag
SIGNAL rx_parity : STD_LOGIC_VECTOR(d_width DOWNTO 0); --calculation of receive parity
SIGNAL tx_parity : STD_LOGIC_VECTOR(d_width DOWNTO 0); --calculation of transmit parity
SIGNAL rx_buffer : STD_LOGIC_VECTOR(parity+d_width DOWNTO 0) := (OTHERS => '0'); --values received
SIGNAL tx_buffer : STD_LOGIC_VECTOR(parity+d_width+1 DOWNTO 0) := (OTHERS => '1'); --values to be transmitted
BEGIN
--generate clock enable pulses at the baud rate and the oversampling rate
PROCESS(reset_n, clk)
VARIABLE count_baud : INTEGER RANGE 0 TO clk_freq/baud_rate-1 := 0; --counter to determine baud rate period
VARIABLE count_os : INTEGER RANGE 0 TO clk_freq/baud_rate/os_rate-1 := 0; --counter to determine oversampling period
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
baud_pulse <= '0'; --reset baud rate pulse
os_pulse <= '0'; --reset oversampling rate pulse
count_baud := 0; --reset baud period counter
count_os := 0; --reset oversampling period counter
ELSIF(clk'EVENT AND clk = '1') THEN
--create baud enable pulse
IF(count_baud < clk_freq/baud_rate-1) THEN --baud period not reached
count_baud := count_baud + 1; --increment baud period counter
baud_pulse <= '0'; --deassert baud rate pulse
ELSE --baud period reached
count_baud := 0; --reset baud period counter
baud_pulse <= '1'; --assert baud rate pulse
count_os := 0; --reset oversampling period counter to avoid cumulative error
END IF;
--create oversampling enable pulse
IF(count_os < clk_freq/baud_rate/os_rate-1) THEN --oversampling period not reached
count_os := count_os + 1; --increment oversampling period counter
os_pulse <= '0'; --deassert oversampling rate pulse
ELSE --oversampling period reached
count_os := 0; --reset oversampling period counter
os_pulse <= '1'; --assert oversampling pulse
END IF;
END IF;
END PROCESS;
--receive state machine
PROCESS(reset_n, clk)
VARIABLE rx_count : INTEGER RANGE 0 TO parity+d_width+2 := 0; --count the bits received
VARIABLE os_count : INTEGER RANGE 0 TO os_rate-1 := 0; --count the oversampling rate pulses
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
os_count := 0; --clear oversampling pulse counter
rx_count := 0; --clear receive bit counter
rx_busy <= '0'; --clear receive busy signal
rx_error <= '0'; --clear receive errors
rx_data <= (OTHERS => '0'); --clear received data output
rx_state <= idle; --put in idle state
ELSIF(clk'EVENT AND clk = '1' AND os_pulse = '1') THEN --enable clock at oversampling rate
CASE rx_state IS
WHEN idle => --idle state
rx_busy <= '0'; --clear receive busy flag
IF(rx = '0') THEN --start bit might be present
IF(os_count < os_rate/2) THEN --oversampling pulse counter is not at start bit center
os_count := os_count + 1; --increment oversampling pulse counter
rx_state <= idle; --remain in idle state
ELSE --oversampling pulse counter is at bit center
os_count := 0; --clear oversampling pulse counter
rx_count := 0; --clear the bits received counter
rx_busy <= '1'; --assert busy flag
rx_state <= receive; --advance to receive state
END IF;
ELSE --start bit not present
os_count := 0; --clear oversampling pulse counter
rx_state <= idle; --remain in idle state
END IF;
WHEN receive => --receive state
IF(os_count < os_rate-1) THEN --not center of bit
os_count := os_count + 1; --increment oversampling pulse counter
rx_state <= receive; --remain in receive state
ELSIF(rx_count < parity+d_width) THEN --center of bit and not all bits received
os_count := 0; --reset oversampling pulse counter
rx_count := rx_count + 1; --increment number of bits received counter
rx_buffer <= rx & rx_buffer(parity+d_width DOWNTO 1); --shift new received bit into receive buffer
rx_state <= receive; --remain in receive state
ELSE --center of stop bit
rx_data <= rx_buffer(d_width DOWNTO 1); --output data received to user logic
rx_error <= rx_buffer(0) OR parity_error OR NOT rx; --output start, parity, and stop bit error flag
rx_busy <= '0'; --deassert received busy flag
rx_state <= idle; --return to idle state
END IF;
END CASE;
END IF;
END PROCESS;
--receive parity calculation logic
rx_parity(0) <= parity_eo;
rx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
rx_parity(i+1) <= rx_parity(i) XOR rx_buffer(i+1);
END GENERATE;
WITH parity SELECT --compare calculated parity bit with received parity bit to determine error
parity_error <= rx_parity(d_width) XOR rx_buffer(parity+d_width) WHEN 1, --using parity
'0' WHEN OTHERS; --not using parity
--transmit state machine
PROCESS(reset_n, clk)
VARIABLE tx_count : INTEGER RANGE 0 TO parity+d_width+3 := 0; --count bits transmitted
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
tx_count := 0; --clear transmit bit counter
tx <= '1'; --set tx pin to idle value of high
tx_busy <= '1'; --set transmit busy signal to indicate unavailable
tx_state <= idle; --set tx state machine to ready state
ELSIF(clk'EVENT AND clk = '1') THEN
CASE tx_state IS
WHEN idle => --idle state
IF(tx_ena = '1') THEN --new transaction latched in
tx_buffer(d_width+1 DOWNTO 0) <= tx_data & '0' & '1'; --latch in data for transmission and start/stop bits
IF(parity = 1) THEN --if parity is used
tx_buffer(parity+d_width+1) <= tx_parity(d_width); --latch in parity bit from parity logic
END IF;
tx_busy <= '1'; --assert transmit busy flag
tx_count := 0; --clear transmit bit count
tx_state <= transmit; --proceed to transmit state
ELSE --no new transaction initiated
tx_busy <= '0'; --clear transmit busy flag
tx_state <= idle; --remain in idle state
END IF;
WHEN transmit => --transmit state
IF(baud_pulse = '1') THEN --beginning of bit
tx_count := tx_count + 1; --increment transmit bit counter
tx_buffer <= '1' & tx_buffer(parity+d_width+1 DOWNTO 1); --shift transmit buffer to output next bit
END IF;
IF(tx_count < parity+d_width+3) THEN --not all bits transmitted
tx_state <= transmit; --remain in transmit state
ELSE --all bits transmitted
tx_state <= idle; --return to idle state
END IF;
END CASE;
tx <= tx_buffer(0); --output last bit in transmit transaction buffer
END IF;
END PROCESS;
--transmit parity calculation logic
tx_parity(0) <= parity_eo;
tx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
tx_parity(i+1) <= tx_parity(i) XOR tx_data(i);
END GENERATE;
END logic;
and this is the test bench
-- VHDL Test Bench Created from source file UART_TOP.vhd -- Sun Aug 19 12:41:55 2018
--
-- Notes:
-- 1) This testbench template has been automatically generated using types
-- std_logic and std_logic_vector for the ports of the unit under test.
-- Lattice recommends that these types always be used for the top-level
-- I/O of a design in order to guarantee that the testbench will bind
-- correctly to the timing (post-route) simulation model.
-- 2) To use this template as your testbench, change the filename to any
-- name of your choice with the extension .vhd, and use the "source->import"
-- menu in the ispLEVER Project Navigator to import the testbench.
-- Then edit the user defined section below, adding code to generate the
-- stimulus for your design.
-- 3) VHDL simulations will produce errors if there are Lattice FPGA library
-- elements in your design that require the instantiation of GSR, PUR, and
-- TSALL and they are not present in the testbench. For more information see
-- the How To section of online help.
--
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY testbench IS
END testbench;
ARCHITECTURE behavior OF testbench IS
COMPONENT UART_TOP
PORT(
reset_n : IN std_logic;
tx_ena : IN std_logic;
CLOCK_UART : IN std_logic;
DIN : IN std_logic_vector(15 downto 0);
tx_busy : OUT std_logic;
tx : OUT std_logic
);
END COMPONENT;
SIGNAL reset_n : std_logic;
SIGNAL tx_ena : std_logic;
SIGNAL tx_busy : std_logic;
SIGNAL tx : std_logic;
SIGNAL CLOCK_UART : std_logic;
SIGNAL DIN : std_logic_vector(15 downto 0);
constant half_period : time := 10 ns;
BEGIN
-- Please check and add your generic clause manually
uut: UART_TOP PORT MAP(
reset_n => reset_n,
tx_ena => tx_ena,
tx_busy => tx_busy,
tx => tx,
CLOCK_UART => CLOCK_UART,
DIN => DIN
);
-- *** Test Bench - User Defined Section ***
tb : PROCESS
BEGIN
reset_n <= '1';
tx_ena <= '0';
DIN <= B"0101010101010101";
CLOCK_UART <= '1';
wait for half_period ;
CLOCK_UART <= '0';
wait for half_period ;
CLOCK_UART <= '1';
wait for half_period ;
CLOCK_UART <= '0';
wait for half_period ;
tx_ena <= '1';
loop
CLOCK_UART <= '1';
wait for half_period ;
tx_ena <= '0';
CLOCK_UART <= '0';
wait for half_period ;
end loop;
END PROCESS;
-- *** End Test Bench - User Defined Section ***
END;

Error (10028): Can't resolve multiple constant drivers for net "sda" at I2C_com.vhd(185)

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';

VHDL simulation failed with unexpected result

I learned VHDL 5 years back, and never used after that as I was working on different domain. Now I'm working in a project that required some work in VHDL. I have to implement SPI to program a ADF4158 device. I opened a book for syntax and tried to program. I need to develop the below module, I coded as per my understanding and also a test bench but it doesnot work in the simulation like I need. Below is the module I want to develop and the over all block diagram.
Block diagram of process and vhdl module (clickable):
The following is the SPI timing diagram as follows (clickable):
The below is the VHDL code I wrote to acheive the above SPI communication:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.all;
entity sender is
Generic( DATA_WIDTH : INTEGER := 32); --32 bit registers to pogram (total 8 registers to program)
Port ( sys_clk : in STD_LOGIC; --clock from microblaze (32 MHz)
enable : in STD_LOGIC; --from microblaze to trigger start
reset : in STD_LOGIC; --reset spi clk generation
start_data_read : out STD_LOGIC; --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to buffer
start_data_write : out STD_LOGIC; --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to mosi port
data_in : in STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --program data (32bit data in 8 phases depending on register_select)
process_done : out STD_LOGIC; --flag bit to microblaze when complete process is complete
register_select : in STD_LOGIC_VECTOR(2 downto 0); --select code to identify which register to grogram, theorder can be manupulated from microblaze
sclk : buffer STD_LOGIC; --spi clock for ADC (3.2 MHz)
ss : out STD_LOGIC := '1'; --select line for ADF (slave)
mosi : out STD_LOGIC); --program data for ADF
end sender;
architecture Behavioral of sender is
type machine is(store, sending); --states of state-machine
signal state : machine := store;
signal clk_divide: STD_LOGIC_VECTOR(5 downto 0); --clock cycle ratio between system clock from microblaze and spi clock for ADF
signal tx_buffer_0 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 0)
signal tx_buffer_1 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 1)
signal tx_buffer_2 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 2)
signal tx_buffer_3 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 3)
signal tx_buffer_4 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 4)
signal tx_buffer_5 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 5)
signal tx_buffer_6 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 6)
signal tx_buffer_7 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 7)
begin
ClK_GEN: process(sys_clk)
begin --spi sclk 20:1 cycles of sys_clk(system runs at 32 MHz and SPI CLK required is 1.6 MHz)
if rising_edge(sys_clk) then
if reset = '1' then
clk_divide <= (others => '0');
mosi <= 'Z'; --send high impedence
else
if clk_divide < "001010" then --10
sclk <= '0';
clk_divide <= clk_divide + 1;
else
if clk_divide < "010100" then --20
sclk <= '1';
else
clk_divide <= (others => '0');
end if;
end if;
end if;
end if;
end process ClK_GEN;
SEND: process(sclk,enable,register_select)
begin
if rising_edge(sclk) then
if enable = '1' then
case state is
when store =>
start_data_read <= '1'; --ask microblaze to send register_selectcodes and data
case register_select is
when "000" =>
tx_buffer_7 <= data_in; --copy data to buffer
when "001" =>
tx_buffer_6 <= data_in;
when "010" =>
tx_buffer_5 <= data_in;
when "011" =>
tx_buffer_4 <= data_in;
when "100" =>
tx_buffer_3 <= data_in;
when "101" =>
tx_buffer_2 <= data_in;
when "110" =>
tx_buffer_1 <= data_in;
when "111" =>
tx_buffer_0 <= data_in;
when others =>
tx_buffer_1 <= (OTHERS => '0');
end case;
state <= sending; --change state to next
when sending =>
start_data_write <= '1'; --ask microblaze to send register_select codes to pgrogram a register
case register_select is
when "000" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_7 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "001" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_6 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "010" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
ss <= '1';
when "011" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_4 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "100" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_3 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "101" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_2 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "110" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_1 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "111" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_0 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when others =>
mosi <= '0';
end case;
end case;
end if;
end if;
end process SEND;
end Behavioral;
I also wrote a test bench code to send the above module, belowis the code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY test_sender IS
END test_sender;
ARCHITECTURE behavior OF test_sender IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT sender
PORT(
sys_clk : IN std_logic;
enable : IN std_logic;
reset : IN std_logic;
start_data_read : OUT std_logic;
start_data_write : OUT std_logic;
data_in : IN std_logic_vector(31 downto 0);
process_done : OUT std_logic;
register_select : IN std_logic_vector(2 downto 0);
sclk : buffer std_logic;
ss : OUT std_logic;
mosi : OUT std_logic
);
END COMPONENT;
--Inputs
signal sys_clk : std_logic := '0';
signal enable : std_logic := '0';
signal reset : std_logic := '0';
signal data_in : std_logic_vector(31 downto 0) := (others => '0');
signal register_select : std_logic_vector(2 downto 0) := (others => '0');
--Outputs
signal start_data_read : std_logic;
signal start_data_write : std_logic;
signal process_done : std_logic;
signal sclk : std_logic;
signal ss : std_logic;
signal mosi : std_logic;
-- Clock period definitions
constant clk_sys_period : time := 31.25 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: sender PORT MAP (
sys_clk => sys_clk,
enable => enable,
reset => reset,
start_data_read => start_data_read,
start_data_write => start_data_write,
data_in => data_in,
process_done => process_done,
register_select => register_select,
sclk => sclk,
ss => ss,
mosi => mosi
);
-- Clock process definitions
clk_sys_process :process
begin
sys_clk <= '0';
wait for clk_sys_period/2;
sys_clk <= '1';
wait for clk_sys_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 1ns;
enable <= '1';
if start_data_read = '1' then
wait for 1ns;
register_select <= "000";
wait for 1 ns;
data_in <= "01001111001101010101010111100001";
wait for 5 ns;
register_select <= "001";
wait for 1 ns;
data_in <= "11001111001101010111011111100101";
wait for 5 ns;
register_select <= "010";
wait for 1 ns;
data_in <= "00000011001101010101011101100101";
wait for 5 ns;
register_select <= "011";
wait for 1 ns;
data_in <= "00011111001101010101010011100101";
wait for 5 ns;
register_select <= "100";
wait for 1 ns;
data_in <= "10001111001101010101011111100001";
wait for 5 ns;
register_select <= "101";
wait for 1 ns;
data_in <= "11001111001101010101011110000101";
wait for 5 ns;
register_select <= "110";
wait for 1 ns;
data_in <= "00101000001101010101011111100101";
wait for 5 ns;
register_select <= "111";
wait for 1 ns;
data_in <= "11111111001101010101011110100101";
wait for 5 ns;
end if;
if start_data_write = '1' then
wait for 1ns;
register_select <= "000";
wait for 5 ns;
register_select <= "001";
wait for 5 ns;
register_select <= "010";
wait for 5 ns;
register_select <= "011";
wait for 5 ns;
register_select <= "100";
wait for 5 ns;
register_select <= "101";
wait for 5 ns;
register_select <= "110";
wait for 5 ns;
register_select <= "111";
wait for 5 ns;
end if;
-- insert stimulus here
wait;
end process;
END;
The simulation is not working properly, and so the code is wrong, but I can't find out where is the mistake, it would be great if some one can help me and make me understand my mistake.
Do you mean to do a data_read and data_write in this simulation? In RTL we can do a check like the following because we look many times (probably on an edge of clock):
if start_data_read = '1' then
However your testbench process does not loop. So instead of doing an "IF" the way we do in RTL code, you need to do something to cause your test to stop until that condition exists. So your test would be the following:
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 1ns;
enable <= '1';
if start_data_read /= '1' then
wait until start_data_read = '1' ;
end if ;
-- Do a read sequence
. . .
if start_data_write /= '1' then
wait until start_data_write = '1' ;
end if ;
-- Do a write sequence
Within your read and write sequence, you have "wait for 5 ns". Can your device really accept operations this quickly? This is faster than a clock cycle. Are the operations in any way aligned with clock? You can wait for clock cycles by doing either of the following:
wait until rising_edge(Clk) ;
wait until Clk = '1' ; -- assumes Clk is only '0' or '1' (safe for clocks)
Once you get the basics working, you might further consider encapsulating a single write or read operation into a subprogram.

VHDL state transitions based on if statements - works on board but doesn't work in simulator

I hate to ask yet another question on here but apparently I'm really useless with simulators :(.
Basically, I have a traffic light controller that is made up of a bunch of different states and a few timers running for different lengths of time. When the system enters a state, it activates a timer and there is an if statement that watches the timer output and points the system to the next state when the timer output value is 1.
This all works fine on the board, but when I simulate it the count ticks to '1' but the next state isn't selected. This can be seen, here:
I've tried to boil the code down into the essentials below, but if you need more context (and are feeling far more generous than I deserve) then the full code is here.
Initialisation:
entity trafficlightcontroller is
port
(
clk : in std_logic;
reset : in std_logic;
ambulance : in std_logic;
smr : in std_logic;
sml : in std_logic;
ssr : in std_logic;
rlmr : out std_logic;
almr : out std_logic;
glmr : out std_logic;
rlsr : out std_logic;
alsr : out std_logic;
glsr : out std_logic
);
end entity;
architecture rtl of trafficlightcontroller is
-- Build an enumerated type for the state machine
-- r=red;a=amber;g=green;c=car waiting;m=main road;s=side road
type state_type is (rmgs, rmas, rmrs, amrs, gmrs, gmrcs, ramrs, rmacs, rmrcs, ramrcs, rmras, rmrs2);
-- Signals to hold the states
signal present_state, next_state : state_type;
signal divclk, reset2, reset2b, reset3, reset3b, reset10, reset20, reset20b, count2, count2b, count3, count3b, count10, count20, count20b: std_logic;
component timer is
generic (
trigger_cnt: natural := 20
);
port (
clk: in std_logic;
reset: in std_logic;
count: buffer std_logic
);
end component timer;
component clockdivider
port(clkin : in std_logic;
dividedclk : out std_logic
);
end component clockdivider;
begin
timer2 : timer generic map (trigger_cnt => 2) port map(divclk,reset2,count2);
timer2b : timer generic map (trigger_cnt => 2) port map(divclk,reset2b,count2b);
timer3 : timer generic map (trigger_cnt => 3) port map(divclk,reset3,count3);
timer3b : timer generic map (trigger_cnt => 3) port map(divclk,reset3b,count3b);
timer10 : timer generic map (trigger_cnt => 10) port map(divclk,reset10,count10);
timer20 : timer generic map (trigger_cnt => 20) port map(divclk,reset20,count20);
timer20b : timer generic map (trigger_cnt => 20) port map(divclk,reset20b,count20b);
divider : clockdivider port map(clk, divclk);
The beginning of the states (including the state shown in the simulation):
case present_state is
--Red light main; green side road
when rmgs=>
reset2 <= '0';
reset2b <= '0';
reset3 <= '0';
reset3b <= '0';
reset20 <= '0';
reset20b <= '0';
rlmr <= '1';
almr <= '0';
glmr <= '0';
rlsr <= '0';
alsr <= '0';
glsr <= '1';
reset10 <= '1';
--if count is complete then move to next state
if ( count10='1' ) THEN
next_state <= rmas;
--otherwise, return to current state
else
next_state <= rmgs;
end if;
Clock process:
--Every clock tick, the next state is selected as the present state.
state_clocked: process(clk)
begin
if ( rising_edge( clk ) ) THEN
present_state <= next_state;
end if;
end process state_clocked;
The line I entered into the simulator to initialise the clock:
force clk 0 0ns, 1 10 ns -repeat 20ns
Your next_state process is missing lots of signals in the sensitivity list. This will probably fix it. VHDL-2008 allows you to use the keyword "all" instead of signal names. If your synthesis tool supports this, it might be worth using.
The rest are suggestions:
With a two process statemachine, reset logic is most often captured in the state_clocked process. And hence, look more like this:
state_clocked: process(clk)
begin
if ( rising_edge( clk ) ) THEN
if Reset = '0' then
present_state <= rmrs;
else
present_state <= next_state;
end if ;
end if;
end process state_clocked;
You can shorten your code significantly if you use a default assignment to assign the "off" value to all signal outputs of the next_state process:
next_state_proc : process (present_state, ssr, ambulance, Count10, Count3, ... )
begin
-- default assignments
reset2 <= '0';
reset2b <= '0';
reset3 <= '0';
reset3b <='0';
reset10 <= '0';
reset20 <= '0';
reset20b <= '0';
rlmr <= '1';
almr <= '0';
glmr <= '0';
rlsr <= '1';
alsr <= '0';
glsr <= '0';
next_state <= present_state ; -- optional
-- Statemachine code starts here
-- Only do assignments that are different from the default.
if ssr = '0' then
-- Do you change the values from the defaults here?
-- with the defaults, it is not necessary to do any assignments here, however,
-- without the defaults these outputs would have latches on them.
case present_state is
when gmrs => next_state <= gmrcs;
when rmas => next_state <= rmacs;
...
end case ;
elsif ambulance = '0' then
-- Do you change the values from the defaults here?
-- with the defaults, it is not necessary to do any assignments here, however,
-- without the defaults these outputs would have latches on them.
case present_state is
when gmrs | ramrs | ramrcs => next_state <= amrs;
-- when rmas => ???
when rmgs | rmras => next_state <= rmas;
...
end case ;
else
-- main statemachine
case present_state is
when rmgs=>
-- Only drive outputs that are different from the defaults here.
rlsr <= '0';
glsr <= '1';
reset10 <= '1';
--if count is complete then move to next state
if ( count10='1' ) THEN
next_state <= rmas;
--otherwise, return to current state
else
next_state <= rmgs;
end if;
when rmas=>
. . .
end case ;
The reset for the present_state register isn't strictly needed for simulation, but should be there for synthesis.
state_clocked:
process(reset,clk)
begin
if reset = '0' then
present_state <= rmrs;
elsif rising_edge( clk ) THEN
present_state <= next_state;
end if;
end process;
(Jim beat me to it).
process (present_state, reset, ssr, ambulance, count2, count2b,
count3, count3b, count10, count20, count20b)
Adding the process sensitivity elements (and using reset):
(I added a bit more to it. A lot of your design appears to be working to a good extent.)
And think about using a test bench, it would allow automated testing by generating inputs on ambulance, smr, sml and ssr.
library ieee;
use ieee.std_logic_1164.all;
entity tb_tfc is
end entity;
architecture foo of tb_tfc is
signal clk: std_logic := '0';
signal reset: std_logic;
signal ambulance: std_logic := '1';
signal smr: std_logic := '1';
signal sml: std_logic := '1';
signal ssr: std_logic := '1';
signal rlmr: std_logic;
signal almr: std_logic;
signal glmr: std_logic;
signal rlsr: std_logic;
signal alsr: std_logic;
signal glsr: std_logic;
begin
DUT:
entity work.trafficlightcontroller
port map (
clk,
reset,
ambulance,
smr,
sml,
ssr,
rlmr, -- out
almr, -- out
glmr, -- out
rlsr, -- out
alsr, -- out
glsr -- out
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 1280 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
reset <= '0'; --
wait for 20 ns;
reset <= '1';
wait for 1020 ns;
ssr <= '0';
wait;
end process;
end architecture;

Resources