Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17049 Discussions

Control shift registers with FPGA

Altera_Forum
Honored Contributor II
1,505 Views

Hi all, I am new here. I tell you my problem. I have been now several days trying to figure it out how to control shift registers SIPO 74LS164 with my FPGA. I am doing a clock, displaying hours, minutes and seconds with NIXIE tubes. What I need to do is to send each second, 24 bits, and remain those 24 bits displaying in the NIXIE tubes during the second, till the new second comes and new 24 bits are sent. Maybe this is a stupid question but I don't know how to produce my clock signal and my serial output to control this ICs.I already have a vector of 24 bits and the schematic of how cascading these ICs so that's not the problem. I think you get which my problem is.Please if somebody can help me would be so so great!Thank you very muchRegards

0 Kudos
11 Replies
Altera_Forum
Honored Contributor II
830 Views
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Design a finite state machine. The states may be: 

 

s0 - wait for a internal "start" signal goes to '1', that triggers the transmission. If this is true, load register n with 24 ( 24 bits ) and go to state s1. 

 

s1- put a data bit on 74LS164 serial in. go to state s2 

 

s2 - rise 74ls164 clock signal. go to state s3 

 

s3 - place '0' on 74ls164 signal. go to state s4 

 

s4 - shift data register, decrement n register. go to state s5. 

 

s5 - if n register is 0 you ended your transmission. If no 0, go to state s1. 

 

Translate this to vhdl. You could do with fewer states.
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Thank you very much for your reply, it helped me a lot on how focus the problem. Now my problem is with the state machine itself. I paste here the code  

 

LIBRARY IEEE; 

USE IEEE.STD_LOGIC_1164.ALL; 

USE IEEE.NUMERIC_STD.ALL; 

 

 

entity control_unit2 IS 

port (clk2: in std_logic; 

clk: in std_logic; 

data : in std_logic_vector (23 downto 0); 

data_out : out std_logic; 

clk_out : out std_logic); 

end control_unit2; 

 

Architecture Behavioral of control_unit2 is  

 

type state_type is (start, load, pulse, rst, shift, check); 

 

signal pstate, nstate : state_type := start; 

 

signal data_reg : std_logic_vector (23 downto 0); 

 

signal data_aux: std_logic ; 

 

signal clk_aux: std_logic; 

 

signal trigger: std_logic := '0'; 

 

 

BEGIN 

 

 

 

clocked: PROCESS (clk2,clk) 

 

 

BEGIN 

 

if clk2'event and clk2 = '1' then 

 

pstate <= nstate; 

 

END IF; 

 

END PROCESS clocked; 

 

states: process(pstate,data,trigger, clk) 

 

variable i : integer; 

 

begin 

 

case pstate is 

 

when start => 

 

i := 24; 

data_reg <= data; 

nstate <= load; 

 

when load =>  

 

data_aux <= data_reg(i); 

nstate <= pulse; 

 

when pulse => 

 

clk_aux <= '1'; 

nstate <= rst; 

 

when rst =>  

 

clk_aux <= '0'; 

nstate <= shift; 

 

when shift =>  

 

i := i - 1;  

nstate <= check; 

 

when check =>  

 

if i = 0 then 

nstate <= waiting; 

 

else  

 

nstate <= load; 

 

end if; 

 

end case; 

 

end process states; 

 

clk_out <= clk_aux; 

 

data_out <= data_aux; 

 

 

 

 

END Behavioral; 

 

 

 

The problem is in the state 0. My start signal, following your explanation, is a falling edge of the clock clk. That falling edge tell me when a second starts, i.e. when I must start sending data through the output.  

 

 

When I try to synthesize this I get this error: Error (10822): HDL error at control_unit2.vhd(55): couldn't implement registers for assignments on this clock edge 

 

I don't know where is the problem and what should I do to solve it. Can you help me?  

 

Thank you again. 

 

Regards
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

The code looks very good. But u have to fix some things: 

 

a-u have 2 inputs clocks: clk and clk2. Your design needs no more than 1 clock. 

 

b-u separate the register description from the next state logic. I like that, it's very clear. But when u declare pstate and nstate u assign an initial state ( start ). This doesn't work. It only have sense for simulation purposes. Set an initial state in the register description: 

 

if( reset = '0' ) then 

pstate <= start; 

elsif(clk'event and clk = '1') then 

pstate <= nstate; 

end if; 

 

c-You have a trigger signal. How do u use it? And where you generate it? 

 

d-I don't now where is the line 55, that generates the error. 

 

Regards.
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Thank you for your reply.  

 

Regarding the 2 clocks, one its acting like a clock itself (clk2), but the other one is the 1 Hz signal generated to get the seconds value and synchronized with the DCF77 signal (it's a long wave time signal, which I use for this project). This 1 Hz signal is generated in another block (I'm doing this with blocks in Quartus II). I need that 1 Hz clock to send the datas at the beginning of the second (falling edge of this signal). 

 

b. I think I get the point but the problem is that I need, like I said before, to go to the "start" state, each time I get a falling edge on clk (1 Hz signal) and that's the problem I have, I don't know how to do this. 

 

c. Sorry for that, it's just something I was trying and then forgot to delete it.  

 

d. I pasted you another code sorry, just change in the description of the "start" state and here it is and it's where I get the error: 

 

begin 

 

case pstate is 

 

when start => 

 

if clk'event and clk = '0' then -- Falling edge on the 1 Hz clock  

 

i := 24; 

data_reg <= data; 

nstate <= load; 

 

else  

 

nstate <= start; 

 

end if; 

 

What I am trying to do here, is to create a "bucle" in the "start" state, waiting for that falling edge.  

 

I hope I make myself clear. 

 

Thank you again, very much. 

 

Regards
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Ok. The second clock ( clk ) is like a trigger signal. I write the transitions this way: 

 

process... 

begin 

nstate <= pstate; 

clk2_next <= clk2_reg; 

dat_next <= dat_reg; 

n_next <= n_reg; 

case pstate is 

when reposo => 

if ( clk = '0' ) then --- falling edge 

nstate <= etapa1; 

end if; 

when etapa1 => 

dat_next <= shift_reg(23); 

nstate <= etapa2; 

when etapa2 => 

shift_next <= shift_reg(22 downto 1) & '0'; 

n_next <= n_reg - 1; 

when etap3 => 

... -- up clkout 

when etapa4 => 

-- down clkcout 

when etapa5 => 

if( n_reg = 0 ) then 

nstate <= reposo; 

else 

nstate <= etapa1; 

when others =>.... 

 

I worked the clock and data out as register.
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Thank you again for your time. 

I don't know if I got it. If I understood, this is what you said: 

LIBRARY IEEE; 

USE IEEE.STD_LOGIC_1164.ALL; 

USE IEEE.NUMERIC_STD.ALL; 

 

entity control_unit2 IS 

port (clk2: in std_logic; 

clk: in std_logic; 

reset : in std_logic; 

data : in std_logic_vector (23 downto 0); 

data_out : out std_logic; 

clk_out : out std_logic); 

end control_unit2; 

 

Architecture Behavioral of control_unit2 is  

 

type state_type is (reposo, etapa1, etapa2, etapa3, etapa4, etapa5); 

 

signal pstate, nstate : state_type; 

 

signal data_reg : std_logic_vector (23 downto 0); 

 

signal data_aux: std_logic; 

 

signal clk_aux: std_logic; 

 

signal clk_next: std_logic; 

 

 

 

BEGIN 

 

 

clocked: PROCESS (clk2) 

 

 

BEGIN 

if reset = '1' then 

 

pstate <= reposo; 

elsif clk2'event and clk2 = '1' then 

 

pstate <= nstate; 

 

END IF; 

 

END PROCESS clocked; 

 

states: process(pstate,data,clk) 

 

variable i : integer; 

 

begin 

 

clk_next <= clk;  

data_reg <= data; 

 

case pstate is 

 

 

 

when reposo => 

 

if clk_next = '0' then  

nstate <= etapa1; 

i := 24; 

end if; 

 

when etapa1 =>  

 

data_aux <= data_reg(23); 

nstate <= etapa2; 

when etapa2 =>  

 

data_reg <= data_reg(22 downto 0) & '0'; 

i := i - 1; 

nstate <= etapa3; 

 

when etapa3 =>  

 

clk_aux <= '1'; 

nstate <= etapa4; 

 

when etapa4 => 

 

clk_aux <= '0'; 

nstate <= etapa5; 

 

when etapa5 =>  

 

if (i = 0) then  

 

nstate <= reposo; 

 

else  

 

nstate <= etapa1; 

 

end if; 

 

end case; 

 

end process states; 

 

clk_out <= clk_aux; 

 

data_out <= data_aux; 

 

 

 

 

END Behavioral; 

I put in black, the critical point of the problem. How can that be a falling edge?. If i write here: 

 

when reposo => 

 

if clk'next'event and clk_next = '0' then -- or with clk itself  

nstate <= etapa1; 

i := 24; 

end if; 

 

I will get an error like this: "Error (10822): couldn't implement registers for assignments on this clock edge" 

And with the code like it is wrote above, I get in the clock output a clock signal working during half second (time when clk = 0) and nothing in the data output. I really don't know where is the mistake. I also looked the input data for this block and I get them right but not in the ouput. On the other hand, in clk_out I should just have 24 pulses instead of the whole half second with the clk2 frequency. Any tips? 

Thank you very much again and sorry if my questions are very basic... I'm pretty new with VHDL.
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Probably you have an inferred latch on dat_reg. Use next state logic like you do with the state reg: 

 

if reset = '1' then 

pstate <= reposo; 

data_reg <= ( others => '0' ); 

clk_reg <= '0'; 

dat_reg <= '0'; 

i_reg <= ( others => '0' ); 

elsif clk2'event and clk2 = '1' then 

pstate <= nstate; 

data_reg <= data_next; -- next state logic for the registers 

clk_reg <= clk_aux; 

dat_reg <= dat_aux; 

i_reg <= i_next; 

END IF; 

 

states: process(pstate,data,clk) 

 

begin 

 

clk_next <= clk;  

 

data_aux <= data_reg; 

 

 

case pstate is 

 

 

 

when reposo => 

 

if clk_next = '0' then 

nstate <= etapa1; 

i_reg <= to_unsigned(24, 5); -- declare i_reg as a 5 bits unsigned vector 

end if; 

 

when etapa1 => 

 

data_aux <= data_reg(23); 

nstate <= etapa2; 

 

when etapa2 => 

 

data_aux<= data_reg(22 downto 0) & '0'; -- don't use reg, use next ( or aux as u call it ) 

i_next := i_reg - 1; -- i don't like variables. I generate a register above 

nstate <= etapa3; 

 

when etapa3 => 

 

clk_aux <= '1'; 

nstate <= etapa4; 

 

when etapa4 => 

 

clk_aux <= '0'; 

nstate <= etapa5; 

 

when etapa5 => 

 

if (i = 0) then 

 

nstate <= reposo; 

 

else 

 

nstate <= etapa1; 

 

end if; 

 

 

end case; 

 

end process states; 

 

clk_out <= clk_reg; 

 

data_out <= dat_reg; 

 

 

 

 

END Behavioral;  

 

Something like this.
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Hi again, thank you for your answer. 

 

Still getting at the output clk_out, a clock signal always running, instead of the 24 pulses I should (or want to) have, and nothing in the data output.  

 

I am handling now the "trigger" signal, in a separate block, detecting there the falling edge and sending a pulse to the State Machine block when it is detected.  

 

When I compile the following code, I don't get errors but I get a lot of warnings. One of them are:  

 

Inferring latches for signals : i_next, data_next, clk_aux and data_aux. 

 

And: Latch data_next(23) has unsafe behavior (this happens with all data_next bits). 

 

I paste here the code and please tell me where is the error, I was a bit confused with the last answer with so many _reg, _aux and _next and I don't know if I understood it. 

 

entity control_unit2 IS port (clk2: in std_logic; trigger: in std_logic; data : in std_logic_vector (23 downto 0); data_out : out std_logic; clk_out : out std_logic); end control_unit2; Architecture Behavioral of control_unit2 is type state_type is (start, load, pulse, rst, shift, check, hold); signal pstate, nstate : state_type; signal data_reg : std_logic_vector (23 downto 0); signal data_next: std_logic_vector (23 downto 0); signal i_reg : unsigned (4 downto 0); signal i_next: unsigned (4 downto 0); signal data_aux: std_logic ; signal clk_aux: std_logic; BEGIN clocked: PROCESS (clk2) BEGIN if clk2'event and clk2 = '1' then if trigger = '1' then pstate <= start; else pstate <= nstate; i_reg <= i_next; data_reg <= data_next; end if; END IF; END PROCESS clocked; states: process(pstate,data,trigger) begin case pstate is when start => i_next <= to_unsigned(24,5); data_next <= data; nstate <= load; clk_aux <= '0'; when load => data_aux <= data_reg(23); nstate <= pulse; clk_aux <= '0'; i_next <= i_reg; when pulse => data_next <= data_reg(22 downto 0) & '0'; clk_aux <= '1'; nstate <= rst; i_next <= i_reg; when rst => i_next <= i_reg; clk_aux <= '0'; nstate <= shift; when shift => i_next <= i_reg - 1; nstate <= check; when check => if i_reg = 0 then nstate <= hold; else nstate <= load; end if; when hold => nstate <= hold; end case; end process states; clk_out <= clk_aux; data_out <= data_aux; END Behavioral; 

 

 

Thank you again 

 

Regards
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

First of all, i recommend you when you design a finite state machine in vhdl use next state logic approach for all regiters. VHDL is not a programming language like C or basic. Read the books of Stephen Brown or Pong Chu to understand the method. 

 

Some signals has no a default value. This is the cause of the error: 

 

states: process(pstate,data,trigger) 

 

begin 

i_next <= i_reg; -- default value 

data_next <= reg; -- default value 

.... -- and this for all registers 

case pstate is 

 

when start => 

 

i_next <= to_unsigned(24,5); 

data_next <= data; 

nstate <... 

 

 

The other things is the name and purpose of signals are bit confused. I give a suggestion: 

 

entity control_unit2 IS 

port( 

reset : in std_logic; 

clk : in std_logic; 

trigger: in std_logic; 

data : in std_logic_vector (23 downto 0); 

data_out : out std_logic; 

clk_out : out std_logic 

); 

end control_unit2; 

 

Architecture Behavioral of control_unit2 is  

type state_type is (start, load, pulse, rst, shift, check, hold); 

signal pstate, nstate : state_type; 

signal data_reg, data_next : std_logic_vector (23 downto 0); 

 

signal i_reg, i_next : unsigned (4 downto 0); 

signal datout_reg, datout_next: std_logic ; 

signal clkout_reg, clkout_next: std_logic; 

 

BEGIN 

clocked: PROCESS (clk) 

BEGIN 

if( reset = '1' ) then  

pstate <= start; 

i_reg <= ( others => '0' ); 

data_reg <= ( others => '0' ); 

datout_reg <= '0'; 

clkout_reg <= '0'; 

elsif clk'event and clk = '1' then 

pstate <= nstate; 

i_reg <= i_next; 

data_reg <= data_next; 

datout_reg <= datout_next; 

clkout_reg <= clkout_next; 

END IF; 

END PROCESS clocked; 

 

states: process(pstate,data,trigger) -- complete de sensitivity list 

begin 

data_next <= data_reg; 

i_next <= i_reg; 

clkout_next <= clkout_reg; 

datout_reg <= datout_next; 

case pstate is 

 

when start => 

 

i_next <= to_unsigned(24,5); 

data_next <= data; 

nstate <= load; 

clk_next <= '0'; 

 

when load =>  

 

datout_next <= data_reg(23); 

nstate <= pulse; 

clk_next <= '0'; 

i_next <= i_reg; 

 

 

when pulse => 

 

data_next <= data_reg(22 downto 0) & '0'; 

clkout_next <= '1'; 

nstate <= rst; 

i_next <= i_reg; 

 

when rst =>  

 

i_next <= i_reg; 

clkout_next <= '0'; 

nstate <= shift; 

 

when shift =>  

 

i_next <= i_reg - 1; 

 

nstate <= check; 

 

when check =>  

 

if i_reg = 0 then 

 

nstate <= hold; 

 

else  

 

nstate <= load; 

 

end if; 

 

when hold =>  

 

nstate <= hold; 

-- GENERATE a 1 CLOCK PULSE SIGNAL IN '1' TO TELL OTHER CIRCUIT THAT 

-- YOU FINISH THE TRANSMISSION. THEN RETURN TO START STATE TO 

-- WAIT ANOTHER TRIGGER 

 

end case; 

 

end process states; 

 

clk_out <= clkout_reg; 

 

data_out <= datout_reg; 

 

 

 

 

END Behavioral; 

 

I hope this fix the errors.
0 Kudos
Altera_Forum
Honored Contributor II
830 Views

Finally! It worked! I didn't use the "hold" state at the end, I didn't see it neccesary and it seems to work fine, I'll continue checking it to see if its consistent in time. However I paste here the code again, in case someone has the same problem or see something wrong in it.  

 

I don't know how to thank you for your help, you saved me. I wish one day I can return the favor. Thank you very much! 

 

LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; entity control_unit2 IS port (reset: in std_logic; clk: in std_logic; trigger: in std_logic; data : in std_logic_vector (23 downto 0); data_out : out std_logic; clk_out : out std_logic); end control_unit2; Architecture Behavioral of control_unit2 is type state_type is (start, load, pulse, rst, shift, check); signal pstate, nstate : state_type; signal data_reg : std_logic_vector (23 downto 0); signal data_next: std_logic_vector (23 downto 0); signal i_reg : unsigned (4 downto 0); signal i_next: unsigned (4 downto 0); signal datout_reg, datout_next: std_logic ; signal clkout_reg, clkout_next: std_logic; BEGIN clocked: PROCESS (clk,reset) BEGIN if (reset = '1') then pstate <= start; i_reg <= (others => '0'); data_reg <= (others => '0'); datout_reg <= '0'; clkout_reg <= '0'; elsif clk'event and clk = '1' then pstate <= nstate; i_reg <= i_next; data_reg <= data_next; datout_reg <= datout_next; clkout_reg <= clkout_next; end if; end process clocked; states: process(datout_reg, pstate,data,trigger,data_reg,clkout_reg,i_reg) begin data_next <= data_reg; i_next <= i_reg; clkout_next <= clkout_reg; datout_next <= datout_reg; case pstate is when start => if trigger = '1' then i_next <= to_unsigned(24,5); data_next <= data; nstate <= load; clkout_next <= '0'; else nstate <= start; end if; when load => datout_next <= data_reg(23); nstate <= pulse; clkout_next <= '0'; i_next <= i_reg; when pulse => data_next <= data_reg(22 downto 0) & '0'; clkout_next <= '1'; nstate <= rst; i_next <= i_reg; when rst => i_next <= i_reg; clkout_next <= '0'; nstate <= shift; when shift => i_next <= i_reg - 1; nstate <= check; when check => if i_reg = 0 then nstate <= start; else nstate <= load; end if; end case; end process states; clk_out <= clkout_reg; data_out <= datout_reg; END Behavioral; 

 

 

 

Pdta: I will read one of those books! Thanks!
0 Kudos
Reply