PWM controlled LED using VHDL - vhdl

I've written the following VHDL code and test-bench to control the brightness of LEDs. Then tried with Altera ModelSim to simulate the code. However, I'm facing some technical difficulties. It would be really nice if someone will compile the code and share me the simulated result with me. Thanks in advance.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity main_testbench is
end main_testbench;
architecture behavior of main_testbench is
component led_controller is
Port ( clk, reset: in std_logic; -- system clock is assumed 10KHz
in_word: in std_logic_vector(7 downto 0); -- LS 4 bits - frequency & MS 4 bits - duty-cycle
LEDs: out std_logic_vector(3 downto 0));
end component;
signal clk, reset: std_logic := '0';
signal in_word: std_logic_vector(7 downto 0) := "00010001"; -- 0.2 Hz, 10% duty cycle
signal LEDs: std_logic_vector(3 downto 0) := "0000";
type in_word_commands is array (0 to 15) of std_logic_vector(7 downto 0);
signal in_words: in_word_commands := ("00010001", "00010010", "00010100", "00011000", -- 10% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
"00100001", "00100010", "00100100", "00101000", -- 30% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
"01000001", "01000010", "01000100", "01001000", -- 60% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
"10000001", "10000010", "10000100", "10001000"); -- 85% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
signal command_num : integer := 0;
begin
dut: led_controller port map (clk, reset, in_word, LEDs);
clk <= not clk after 50 us; -- 0.1ms/2 = 50us
command_num <= command_num + 1 after 5000 ms; -- 5000ms = 5s
in_word <= in_words(command_num);
end behavior;
controller:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
entity led_controller is
Port ( clk, reset: in std_logic;
in_word: in std_logic_vector(7 downto 0);
LEDs: out std_logic_vector(3 downto 0));
end led_controller;
architecture behavior of led_controller is
--------------------- signals ---------------------
type freq is array (0 to 3) of integer range 0 to 50000;
signal frq: freq := (25000, 10000, 5000, 2500);
signal led_freq_count: integer range 0 to 50000 := frq(0);
type d is array (0 to 3) of integer range 0 to 100;
signal duty: d := (10, 30, 60, 85);
signal duty_cycle: integer range 0 to 100 := duty(0);
signal LED_switch, new_command: std_logic := '0';
begin
--------- clock process / sync reset configuration ---------------
process (clk)
variable duty_counter: integer range 0 to 100 := 100;
variable freq_counter: integer range 0 to 50000 := led_freq_count;
begin
if rising_edge(clk) then
------- if reset was high or new in_word were arrived --------
if reset = '1' or new_command = '1' then
LEDs <= "0000";
duty_counter := 100;
freq_counter := led_freq_count;
new_command <= '0';
else
------- blinking process --------
if freq_counter = 0 then
freq_counter := led_freq_count;
LED_switch <= not LED_switch;
end if;
freq_counter := freq_counter - 1;
if duty_counter = 0 then
duty_counter := 100;
end if;
duty_counter := duty_counter - 1;
------ output assignment -------
if LED_switch = '1' and duty_counter < duty_cycle then
LEDs <= "1111";
else
LEDs <= "0000";
end if;
end if;
end if;
end process;
--------- input process---------------
process (in_word)
begin
case in_word(3 downto 0) is
when "0001" => led_freq_count <= frq(0);
when "0010" => led_freq_count <= frq(1);
when "0100" => led_freq_count <= frq(2);
when "1000" => led_freq_count <= frq(3);
when others => led_freq_count <= frq(0);
end case;
case in_word(7 downto 4) is
when "0001" => duty_cycle <= duty(0);
when "0010" => duty_cycle <= duty(1);
when "0100" => duty_cycle <= duty(2);
when "1000" => duty_cycle <= duty(3);
when others => duty_cycle <= duty(0);
end case;
new_command <= '1';
end process;
end behavior;

if freq_counter = 0 then
freq_counter := led_freq_count;
LED_switch <= not LED_switch;
else
freq_counter := freq_counter - 1;
end if;
if duty_counter = 0 then
duty_counter := 100;
else
duty_counter := duty_counter - 1;
end if;

Related

Different Clock Domain VHDL

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.

How can i implement byte addressable memory in VHDL?

I want to make 4kb byte addressable memory. sorry I'm new in VHDL
I wanted my code works first write 4byte number in adress 8 (rdwr=1, addr=1000, size=10(2^2byte), idata=10001100)
then wait 8 cycles to implement writing time(ivalid=0)
Second read 4byte number from adress 8(rdwr=0, addr=1000, size=10(2^2byte))
In my purpose, the "ready" signal should be '0' while waiting for writing time
but the signal is always 'U' in simulation. I tried to figure out what is the problem but i couldn't
Can anyone help me where did a make mistake?
Here is my code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Memory is
port (
clk: in std_logic;
ready: out std_logic; -- 0: busy, 1: ready
ivalid: in std_logic; -- 0: invalid, 1: valid
rdwr: in std_logic; -- 0: read, 1: write
addr: in unsigned(11 downto 0); -- byte address
size: in std_logic_vector(1 downto 0); -- 00/01/10/11: 1/2/4/8 bytes
idata: in std_logic_vector(63 downto 0);
ovalid: out std_logic; -- 0: invalid, 1: valid
odata: out std_logic_vector(63 downto 0)
);
end entity;
architecture Behavioral of Memory is
type ram_type is array (0 to (2**12)-1) of std_logic_vector(7 downto 0);
signal RAM : ram_type;
signal state : std_logic := '1'; --if ready '1'
signal queue : std_logic := '0'; --if something to do '1'
signal timer : integer := 0; --timer
signal curr_addr : unsigned(11 downto 0);
signal curr_size : std_logic_vector(1 downto 0);
signal curr_data : std_logic_vector(63 downto 0);
signal write : std_logic := '0';
signal read : std_logic := '0';
begin
process(clk)
variable vstate : std_logic := state;
variable vqueue : std_logic := queue; --if something to do '1'
variable vtimer : integer := timer; --timer
variable vcurr_addr : unsigned(11 downto 0) := curr_addr;
variable vcurr_size : std_logic_vector(1 downto 0) := curr_size;
variable vcurr_data : std_logic_vector(63 downto 0) := curr_data;
variable vwrite : std_logic := write;
variable vread : std_logic := read;
begin
--get input
if(rising_edge(clk)) then
ovalid <= '0';
if(vstate='1') then
if(ivalid='1') then
vcurr_addr := addr;
vcurr_size := size;
if(rdwr='0') then
--read
vread := '1';
else
vwrite := '1';
vcurr_data := idata;
end if;
vqueue := '1';
vtimer := 2**(to_integer(unsigned(vcurr_size)))-1;
end if;
end if;
--process
if(vqueue = '1') then
if(vtimer > 0) then
--wait for next cycle
ready <= '0';
vstate := '0';
vtimer := vtimer - 1;
else
--ok to go
if(vwrite = '1') then
--write
for x in 0 to 2**(to_integer(unsigned(vcurr_size)))-1 loop
for y in 0 to 7 loop
RAM(to_integer(vcurr_addr) + x)(y) <= vcurr_data(y + 8*x);
end loop;
end loop;
elsif(vread = '1') then
--read
for x in 0 to 7 loop
for y in 0 to 7 loop
if(x < 2**(to_integer(unsigned(vcurr_size)))) then
odata(y + 8*x) <= RAM(to_integer(vcurr_addr) + x)(y);
else
odata(y + 8*x) <= '0';
end if;
end loop;
end loop;
ovalid <= '1';
end if;
vqueue := '0';
vstate := '1';
ready <= '1';
end if;
end if;
--save variable to signals
state <= vstate;
queue <= vqueue;
timer <= vtimer;
curr_addr <=vcurr_addr;
curr_size <=vcurr_size;
curr_data<= vcurr_data;
write <= vwrite;
read <= vread;
end if;
end process;
end architecture;

VHDL Multiple Processes error

I am writing a VHDL homework, which produces a strange behavior, which I do not understand.
The concept is the following. There should be an LFSR which is used to generate random numbers. The LFSR could be driven by I_CLK or by I_NEXT input. If the LFSR is driven by the I_CLK, it should automatically generate random numbers on its output, but if its driven by the I_NEXT input, it should generate number by changing the I_NEXT value manually from 0 to 1. I have a problem with the following code. If I comment out one of the processes, the LFSR works fine but if all the processes are enabled, it just do not work at all. Could you help me figure out the problem? I think it should be a design error, but I do not know what is wrong with my design.
entity LFSR_v2 is
Generic (
width : positive := 31;
tap_1 : positive := 30;
tap_2 : positive := 27
);
Port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
i_load : in std_logic;
i_direction : in std_logic;
o_number : out std_logic_vector (width -1 downto 0);
i_seed : in std_logic_vector (width -1 downto 0)
);
end LFSR_v2;
architecture Behavioral of LFSR_v2 is
signal internal_number : std_logic_vector(width -1 downto 0);
begin
-------------------------------------------------------------------------------------------
-- FREE RUNNING PROCESS
--
-- In Free Running mode the LFSR switches its state on every rising edge of the i_clk input.
-------------------------------------------------------------------------------------------
next_number_free_run : process(i_clk, i_reset)
--variable fileline : line;
--variable gen_num : integer;
begin
if rising_edge(i_clk) then
--------------------------------------
-- NORMAL MODE
-- enable = 1
-- reset = 0
--------------------------------------
if (i_enable = '1' and i_free_run = '1') then
-- Internal number to the output
o_number <= internal_number;
-----------------------------
-- RESET
-----------------------------
if(i_reset = '1') then
if(i_direction = '1') then
internal_number <= (OTHERS => '1');
else
internal_number <= (OTHERS => '0');
end if;
else
------------------------------
-- LOAD SEED
-- load = 1
------------------------------
if(i_load = '1') then
internal_number <= i_seed;
else
--------------------------------------
-- GENERATE NEXT NUMBER - FREE RUNNING
-- load = 0
-- free_run = 1
-------------------------------------
if(i_direction = '1') then
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
else
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
end if;
----------------------------------------
-- FILE LOGGING
----------------------------------------
--gen_num := to_integer(internal_number);
--write(fileline, gen_num);
--writeline(MyFile, fileline);
end if;
end if;
end if;
end if;
end process next_number_free_run;
---------------------------------------------------------------------------------
-- MANUAL RUNNING PROCESS
--
-- In this mode the LFSR does not use the input clock to generate the next number.
-- Number can be generated by creating a 0 -> 1 signal change on the i_next input.
---------------------------------------------------------------------------------
next_number_man_run : process(i_next, i_reset)
--variable fileline : line;
--variable gen_num : integer;
begin
if rising_edge(i_next) then
--------------------------------------
-- NORMAL MODE
-- enable = 1
-- reset = 0
--------------------------------------
if (i_enable = '1' and i_free_run = '0') then
-- Internal number to the output
o_number <= internal_number;
-----------------------------
-- RESET
-----------------------------
if(i_reset = '1') then
if(i_direction = '1') then
internal_number <= (OTHERS => '1');
else
internal_number <= (OTHERS => '0');
end if;
else
------------------------------
-- LOAD SEED
-- load = 1
------------------------------
if(i_load = '1') then
internal_number <= i_seed;
else
--------------------------------------
-- GENERATE NEXT NUMBER - FREE RUNNING
-- load = 0
-- free_run = 1
-------------------------------------
if(i_direction = '1') then
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
else
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
end if;
----------------------------------------
-- FILE LOGGING
----------------------------------------
--gen_num := to_integer(internal_number);
--write(fileline, gen_num);
--writeline(MyFile, fileline);
end if;
end if;
end if;
end if;
end process next_number_man_run;
end Behavioral;
Test bench for the code:
----------------------------
-- TEST SEED INIT
----------------------------
-- ENABLE OFF -> SEED SHOULD NOT BE INITIALIZED
s_enable <= '0';
s_reset <= '0';
s_free_run <= '0';
s_load <= '1';
s_next <= '0';
s_direction <= '0';
s_seed <= (OTHERS => '1');
wait for 20 ns;
-- ENABLE ON -> SEED SHOULD BE INITIALIZED
s_enable <= '1';
s_reset <= '0';
s_next <= '0';
s_free_run <= '0';
s_load <= '1';
s_direction <= '0';
s_seed <= (OTHERS => '1');
wait for 20 ns;
-- DRIVE MANUAL
s_next <= '1';
wait for clk_period /2;
s_next <= '0';
wait for clk_period /2;
s_next <= '1';
wait for clk_period /2;
s_next <= '0';
wait for clk_period /2;
Instead of using a clock source multiplexer, you should use a synchronous clock-enable as also suggested by Brian.
When the clock enable is high, the LFSR counts up/down one step at the rising edge of the free-running clock i_clk. The definition is:
If i_free_run is high, then the clock enable is also high, i.e. counting always.
If i_free_run is low, then the clock enable is only high for one clock cycle of i_clk every time i_next has changed from low to high, i.e., single step with i_next.
As i_next is driven by a button, you must:
sample the button value with i_clk, i.e., make it synchronous to clock,
debounce the sampled button value. i_next is then the output of the debouncer.
I have applied this method to your code. To limit the code size, I have shortened the implementation to just one direction and no initialization with a seed. You have to put in your full implementation as indicated. Please note, that you have to initialize the LFSR with all zero when counting up with XNOR.
library ieee;
use ieee.std_logic_1164.all;
entity LFSR_v2 is
Generic (
width : positive := 31;
tap_1 : positive := 30;
tap_2 : positive := 27
);
Port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
-- i_load : in std_logic;
-- i_direction : in std_logic;
-- i_seed : in std_logic_vector (width -1 downto 0)
o_number : out std_logic_vector (width -1 downto 0)
);
end LFSR_v2;
architecture Behavioral of LFSR_v2 is
signal internal_number : std_logic_vector(width -1 downto 0);
signal clock_enable : std_logic;
signal next_old : std_logic := '0'; -- old value of "i_next"
begin
-- calculate clock enable
clock_enable <= '1' when i_free_run = '1' else
i_next and not next_old;
process(i_clk) -- no i_reset here!
begin
if rising_edge(i_clk) then
next_old <= i_next; -- save old value for edge detection
-- This should be outside of the clock-enable block or even a concurrent statement
o_number <= internal_number;
if (clock_enable = '1' and i_enable = '1') then -- "i_enable" as in original code
---------------------------------------------------------------
-- Replace the following short implementation with your full
-- implementation
---------------------------------------------------------------
if(i_reset = '1') then
internal_number <= (OTHERS => '0'); -- must be all zero for XNOR below!
else
internal_number <= internal_number(width - 2 downto 0) &
(internal_number(tap_1) xnor internal_number(tap_2));
end if;
end if;
end if;
end process;
end Behavioral;
This is my testbench:
library ieee;
use ieee.std_logic_1164.all;
entity LFSR_v2_tb is
end LFSR_v2_tb;
architecture sim of LFSR_v2_tb is
component LFSR_v2
generic (
width : positive;
tap_1 : positive;
tap_2 : positive);
port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
o_number : out std_logic_vector (width -1 downto 0));
end component;
-- component generics
constant width : positive := 31;
constant tap_1 : positive := 30;
constant tap_2 : positive := 27;
-- component ports
signal i_enable : std_logic;
signal i_reset : std_logic;
signal i_clk : std_logic := '1';
signal i_next : std_logic;
signal i_free_run : std_logic;
signal o_number : std_logic_vector (width -1 downto 0);
begin -- sim
DUT: LFSR_v2
generic map (
width => width,
tap_1 => tap_1,
tap_2 => tap_2)
port map (
i_enable => i_enable,
i_reset => i_reset,
i_clk => i_clk,
i_next => i_next,
i_free_run => i_free_run,
o_number => o_number);
-- clock generation
i_clk <= not i_clk after 10 ns;
-- waveform generation
WaveGen_Proc : process
begin
i_free_run <= '1'; -- start with a free-running clock
i_reset <= '1';
i_enable <= '1'; -- must be high even for reset
i_next <= '0';
wait until rising_edge(i_clk);
i_reset <= '0'; -- now let the LFSR toogle on i_clk
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
i_free_run <= '0'; -- change to single step mode
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
for i in 1 to 3 loop -- 3 single steps
i_next <= '1'; -- do single step
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
i_next <= '0';
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
end loop; -- i
i_free_run <= '1'; -- change back to free-running clock
wait until rising_edge(i_clk);
wait;
end process WaveGen_Proc;
end sim;
And this is the simulation result. Please note, that the output signal changes rapidly at the "..." boxes.
You can not implement two different designs in one entity.
Use either:
two entities or
two different architectures of the same entity or
two if..generate statements and a generic parameter to switch the implementations.
Solutions 2 and 3 are not so good in your case, because one uses a clock and the other a next signal. One signal is always unused -> the port list of the entity is filled with dummy signals.

How to send some data 10 times with a delay of 10 ms between chunks of databits to the TX port of uart

I have an sensor it has an unlocked byte sequence which needs to be sent to it to unlock it and then it can receive the other command data.
The sensor receive data at a baudrate of 115200 bps, 8 data bits, even parity, 2 stop bits.
and before receiving any command data( used to set parameters) It needs to recieve d4 (hexadecimal number, byte) 10 times at an interval of 1ms.
I send the d4 converted into bits 11010100 added with parity and stop bits becomes 11010100011 to the TX port of uart at the baud rate of 115200 but how to create a delay between two d4 data byte sent ? I am writing the code if not clear please let me know I would put more details.
entity Uart_tx is
port (
TX : out std_logic;
clk_in : in std_logic;
but_div_clk : out std_logic;
clk_in_2 : in std_logic
);
end Uart_tx;
architecture Behavioral of Uart_tx is
signal tx_clk : std_logic := '0';
signal clk_1Khz : std_logic := '0';
signal q : unsigned(8 downto 0) := (others => '0');
signal p : unsigned(8 downto 0) := (others => '0');
type state_type is (idle, start);
signal state : state_type;
signal tick_in : std_logic := '0';
subtype byte is std_logic_Vector(7 downto 0);
type byte_array is array(natural range <>) of byte;
signal data_byte_array : byte_array(1 to 8);
-- signal curr_byte : std_logic_vector(7 downto 0);
signal byte_index : unsigned(2 downto 0) := "000";
subtype reg is std_logic_Vector(10 downto 0);
type reg_array is array(natural range <>) of reg;
signal TxDataReg_array : reg_array(1 to 8);
signal cur_Tx_reg : std_logic_vector(10 downto 0);
signal current_reg : unsigned(3 downto 0) := "0001";
signal count : unsigned (4 downto 0) := (others => '0');
signal count_d : unsigned (4 downto 0) := (others => '0');
signal sent_d4 : unsigned (3 downto 0) := (others => '0');
signal send_d4 : std_logic := '1';
signal D_4 : std_logic_vector(10 downto 0) :="11000101011";
begin
-- below are random entry ..actual data will come from slv_reg registers.
data_byte_array(1) <= "10101010"; -- slv_reg0(7 downto 0);
data_byte_array(2) <= "10101011"; -- slv_reg0(15 downto 8);
data_byte_array(3) <= "10101010"; -- slv_reg0(23 downto 16);
data_byte_array(4) <= "10101011"; -- slv_reg0(31 downto 24);
data_byte_array(5) <= "10101010"; -- slv_reg1(39 downto 32);
data_byte_array(6) <= "10101011"; -- slv_reg1(47 downto 40);
data_byte_array(7) <= "10101010"; -- slv_reg1(55 downto 48);
data_byte_array(8) <= "10101011"; -- slv_reg1(63 downto 56);
tick_in <= '1';
---------------------------------------Clk_div-----------------------------------------
process ( clk_in ) is
begin
if clk_in'event and clk_in = '1' then
q <= q + 1;
tx_clk <= q(8); --- 58.gdfg/2^8 =~ 230Khz baud rate = 115200
but_div_clk <= tx_clk;
end if;
end process;
---------------------------------------Clk_div------------------------------------------
---------------------------------------Clk_div------------------------------------------
process( clk_in_2 ) is
begin
if clk_in_2'event and clk_in_2 = '1' then
p <= p + 1;
clk_1Khz <= p(7);
end if;
end process;
---------------------------------------------------------------------------------------
--------------------------------------TX_Process----------------------------------------
process( state, tx_clk , tick_in) is
variable parity : std_logic := '0';
variable curr_byte : std_logic_vector(7 downto 0) := (others => '0');
begin
case state is
when idle => TX <= '1';
if tick_in = '1' then
state <= start;
else
TX <= '1';
end if;
when start =>
if send_d4 = '1' then
if (rising_edge(clk_1Khz)) then
case count_d is
when "00000" => TX <= D_4(0);
when "00001" => TX <= D_4(1);
when "00010" => TX <= D_4(2);
when "00011" => TX <= D_4(3);
when "00100" => TX <= D_4(4);
when "00101" => TX <= D_4(5);
when "00110" => TX <= D_4(6);
when "00111" => TX <= D_4(7);
when "01000" => TX <= D_4(8);
when "01001" => TX <= D_4(9);
when "01010" => TX <= D_4(10);
when others => TX <= '1';
end case;
count_d <= count_d +1;
sent_d4 <= sent_d4 + 1;
if to_integer(count_d) = 11 then
count_d <= "00000";
end if;
if to_integer(sent_d4) = 10 then
send_d4 <= '0' ;
end if;
end if;
else
for i in 1 to 8 loop
curr_byte := data_byte_array(i);
parity := '0';
for j in curr_byte'range loop
parity := parity xor curr_byte(j);
end loop;
if parity = '0' then
TxDataReg_array(i) <= "110" & curr_byte ;
else
TxDataReg_array(i) <= "111" & curr_byte ;
end if;
end loop;
cur_Tx_reg <= TxDataReg_array(to_integer(byte_index)+1);
byte_index <= byte_index + 1;
if rising_edge(tx_clk) then
case count is
when "00000" => TX <= cur_Tx_reg(0);
when "00001" => TX <= cur_Tx_reg(1);
when "00010" => TX <= cur_Tx_reg(2);
when "00011" => TX <= cur_Tx_reg(3);
when "00100" => TX <= cur_Tx_reg(4);
when "00101" => TX <= cur_Tx_reg(5);
when "00110" => TX <= cur_Tx_reg(6);
when "00111" => TX <= cur_Tx_reg(7);
when "01000" => TX <= cur_Tx_reg(8);
when "01001" => TX <= cur_Tx_reg(9);
when "01010" => TX <= cur_Tx_reg(10);
when others => TX <= '1';
end case;
count <= count+1;
if to_integer(count) = 11 then
count <= "00000";
state <= idle;
-- TX <= '1';
end if;
end if;
end if;
when others => TX <= '1';
end case;
end process;
end Behavioral;
To get a timed delay you have to implement a counter that ticks off a computed number of clock cycles equal to 1 ms. You then need to insert states into your FSM that activate the counter and wait for it to complete when needed. It is possible to manually calculate the counter value but you can make the tools do the work for you and avoid having magic numbers in your code.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
...
constant CLOCK_FREQ : real := 50.0e6; -- 50 MHz system clock
constant SENSOR_DELAY : real := 1.0e-3; -- 1 ms delay
constant DELAY_COUNT : natural := integer(CLOCK_FREQ * SENSOR_DELAY);
-- This could be auto calculated with a ceil_log2() function
constant TIMER_SIZE : natural := 16;
signal timer : unsigned(TIMER_SIZE-1 downto 0);
constant DELAY_INIT : unsigned(timer'range)
:= to_unsigned(DELAY_COUNT, timer'length);
...
-- Initialize the timer sometime before you want the delay
timer <= DELAY_INIT;
...
-- Somewhere in your FSM
when WAIT_1MS =>
timer <= timer - 1;
if timer = 0 then
state <= WHATEVER_YOU_WANT_NEXT;
end if;
This method of using real constants to compute integer values is subject to rounding errors and general floating-point inaccuracies. For these sort of long delays, the small error (typically off-by-one) that could happen isn't usually of concern.
Note that you need to rework your state machine to follow more conventional patterns. You have created a process that mixes pure combinational logic with synchronous. You should not mix the two. You should not have the rising_edge() tests inside your FSM case statement but rather there should be a single if-block evaluating rising_edge() that contains your FSM.
If you need a clock sensitive process then it should only have the clock and an (optional) asynchronous reset in its sensitivity list. Any other pure combinational code should be put in a separate process. In a design such as this that shouldn't be necessary though.
VHDL allows what you have now but synthesis tools expect the use of a more limited style when describing the hardware. You risk having unexpected results if they can handle your code at all.

Asynchrony in vhdl: SPI Slave - Low VIOLATION issue on post-route simulation

I have implemented very simple SPI slave interface: 8 bit, MSB first, pol=1 pha=1. CS pin and 'Z' state of SO is not required. Max SPI SCK is 8 MHz. System clock 50 MHz
Code:
entity spi_slave_if is Port (
si : in STD_LOGIC;
sck : in STD_LOGIC;
so : out STD_LOGIC;
clk : in std_logic;
reset : in std_logic;
data_out : in std_logic_vector(7 downto 0); -- data for send
data_in : out std_logic_vector(7 downto 0); -- received data
transaction_done : out std_logic);
end spi_slave_if;
architecture Behavioral of spi_slave_if is
signal cur_bit, prev_bit: unsigned(2 downto 0);
begin
process(sck) begin
if falling_edge(sck) then
so <= data_out(to_integer(cur_bit));
end if;
end process;
process(sck, reset) begin
if (reset = '1') then
data_in <= (others => '0');
cur_bit <= to_unsigned(7, 3);
elsif rising_edge(sck) then
data_in(to_integer(cur_bit)) <= si;
cur_bit <= cur_bit - 1;
end if;
end process;
process(clk, reset)
variable td_raised: boolean;
begin
if reset = '1' then
prev_bit <= to_unsigned(7, 3);
td_raised := false;
transaction_done <= '0';
elsif falling_edge(clk) then
prev_bit <= cur_bit;
if td_raised then
transaction_done <= '0';
td_raised := false;
elsif (to_integer(prev_bit) = 0 and to_integer(cur_bit) = 7 ) then
transaction_done <= '1';
td_raised := true;
end if;
end if;
end process;
end Behavioral;
In testbench I try to model async master interface(with random data bytes) and random delays:
loop
UNIFORM(seed1, seed2, rand);
int_rand := INTEGER(TRUNC(rand*255.0)); -- rescale to 0..255
test_1_transact(125 ns, std_logic_vector(to_unsigned(int_rand, 8)));
wait for 1us; -- model async delay
wait for ((rand*0.00000001)*1 sec);
wait for ((rand*0.000000001)*1 sec);
wait for ((rand*0.0000000001)*1 sec);
end loop;
Where test_1_transact is:
procedure test_1_transact(constant prd : time; constant si_data &colon; std_logic_vector (7 downto 0)) is begin
data_out <= not si_data; --for back test invert dorward data
wait for 20ns; -- wait for data apply
FOR i IN 7 downto 0 LOOP
si <= si_data(i);
sck <= '0'; wait for prd / 2;
sck <= '1'; wait for prd / 2;
END LOOP;
end procedure;
When I do behevioral simulation code works fine all time.
But when I try to perform post route simulation, code also works first 47us, but then it failed, ISIM say me:
at 49422978 ps(3), Instance /test_spi_slv_if/uut/prev_bit_0/ : Warning: /X_FF HOLD Low VIOLATION ON I WITH RESPECT TO CLK;
Expected := 0.048 ns; Observed := 0.036 ns; At : 49422.978 ns
at 49922978 ps(3), Instance /test_spi_slv_if/uut/prev_bit_0/ : Warning: /X_FF HOLD Low VIOLATION ON I WITH RESPECT TO CLK;
Expected := 0.048 ns; Observed := 0.036 ns; At : 49922.978 ns
And on this moment transaction_done don't work.
Is there in vhdl some way to solve this?

Resources