VHDL shift register with enable - vhdl

I am newbie to VHDL. I am implementing serial in serial out 72 bit shift register using VHDL. When the enable signal is high, I want the shift register to shift 72 times, irrespective of whether enable continues to be high or low. I have written the following code which is working only when the enable is high. Can anyone please help me to shift data once enable is high and then does not depend on enable to shift the data?
library ieee;
use ieee.std_logic_1164.all;
entity SR is
port(clk, din, rst, enable : in std_logic;
sr_out : inout std_logic_vector(71 downto 0));
end SR;
architecture behavioral of SR is
signal shift_reg: std_logic_vector(71 downto 0);
begin
process (clk, rst)
begin
if (rst = '0') then
shift_reg <= (others => '0');
elsif (clk'event and clk = '1') then
if enable= '1' then
shift_reg(70 downto 0) <= shift_reg(71 downto 1);
shift_reg(71) <= din;
end if;
end if;
end process;
sr_out <= shift_reg;
end behavioral;
Thanks a lot!

I think you need an RS-FlipFlop which is set by a start signal. Its output is your enable signal. The start signal also starts a 72 clock cycle counter. When the counter rolls over (or reaches zero, depending on its direction) you reset the FlipFlop which results in a disabled shift register.
edit: In addition you can add a gate to the start signal which blocks new start impulses while the counter is active. So you can be sure your data is only shifted with a multiple of 72 bits.

You need a two states machine to do so. Here's a very good idea of how to do it. I'm pretty sure it does what you need or is very close to.
library ieee;
use ieee.std_logic_1164.all;
entity SR is
port(
clk : in std_logic;
din : in std_logic;
rst : in std_logic;
enable : in std_logic;
sr_out : inout std_logic_vector(71 downto 0)
);
end SR;
architecture behavioral of SR is
signal shift_reg : std_logic_vector(71 downto 0);
signal shift_cnt : integer range 0 to 72 := 0;
type T_STATE_TYPE is (IDLE, COUNTING);
signal current_state : T_STATE_TYPE;
begin
p_shift_counter : process(clk,rst)
begin
if rst = '1' then
current_state <= IDLE;
shift_cnt <= 0;
elsif rising_edge(clk) then
if (current_state = IDLE) then --no enable detected yet
shift_cnt <= 0;
if enable = '1' then
current_state <= COUNTING;
end if;
elsif (current_state = COUNTING) then --will stay in that state until it finishes counting
if (shift_cnt < 72) then
shift_reg(0) <= din;
for i in 0 to 71 loop shift_reg(i+1) <= shift_reg(i); end loop; --shifting register
shift_cnt <= shift_cnt + 1;
else
current_state <= IDLE; --finished counting
end if;
end if;
end if;
end process;
sr_out <= shift_reg;
end behavioral;

Related

Shift Right (srl) going wrong on VHDL Quartus II

I'm trying to make a 8-bit Sequential Multiplier on Quartus II. I did all the simulations of all blocks, but one is showing error on the VWF simulation. The sum_reg block it's doing a infinite shift in a very small time interval.
In the "dark blue" part of waveform simulation, on o_DOUT, it's when the shift gones infinite until the MSB goes to the LSB. The image below shows what happens in the dark blue part of the simulation:
Someone know what's happen?
Below the code:
Sum register(where the simulation goes wrong):
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity sum_register is
port (
i_DIN : in UNSIGNED(8 DOWNTO 0);
i_LOAD : in STD_LOGIC;
i_CLEAR : in STD_LOGIC;
i_SHIFT : in STD_LOGIC;
o_DOUT : buffer UNSIGNED(15 downto 0)
);
end sum_register;
architecture arch_1 of sum_register is
begin
process(i_CLEAR,i_LOAD,i_SHIFT, i_DIN)
begin
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 7) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
end process;
end arch_1;
You need to use a clock signal in the circuit to make this synchronous, you will need an input in your entity like this:
i_CLOCK : in STD_ULOGIC;
After this you will need to make your process sensitivy to the clock:
process(i_CLOCK)
And your architecture will change to this:
architecture arch_1 of sum_register is
SIGNAL r_DOUT : unsigned(15 downto 0);
begin
process(i_CLOCK)
begin
IF rising_edge(i_CLOCK) THEN
IF (i_CLEAR = '1') THEN
r_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
r_DOUT(15 downto 8) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
r_DOUT <= r_DOUT SRL 1;
END IF;
END IF;
end process;
o_DOUT <= r_DOUT;
end arch_1;
With this architecture you will need a unsigned signal to make atribution for your output o_DOUT, with this you can change your o_DOUT output to output type again (not buffer).
NOTE: The clock signal needs to be the same for all blocks!

Servo Control using FPGA (Altera DE2)

I am creating a VHDL code for controlling servo position using 8 switches on DE2 development kit. When the code is done, I tested the code with the servo motor but it is not working. Then I did a waveform simulation with timing analysis, I found that there is some glitches in the wave. Is it glitch the reason why this is not working? If yes, how can I solve this?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity servo_pwm is
PORT (
clk50 : IN STD_LOGIC;
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
position : IN STD_LOGIC_VECTOR(7 downto 0);
servo : OUT STD_LOGIC
);
end servo_pwm;
architecture Behavioral of servo_pwm is
signal cnt : unsigned(11 downto 0);
signal pwmi: unsigned(7 downto 0);
begin
pwmi <= unsigned(position);
start: process (reset, clk) begin
if (reset = '1') then
cnt <= (others => '0');
elsif rising_edge(clk) then
if (cnt = 2559) then
cnt <= (others => '0');
else
cnt <= cnt + 1;
end if;
end if;
end process;
servo <= '1' when (cnt < pwmi) else '0';
end Behavioral;
Clock divider:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity clk64kHz is
Port (
clk : in STD_LOGIC;
reset : in STD_LOGIC;
clk_out: out STD_LOGIC
);
end clk64kHz;
architecture Behavioral of clk64kHz is
signal temporal: STD_LOGIC;
signal counter : integer range 0 to 195 := 0; --position 8bit
begin
freq_divider: process (reset, clk) begin
if (reset = '1') then
temporal <= '0';
counter <= 0;
--elsif rising_edge(clk) then
elsif (clk'event and clk = '1') then
--if (counter = 390) then
if (counter = 195) then
temporal <= NOT(temporal);
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
clk_out <= temporal;
end Behavioral;
Vector waveform file:

VHDL - coding error of value outside the clock edge

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity RAM_controler is
port(
clk_50 : in std_logic;
clk_baud : in std_logic;
main_reset : in std_logic;
enable: in std_logic; --active high write enable
in_data : in std_logic_vector(7 downto 0);
W_order : out std_logic;
R_order : out std_logic;
Data_OUT : out std_logic_vector(7 downto 0);
Write_Address_OUT: out std_logic_vector(7 downto 0);
Read_Address_OUT: out std_logic_vector(7 downto 0)
);
end entity RAM_controler;
architecture Behavioral of RAM_controler is
type state is (reset,operation);
signal state_reg,next_state_reg : state;
signal write_address : std_logic_vector(W-1 downto 0):="00000000";
signal next_write_address : std_logic_vector(W-1 downto 0):="00000000";
begin
state_change : process(clk_50, main_reset)
begin
if (main_reset = '1') then
state_reg <= reset;
elsif (rising_edge(clk_50)) then
state_reg <= operation;
read_counter <= next_read_counter;
write_address<= next_write_address;
read_address <= next_read_address;
end if;
end process;
writecounter : process(clk_baud, main_reset,enable)
begin
if (main_reset='1') then
next_write_address <= "00000000";
Data_OUT <= "ZZZZZZZZ";
W_order <='0';
Write_Address_OUT <="ZZZZZZZZ";
elsif (rising_edge(clk_baud) and enable='1' ) then
W_order <='1';
Data_OUT <= in_data;
Write_Address_OUT <= write_address;
if (write_address = "11111111") then
next_write_address <= "00000000";
else
next_write_address <= write_address+1;
end if;
else
W_order <='0';
Write_Address_OUT <= "ZZZZZZZZ";
next_write_address <= write_address+1;
end if;
end process;
end Behavioral;
Above code is describing RAM controller.
The part of making problem is "elsif (rising_edge(clk_baud) and enable='1' ) then".
Error : Can`t inter register for "Write_Address_OUT" at RAM_controler.vhd because it does not hold its value outside the clock edge
I don`t know why that point is error.
Is there anyone who advice to me?
Thank you!
If you're coding sequential logic, it is wise to stick to a template. Here is one such template for sequential logic with an asynchronous reset, which all synthesis tools should understand:
process(clock, async_reset) -- nothing else should go in the sensitivity list
begin
-- never put anything here
if async_reset ='1' then -- or '0' for an active low reset
-- set/reset the flip-flops here
-- ie drive the signals to their initial values
elsif rising_edge(clock) then -- or falling_edge(clock)
-- put the synchronous stuff here
-- ie the stuff that happens on the rising or falling edge of the clock
end if;
-- never put anything here
end process;
So enable should not be in the senstivity list and it should not be tested in the same if statement as the asynchronous reset and the clock is tested.
The reason why your are getting this error:
Error : Can`t inter register for "Write_Address_OUT" at
RAM_controler.vhd because it does not hold its value outside the clock
edge
is because the last three assignments in your code:
W_order <='0';
Write_Address_OUT <= "ZZZZZZZZ";
next_write_address <= write_address+1;
can occur on the falling edge of the clock or (because you also had enable in your sensitivity list) independently of any clock at all. A logic synthesiser can't synthesise logic that behaves like that. If you stick to the template, you won't run into this kind of problem (and it makes you think a bit more carefully about what logic you are expecting the synthesiser to synthesise).
So, I would have coded your writecounter process more like this:
writecounter : process(clk_baud, main_reset)
begin
if (main_reset='1') then
next_write_address <= "00000000";
Data_OUT <= "ZZZZZZZZ";
W_order <='0';
Write_Address_OUT <="ZZZZZZZZ";
elsif rising_edge(clk_baud) then
if enable='1' then
W_order <='1';
Data_OUT <= in_data;
Write_Address_OUT <= write_address;
if (write_address = "11111111") then
next_write_address <= "00000000";
else
next_write_address <= write_address+1;
end if;
else
W_order <='0';
Write_Address_OUT <= "ZZZZZZZZ";
next_write_address <= write_address+1;
end if;
end if;
end process;
Though, I should emphasise that my code does not behave exactly like yours. I don't know your design intent, so I can only guess what you intended. If you intended some other behaviour, then you will have to implement that instead. My advice about sticking to a template is nevertheless important, whatever your design intent.
The final else in your code should actually be:
elsif (rising_edge(clk_baud) and enable='0' ) then

vhdl code for producig triangular wave using DAC2904 is not working

I am doing a project in college and want to produce a triangular wave using a DAC2904 and a Spartan 3 xc3s5000 board.
I have written code for it but is not working.
I don't know may be it is the problem in code or in my ucf file:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity traingular is
Port (
clk : in std_logic; -- on board clock
reset : in std_logic;
dac_clk : out std_logic; -- clk for dac module
output : out std_logic_vector(13 downto 0); -- output to dac
wr_dac : out std_logic -- pulse given to write pin of dac ic.
);
end traingular;
architecture Behavioral of traingular is
signal counter : unsigned(3 downto 0);
signal divide : std_logic_vector(15 downto 0);
signal sampling_clk , clk_s : std_logic;
signal decade : std_logic_vector(3 downto 0);
-- decade counter used because on board clk freq is 40 hz
-- so the code written below reduce the freq which is applied to dac module very much
begin
process(clk, reset)
begin
if (reset = '1' ) then
decade <= (others => '0');
elsif (clk' event and clk = '1') then
if (decade = "1010") then
decade <= (others => '0');
else
decade <= std_logic_vector(unsigned(decade) + 1);
end if;
end if;
end process;
clk_s <= '1' when decade = "1010" else
'0';
process(clk_s , reset)
begin
if (reset='1') then
divide <= (others => '0');
elsif (clk_s'event and clk_s = '1') then
divide <= std_logic_vector(unsigned(divide) + 1);
end if;
end process;
sampling_clk <= divide(2);
-- input click is still fast so clock is divided further
dac_clk <= sampling_clk;
wr_dac <= sampling_clk;
process(clk , reset)
begin
-- code below is for counter which will further feed to dac to produce traingular wave.
if (reset = '1' ) then
counter <= (others => '0');
elsif (clk' event and clk = '1') then
if (counter = "1010") then
counter <= (others => '0');
else
counter <= counter + 1;
end if;
end if;
end process;
output <= "0000000000" & std_logic_vector(counter); -- output to dac.
end Behavioral;
So, can you guys tell me what is the problem in my code.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_signed.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity tri_wave is
Port ( clk : in STD_LOGIC;
rst :in STD_LOGIC;
up_step_size,down_step_size:in std_logic_vector(2 downto 0);
dac_out : out STD_LOGIC_VECTOR (7 downto 0));
end tri_wave;
architecture Behavioral of tri_wave is
signal dac_wav:std_logic_vector(7 downto 0);
signal count:std_logic_vector(7 downto 0);
signal dir:std_logic:='0';
begin
process(clk,rst,dir)
begin
if rst='1' then
count<=(others=>'0');
elsif dir='0' then
if clk'event and clk='1' then
if count="01111111" then
dir<='1' ;
else
count<= count + up_step_size;
end if;
end if;
elsif dir='1' then
if clk'event and clk='1' then
if count="10000000" then
dir<='0' ;
else
count<= count - down_step_size;
end if;
end if;
end if;
end process;
--dac_out<=count;
dac_out<=count(count'high) & count(6 downto 0);
end Behavioral;
i think this code gives u better idea just creaet tb and simulae i odelsim u will get it.

Random LED turning on and off in VHDL

I want to implement a random-number game on BASYS2. In this game there would be five LEDs chosen out of which one would turn on at random for a second or two (this time can be changed to increase or decrease the difficulty level of the game). Then the user is required to respond to this LED event by pressing the switch button behind it within the time that it is on. If he or she is able to do so successfully a point would be scored and it would be showed on the Seven Segment Display. If he or she fails no point would be scored. There would be 9 such events after which the game can be replayed.
Now following is my code (only for the random LED turning on). However, I am unable to fix it. Please somebody help. The FPGA I am using is BASYS2 SPARTAN 3E-100.
Thanks in advance to everyone.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity random_number is
generic ( width : integer := 4 );
port (
clk : in std_logic;
reset : in std_logic;
random_num : out std_logic_vector (width-1 downto 0) --output vector
);
end random_number;
architecture Behavioral of random_number is
signal q: std_logic_vector(23 downto 0);
signal divided_clock: std_logic;
begin
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
end process;
divided_clock <= q(22);
process (divided_clock)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(divided_clock)) then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
random_num <= rand_temp;
end process;
end Behavioral;
I think the second process should even run with the main clk and the devided clock should be an enable.
signal divided_enable: std_logic;
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
if (q(22) = '1') then
--short pulse wenn q bit 22 is high
divided_enable <= '1';
q <= (others => '0');
end if;
end process;
process (clk)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(clk)) then
if(divided_enable = '1') then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
end if;
random_num <= rand_temp;
end process;
I don't know if this will fix all your problems. Please discribe compiler errors or errors in the behavior.

Resources