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

Problem with asynchronous FSM - VHDL

Altera_Forum
Honored Contributor II
4,404 Views

I have a problem with implementation of finite state machine, which is responsible for detection of motor direction based on signals from HALL sensors. The system has three inputs (HALL1, HALL2, HALL3) and one output (DIR - '1' for clockwise and '0' for counterclockwise direction). The problem is, that I don't have access to any external clock signal with I could synchronize the work of state machine and involve transitions of states. I tried to solve this problem in few ways, which finally failed:  

 

I have tried to produce synchronization signal using HALL signals - I've just put them together to XOR gate, which gave me a square wave. I wanted to make a transition between states during falling, as also rising edge of the square signal, but I got an error message: "Error (10628): VHDL error at DIR_AUT_SL.vhd(87): can't implement register for two clock edges combined with a binary operator". Actually, I've done some research in this case and found information, that is impossible to make a signal sensitive on both (rising and falling edge). 

 

And here is my question - maybe is somebody on this forum, who had some similar problem and would like to give me an advice. Maybe I should implement an asynchronous state machine, which doesn't need a clock signal? But how can I make a transition between states in such a case? I would be very grateful for any help.  

 

My VHDL code is below:  

 

library ieee ; use ieee.std_logic_1164 .all; use ieee.std_logic_signed .all; entity DIR_AUT_SL is port ( H1_SL, H2_SL, H3_SL, clock: in STD_LOGIC ; DIR_SIGNAL_1 : out STD_LOGIC ); END DIR_AUT_SL; architecture behavior of DIR_AUT_SL is type state_type is (A, B, C, D, E, F, G, H, I, J, K, L); signal y_act, y_next : state_type ; signal hall: std_logic_vector (0 to 2); begin hall <= H1_SL&H2_SL&H3_SL; process (hall, y_act) -- state table begin case y_act is when A => case hall is when "101" => y_next <= B; when "110" => y_next <= L; when others => y_next <= A; end case; when B => case hall is when "001" => y_next <= C; when "100" => y_next <= G; when others => y_next <= B; end case; when C => case hall is when "011" => y_next <= D; when "101" => y_next <= H; when others => y_next <= C; end case; when D => case hall is when "010" => y_next <= E; when "001" => y_next <= I; when others => y_next <= D; end case; when E => case hall is when "110" => y_next <= F; when "011" => y_next <= J; when others => y_next <= E; end case; when F => case hall is when "100" => y_next <= A; when "010" => y_next <= K; when others => y_next <= F; end case; when G => case hall is when "101" => y_next <= B; when "110" => y_next <= L; when others => y_next <= G; end case; when H => case hall is when "001" => y_next <= C; when "100" => y_next <= G; when others => y_next <= H; end case; when I => case hall is when "011" => y_next <= D; when "101" => y_next <= H; when others => y_next <= I; end case; when J => case hall is when "010" => y_next <= E; when "001" => y_next <= I; when others => y_next <= J; end case; when K => case hall is when "110" => y_next <= F; when "011" => y_next <= J; when others => y_next <= K; end case; when L => case hall is when "100" => y_next <= A; when "010" => y_next <= K; when others => y_next <= L; end case; when others => y_act <= A; end case ; end process ; -- state_table process (clock) begin if (rising_edge(clock) OR falling_edge (clock)) then y_act <= y_next ; end if; end process ; process ( y_act ) -- output states begin case y_act is when A => DIR_SIGNAL_1 <= '1'; when B => DIR_SIGNAL_1 <= '1'; when C => DIR_SIGNAL_1 <= '1'; when D => DIR_SIGNAL_1 <= '1'; when E => DIR_SIGNAL_1 <= '1'; when F => DIR_SIGNAL_1 <= '1'; when G => DIR_SIGNAL_1 <= '0'; when H => DIR_SIGNAL_1 <= '0'; when I => DIR_SIGNAL_1 <= '0'; when J => DIR_SIGNAL_1 <= '0'; when K => DIR_SIGNAL_1 <= '0'; when L => DIR_SIGNAL_1 <= '0'; end case ; end process ; -- output states end behavior ;
0 Kudos
12 Replies
Altera_Forum
Honored Contributor II
3,071 Views

You can't infer a register with two edges. 

I wouldn't advice you to go without clock.  

You need a faster clock that can cover both edge of your square signal. Then you can use the rise/fall of your square signal as clock enable.
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

Yes, I understand - but how can I make my square signal twice faster in order to use it as clock enable? I need to add, that I have only access to 3 inputs (3 hall signals).

0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

 

--- Quote Start ---  

Yes, I understand - but how can I make my square signal twice faster in order to use it as clock enable? I need to add, that I have only access to 3 inputs (3 hall signals). 

--- Quote End ---  

 

 

isn't your clock input fast enough. then you can enable a clocked register on your squre signal edges.
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

I did as you wrote and created register - code is below 

 

library ieee ; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; ENTITY CLK_REG IS port (clk, reset : IN STD_LOGIC; q1, q2 : OUT STD_LOGIC ); END CLK_REG; ARCHITECTURE arch9 OF CLK_REG IS BEGIN -- Register with active-high clock PROCESS (clk, reset) BEGIN IF reset = '0' THEN q1 <= '0'; ELSIF clk'EVENT AND clk = '1' THEN q1 <= '1'; END IF; END PROCESS; -- Register with active-low clock PROCESS (clk, reset) BEGIN IF reset = '1' THEN q2 <= '0'; ELSIF clk'EVENT AND clk = '0' THEN q2 <= '1'; END IF; END PROCESS; END arch9;  

 

 

I enabled this by clock created from hall signals and expected to get on my outputs: q1 = 1, and q2 = 0 when clock = 1; q1 = 0, and q2 = 1 when clock = 0; 

And this part works. Then I changed a synchronous part of my state machine as below:  

 

process (q1, q2) begin if (q1 = '0' and q2 = '0') then y_act <= A; elsif (q2 = '1' and q1 = '0' ) then y_act <= y_next; elsif (q1 = '1' and q2 = '0') then y_act <= y_next; end if; end process ;  

 

Unfortunatelly this part doesn't work at all. It changes all the time states only between A and B. Can you tell what mistake I do in this case?
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

your above logic will simply set q1 to 1 and q2 to 1 for ever once a clock edge arrives (assuming reset applied once). 

 

What you need is a proper clock signal and not one gated from xoring HALL1/HALL2/HALL3. 

your clock signal could be just fast enough to sample the HLL signals as below.  

Without clock you cannot design safely. 

Once yu have clock independent of HALL signals then you sample to detect rising/falling edge of your original square signal as follows: 

 

process begin if rising_edge(clk) then sq_d <= square; if square = '1' and sq_d = '0' then -- this is now clk enable --do whatever at this edge end if; if square = '0' and sq_d = '1' then -- another clk enable -- do whatever for falling edge end if; end if; end process;
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

Thank you for your answer. So, if I good understand - without external clock signal I can not deal with this task?

0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

 

--- Quote Start ---  

Thank you for your answer. So, if I good understand - without external clock signal I can not deal with this task? 

--- Quote End ---  

 

 

FPGA design is based on clk. However in some cases one can do without it (as did old digital engineers) provided you are really skilled in asynchronous design, I am not and so are most of fpga designers.  

Is't that difficult to get clock signal? designing asynchronously will be more difficult than getting a clk on board. At the end it might be just possible if your design is simple and accepts delay variations.
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

I would like to renew this topic. After some time, I decided to design an asynchronous state machine. Code is below: 

 

library ieee ; use ieee.std_logic_1164 .all; use ieee.std_logic_signed .all; entity DIR_AUT is port ( H1_SL, H2_SL, H3_SL: in STD_LOGIC ; DIR_SIGNAL : out bit; count : out STD_LOGIC_VECTOR (2 downto 0)); END DIR_AUT; architecture behavior of DIR_AUT is type state_type is (A, B, C, D, E, F); signal y_act : state_type; signal hall: std_logic_vector (0 to 2); begin hall <= H1_SL&H2_SL&H3_SL; process (hall, y_act) -- state table begin case hall is when "100" => if (y_act = B) then DIR_SIGNAL <= '1'; y_act <= A; elsif (y_act = F) then DIR_SIGNAL <= '0'; y_act <= A; else y_act <= A; end if; when "101" => if (y_act = C) then DIR_SIGNAL <= '1'; y_act <= B; elsif (y_act = A) then DIR_SIGNAL <= '0'; y_act <= B; else y_act <= B; end if; when "001" => if (y_act = D) then DIR_SIGNAL <= '1'; y_act <= C; elsif (y_act = B) then DIR_SIGNAL <= '0'; y_act <= C; else y_act <= C; end if; when "011" => if (y_act = E) then DIR_SIGNAL <= '1'; y_act <= D; elsif (y_act = C) then DIR_SIGNAL <= '0'; y_act <= D; else y_act <= D; end if; when "010" => if (y_act = F) then DIR_SIGNAL <= '1'; y_act <= E; elsif (y_act = D) then DIR_SIGNAL <= '0'; y_act <= E; else y_act <= E; end if; when "110" => if (y_act = A) then DIR_SIGNAL <= '1'; y_act <= F; elsif (y_act = E) then DIR_SIGNAL <= '0'; y_act <= F; else y_act <= F; end if; when others => y_act <= A; end case ; end process ; -- state_table with y_act select count <= "000" when A, "001" when B, "010" when C, "011" when D, "100" when E, "101" when F, "111" when others; end behavior ;  

 

I used additional count output as a help just see in every moment what is the actual state of FSM. So, transitions between states seems to be really well, bu the problem now is, taht the output DIR_SIGNAL doesn't change and during whole simulation is on the same level. I really can not find a mistake in above code. I would be really grateful, if you know where can be a problem.
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

Where is your testbench? 

 

Have you also considered Kaz's comment that most FPGA designs are synchronous guys as that is how FPGAs are designed. You're unlikely to get Async help on this board. 

 

Why have you not used a clock?
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

 

--- Quote Start ---  

Where is your testbench? 

 

Have you also considered Kaz's comment that most FPGA designs are synchronous guys as that is how FPGAs are designed. You're unlikely to get Async help on this board. 

 

Why have you not used a clock? 

--- Quote End ---  

 

 

 

The board, what I work with is self-built controller for BLDC motor, where Altera was prepared to do only combinational functions (CLK pins are not connected). I would like to implement additional feature in Altera without interference in hardware of this system - this is the reason, why I want to do this in asynchronous mode.  

 

Results of simulation are below.  

https://www.alteraforum.com/forum/attachment.php?attachmentid=8337  

 

So, during first 30 ns DIR_SIGNAL is unsigned and this is correct. From 30 ns until 180 ns DIR_SIGNAL is 0 and this is also correct, because for clockwise direction this output should be 0. The problem is, that during changing direction of the motor (after 180 ns) the output DIR_SIGNAL doesn't change from 0 to 1 and I really don't understand why, because as you can see on 'count' output the transitions between states are good.
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

Have you checked the netlists to see if the logic it has created is as you expected? 

 

You didnt show your testbench.
0 Kudos
Altera_Forum
Honored Contributor II
3,071 Views

In my simulation(ModelSim) the output DIR_SIGNAL changes from 0 to 1 repeatedly. I used the three inputs set as clock patterns with periods 100,1000,2000

0 Kudos
Reply