State Machine with VHDL for UA(R)T - vhdl

I am trying to create a state machine in vhdl for UA(R)T (Only the sending portion).
I am having an issue with the flow of the program. I know the buad rate portion does not work at the moment. I am trying to get it working with just a clock at the moment, and then will implement the baud rate divider.
When I run it through my test bench (nothing complicated, just assign a couple of initial values reset = 1 for x time, din = z, baud = y, etc), nothing happens. My output txd stays at the initial '1' value that is set in the reset stage and if I set it to '0' it will stay like that for the cycles.
My issue that I had when designing the state machine is the it has two values that it will transition on BUT not in ever state.
Basically, what it is supposed to do is:
reset: txd = 1, count = 1, busy = 0, we = 0
idle: when busy = 1 set shift = init values
wait: transition on next clock signal
trans: if count < 9, txd = shift(0), and shift shift
if count = 9, busy = 0, count = 0
and back to idle
I think my issue is somehow related to the busy signal not being properly set.
-- Universal Asynch Receiver Transmitter
---------------------
library ieee;
use ieee.std_logic_1164.all;
entity eds_uart is
generic (width : positive := 16);
port ( clk,reset: in std_logic ;
din_wen: buffer std_logic; -- state machine sets value thus buffer needed
brd : in std_logic_vector(23 downto 0); -- buad rate dividor
din : in std_logic_vector(7 downto 0); -- input value
txd: out std_logic; -- sent data bit
tx_busy : buffer std_logic -- sent data bit active
);
end entity eds_uart;
architecture behaviour of eds_uart is
type state_type is (idle_s, wait_s, transmit_s); -- three possible states of uat
signal current_s: state_type;
signal tick: std_logic; -- baud rate clock
signal count: integer := 0; -- count number of characters sent
signal shift: std_logic_vector(9 downto 0); -- intermediate vector to be shifted
begin
-- assign tick value based on baud rate
-- need to implement divisor
process(clk, brd) begin
tick <= clk;
end process;
process(tick, reset, din) begin
if (reset = '1') then
current_s <= idle_s; -- default state
count <= 0; -- reset character counter
txd <= '1';
tx_busy <= '0';
din_wen <= '0'; -- able to start sending
elsif (current_s = idle_s and din_wen = '1') then -- transition when write enable is high
current_s <= wait_s; -- transition
tx_busy <= '1';
shift <= '1' & din & '0'; -- init shift value
elsif (current_s = wait_s and rising_edge(tick)) then -- transition on clock signal
current_s <= transmit_s;
elsif (current_s = transmit_s and rising_edge(tick)) then -- test transition on clock signal
if (count < 9) then
txd <= shift(0); -- output value
shift <= '0' & shift(9 downto 1); -- shift to next value
count <= count + 1; -- increment counter
current_s <= transmit_s; -- dont change state
elsif (count = 9) then
txd <= shift(0); -- send last element
count <= 0;
tx_busy <= '0'; -- reset busy signal
current_s <= idle_s; -- start process again
end if;
end if;
end process;
end architecture behaviour ;

The comments:
-- state machine sets value thus buffer needed
and
-- transition when write enable is high
suggest that you may be expecting to have an additional external driver for din_wen. If that is the case the buffer mode is not doing you any good as it only exposes the value of the internal driver of din_wen which is only ever driving '0'. Post VHDL-2002, buffer is effectively a fancy, readable version of out without the limitations from earlier standards. It does not implement an input port. More significantly, it does not let you see the external resolved value if you have additional signal driver(s) outside this entity.
It isn't clear why you even need to drive din_wen internally since it is intended to be a control input that causes the transition into the wait_s state. Consider changing it to an in port mode and removing the reset assignment.
Style note: You are courting danger with the mixture of synchronous and asynchronous logic described here. You should stick to the pattern of having a single call to rising_edge() in a top level if block that wraps all of your synchronous logic.

Related

How do I correctly implement a Finite-State Machine into VHDL without taking in multiple inputs from Basysy3 FPGA

I am new to VHDL and I am attempting to implement the following state machine into VHDL (state diagram provided below). When I press a button on my Basys3 FPGA board( P input) the output is a random state. I suspect this is because the clock is going through many cycles during a single press so more than 1 input is being taken in from a single press but I am unsure. Is there anything I can do to fix this. I want to be able to press button P and the states change one at a time.
library IEEE;
USE ieee.std_logic_1164.all;
ENTITY trasher is
PORT (
clock : IN STD_LOGIC;
P : IN STD_LOGIC;
reset : IN STD_LOGIC;
LED3, LED1,LED2,LED0 : OUT STD_LOGIC);
END ENTITY;
-- Architecture definition for the SimpleFSM entity
Architecture RTL of trasher is
TYPE State_type IS (A, B, C, D); -- Define the states
SIGNAL State : State_Type; -- Create a signal that uses
-- the different states
BEGIN
PROCESS (clock, reset)
BEGIN
IF (reset = '1') THEN -- upon reset, set the state to A
State <= A;
ELSIF rising_edge(clock) THEN -- if there is a rising edge of the
-- clock, then do the stuff below
-- The CASE statement checks the value of the State variable,
-- and based on the value and any other control signals, changes
-- to a new state.
CASE State IS
-- If the current state is A and P is set to 1, then the
-- next state is B
WHEN A =>
IF P='1' THEN
State <= B;
END IF;
-- If the current state is B and P is set to 1, then the
-- next state is C
WHEN B =>
IF P='1' THEN
State <= C;
END IF;
-- If the current state is C and P is set to 1, then the
-- next state is D
WHEN C =>
IF P='1' THEN
State <= D;
END IF;
-- If the current state is D and P is set to 1, then the
-- next state is B.
-- If the current state is D and P is set to 0, then the
-- next state is A.
WHEN D=>
IF P='1' THEN
State <= B;
ELSE
State <= A;
END IF;
WHEN others =>
State <= A;
END CASE;
END IF;
END PROCESS;
-- Decode the current state to create the output
-- if the current state is D, R is 1 otherwise R is 0
LED0 <= '1' WHEN State=A ELSE '0';
LED1 <= '1' WHEN State=B ELSE '0';
LED2 <= '1' WHEN State=C ELSE '0';
LED3 <= '1' WHEN State=D ELSE '0';
END rtl;
Do not use directly the input from your press-button. What you need to feed your state machine is the output of a rising edge detector of P, not P itself.
Moreover P is not synchronous with your master clock and there is thus a risk of meta-stability. Last but not least, if it bounces, you will get several value changes instead of just one. To solve the meta-stability issue you need a re-synchronizer, which is just a shift register. And you can also use it to generate an intermediate signal that is asserted high during only one clock period when the button is pressed, that is, the rising edge detector you need for your state machine. Example with 3-stages:
signal sync: std_ulogic_vector(0 to 2);
signal button_pressed: std_ulogic;
...
process(clock, reset)
begin
if reset = '1' then
sync <= (others => '0');
elsif rising_edge(clock) then
sync <= P & sync(0 to 1);
end if;
end process;
button_pressed <= sync(1) and (not sync(2));
Stages 1 and 2 of sync are safe to use because they have already been resynchronized (assuming 2 stages are enough for your target technology and mean time between failures; read something about meta-stability, maybe, if you don't understand this).
When the button is pressed, ones are shifted in sync. After two clock periods sync = "110" so button_pressed is asserted high. One clock period later sync = "111" and button_pressed is de-asserted. button_pressed is thus a one-clock-period-only indicator that the button was pressed. You can use it as an input of your state machine.
The second problem comes from the way press-buttons work. If your prototyping board does not already debounce its press-buttons it can be that, when the button is pressed, your P input oscillates several times between 0 and 1 before stabilizing to 1. Same when the button is released. As this is sometimes not the case do some tests before implementing a debouncer. For instance, count the number of times button_pressed is asserted high and send this to your LEDs:
signal cnt: u_unsigned(3 downto 0);
...
process(clock, reset)
begin
if reset = '1' then
cnt <= (others => '0');
elsif rising_edge(clock) then
cnt <= cnt + button_pressed;
end if;
end process;
LED0 <= std_logic(cnt(0));
LED1 <= std_logic(cnt(1));
LED2 <= std_logic(cnt(2));
LED3 <= std_logic(cnt(3));
If your button bounces you should sometimes see more than one increment when you press it. It will be time to search a bit about debouncing and, if needed, to ask a new question.

VHDL finite state machine counter with start

i pretty new of vhdl and i'm trying to learn how to do a FSM with vhdl.
At moment i need a code that after a fixed count value, it give me back a pulse, in order to start a second FSM block. (I have a recurring signal every 100 kHz, i need to count it and release this signal after a fixed number of counts).
Actually it work as free run, every time that it see this signal, it start to count, but realy i want to add a "start" signal, so it must start to count this signal after it see this start signal.
at moment my working code is:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity counter is
Port (
signal_in : in STD_LOGIC := '0'; --segnale di start
clk : in STD_LOGIC; --clock di ingresso
reset : in STD_LOGIC; --ff reset
signal_out: out STD_LOGIC; --gate in uscita
count_val: in std_logic_vector (7 downto 0);
start : in STD_LOGIC := '0'
);
end counter;
architecture behavioral of counter is
type state_type is (idle, count_up);
signal state : state_type;
begin
process (reset, clk, signal_in, start)
variable index : integer :=0;
variable countlen: integer;
variable count_v: std_logic;
variable countlen2 : std_logic;
begin
countlen := to_integer(unsigned(count_val))-1;
if reset = '1' then
count_v := '0';
index := 0;
state <= idle;
else
--if start = '1' and
--if rising_edge(clk) then
if rising_edge(signal_in) then
case state is
when idle =>
count_v :='0';
index := 0;
if (signal_in = '1') then
state <= count_up;
else
state <= idle;
end if;
when count_up =>
if(index < countlen) then
state <=count_up;
index := index + 1;
elsif
index = countlen then
count_v := '1';
state <=idle;
end if;
when others => null;
end case;
end if;
end if;
signal_out <= count_v;
end process;
end Behavioral;
Any attempt to work with cose with "start = 1" will stop the count.
Please some one have some suggestion?
Kind REgards
Fulvio
Welcome om StackOverflow. Your specification is not 100% clear. What difference do you make between signal_in and start? According to your code and to your explanations, they both seem to act as a starter.
Moreover, there are several strange things with your code:
your process seems to be a synchronous one, with asynchronous reset. Its sensitivity list should contain only the clock and the reset. And its body should be:
process(clk, reset)
<variable declarations>
begin
<NOTHING HERE>
if reset = '1' then
<reset code>
elsif rising_edge(clk) then
<regular code>
end if;
<NOTHING HERE>
end process;
you are using signal_in as a clock and as a logic signal. This is extremely strange. Moreover, your if (signal_in = '1') then is always true (in the synthesis semantics) and thus useless.
You are initializing variables at declaration (index). This is not supported by some synthesizers and hardware targets. Moreover, even when supported, it works only at power up. If:
you intend to synthesize your code,
you want it to be portable across synthesizers and hardware targets,
you want to re-initialize signal and variables not only at power up but also when a reset input is asserted,
prefer a real explicit reset, instead, and guarantee that it is always asserted after power up (or at the beginning of a simulation) for proper first initialization.
you declare variable index with a full integer range, that is, 32 bits minimum, while 8 bits would suffice. This is a potential waste of hardware resources.
It is difficult to propose a solution without a clear and complete specification but assuming you want to count only after start has been asserted and only when signal_in is asserted, the following may be a starting point:
process (clk, reset)
variable index: natural range 0 to 255;
begin
if reset = '1' then
state <= idle;
signal_out <= '0';
index := 0;
elsif rising_edge(clk) then
case state is
when idle =>
signal_out <= '0';
index := 0;
if start = '1' then
state <= count_up;
end if;
when others =>
if signal_in = '1' then
if index = to_integer(unsigned(count_val)) - 1 then
state <= idle;
signal_out <= '1';
else
index := index + 1;
end if;
end if;
end case;
end if;
end process;
Note that this is really synchronous of your clock clk. I suspect that you made a very common mistake: as you wanted to increment your counter when signal_in is asserted you decided more or less to use signal_in as a clock. This is not a real synchronous and safe design. In a real safe synchronous design you do not use logic signals as clocks. You have well identified clocks and you use only these as clocks. In your case there is one single clock: clk. If you want to do something synchronously when a logic signal is asserted, wait for the rising edge of your clock and then test the logic signal and take appropriate actions.
thanks for your support.
Yes the point is that i need to "decimate" (or count) a signal.
This signal had a width of 50-100ns and it repeat itself with a frequency of 100 kHz.
so in my mind, this signal will go in to "signal in". My FPGA is an Actel proasic3 with a clock of 40 MHz.
In my setup this signal will be always on, but i don't want that my FSM will start to count as it see the first "signal in" but only when i send a "start" signal for the number of count that i indicate. (Realy they ask to me the possibility to decimate this signal up to 65000 count, so for sure i need to use a 16bit vector instead of 8bit).
The async reset is here "just in case" i need to reset the whole fsm in the middle of some data record.
Hope to be more clear now what this code should do.
For Old fart, yes indeed all my signal coming outside the fpga will be first synchronized with a simple 2 ff synchronizer with the FPGA clock

Is the use of rising_edge on non-clock signal bad practice? Are there alternatives?

I am working on a VHDL design and I have it working, but the code is pretty ugly and the fact that it seems that I am trying to work around the language's design to accomplish my goal makes me feel like something is wrong. I'm pretty new to VHDL, but I have been working on smaller chunks of the project for nearly a month so I have the general idea. However, This part is a bit more complex.
I need a process that will create a one clock period long pulse (LOAD_PULSE) after the rising edge of a signal (END_ADC), but not until 4 clocks has passed from the latest rising edge of that signal (END_ADC) OR the falling edge of a second signal (LVAL).
To accomplish the wait period, I have built a timer module that counts microseconds and periods, here:
entity uS_generator is
generic(
Frequency : integer := 66 -- Frequency in MHz
);
Port (
CLK : in STD_LOGIC;
RESET : in STD_LOGIC;
T_CNT : out integer range Frequency downto 1 := 1;
uS_CNT : out integer range 65535 downto 0 := 0
);
end uS_generator;
architecture behavior of uS_generator is
signal T_CNT_INT : integer range Frequency downto 1 := 1; -- Counter for 1 uS
signal uS_CNT_INT : integer range 65535 downto 0 := 0;
begin
COUNT: process(CLK, RESET)
begin
if RESET = '1' then
T_CNT_INT <= 1;
uS_CNT_INT <= 0;
elsif rising_edge(CLK) then
if T_CNT_INT = (Frequency - 1) then -- Increment one clock early so last rising edge sees one uS elapsed.
uS_CNT_INT <= uS_CNT_INT + 1;
T_CNT_INT <= T_CNT_INT + 1;
if uS_CNT_INT = 65535 then
uS_CNT_INT <= 0;
end if;
elsif T_CNT_INT = Frequency then
T_CNT_INT <= 1;
else
T_CNT_INT <= T_CNT_INT + 1;
end if;
end if;
end process COUNT;
T_CNT <= T_CNT_INT;
uS_CNT <= uS_CNT_INT;
end behavior;
The processes I'm using for the pulse generation portion of the design are as follows:
loadPulseProc: process(PIXEL_CLK, END_ADC, RESET)
begin
if RESET = '1' then
PULSE_FLAG <= '0';
LOAD_PULSE <= '0';
elsif rising_edge(END_ADC) then
PULSE_FLAG <= '1';
end if;
if rising_edge(PIXEL_CLK) then
if PULSE_FLAG = '1' and END_ADC = '1' and LVAL <= '0' and ADC_TMR_T >= 4 and LVAL_TMR_T >= 4 then
LOAD_PULSE <= '1', '0' after PIXEL_CLK_T;
PULSE_FLAG <= '0';
end if;
end if;
end process loadPulseProc;
ADCTimerProc: process(END_ADC, RESET)
begin
if RESET = '1' then
ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if rising_edge(END_ADC) then
ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if falling_edge(END_ADC) then
ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
end process ADCTimerProc;
LVALTimerProc: process(LVAL, RESET)
begin
if RESET = '1' then
LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if rising_edge(LVAL) then
LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if falling_edge(LVAL) then
LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
end process LVALTimerProc;
PIXEL_CLK_T is the period of the clock, 15.152 ns.
This design works, simulation shows that it does as I require, but only after significant hassle avoiding errors due to using multiple rising_edge of falling_edge calls by separating them into separate if statements that really should be together. As far as I've read using rising_edge and falling_edge seems to be reserved for clocks only, so is this just bad practice? How can avoid this behavior but still create the same output?
Thanks!
Yes, rising_edge()/falling_edge() should only be used for clock signal. While it works in simulation it can cause problems and unintended hardware in synthesis.
Synthesis tools infer a clock from the function's argument and place such signals/wires on special tracks in the FPGAs (assuming you are targeting an FPGA for your design). The tool will further infer special clock buffers and warn if your input clock pin is not a clock capable pin.
Introducing several clocks can lead to asynchronous designs and make it vulnerable for cross clock faults.
Detecting a rising or falling edge on a signal is done by an edge detection circuit like the following which compares the signal in the previous clock cycle to the current value.
Needed signals:
signal mySignal_d : std_logic := '0';
signal mySignal_re : std_logic;
Needed logic:
mySignal_d <= mySignal when rising_edge(Clock);
mySignal_re <= not mySignal_d and mySignal;
This first line translates to an 1-bit D-flipflop (You could also use a process). The second lines generates a one cycle strobe signal when mySignal changes from low to high. I'm using *_d to indicate a delayed signal of the original input and *_re for rising edge.
The generated signal is still synchronous to Clock.

VHDL code behaves abnormally after synthesis (I2C)

First of all, because of company disclosure agreement I am not allowed to post my code thus I will describe the symptoms of the behavior and hopefully it's enough.
I am using the IP for I2C master provided by Scott Larson on eewiki and I use it the same way in the example provided on the page. The difference is that I have several procedures as described in the example
WHEN get_data => --state for conducting this transaction
busy_prev <= i2c_busy; --capture the value of the previous i2c busy signal
IF(busy_prev = '0' AND i2c_busy = '1') THEN --i2c busy just went high
busy_cnt := busy_cnt + 1; --counts the times busy has gone from low to high during transaction
END IF;
CASE busy_cnt IS --busy_cnt keeps track of which command we are on
WHEN 0 => --no command latched in yet
i2c_ena <= '1'; --initiate the transaction
i2c_addr <= slave_addr; --set the address of the slave
i2c_rw <= '0'; --command 1 is a write
i2c_data_wr <= data_to_write; --data to be written
WHEN 1 => --1st busy high: command 1 latched, okay to issue command 2
i2c_rw <= '1'; --command 2 is a read (addr stays the same)
WHEN 2 => --2nd busy high: command 2 latched, okay to issue command 3
i2c_rw <= '0'; --command 3 is a write
i2c_data_wr <= new_data_to_write; --data to be written
IF(i2c_busy = '0') THEN --indicates data read in command 2 is ready
data(15 DOWNTO 8) <= i2c_data_rd; --retrieve data from command 2
END IF;
WHEN 3 => --3rd busy high: command 3 latched, okay to issue command 4
i2c_rw <= '1'; --command 4 is read (addr stays the same)
WHEN 4 => --4th busy high: command 4 latched, ready to stop
i2c_ena <= '0'; --deassert enable to stop transaction after command 4
IF(i2c_busy = '0') THEN --indicates data read in command 4 is ready
data(7 DOWNTO 0) <= i2c_data_rd; --retrieve data from command 4
busy_cnt := 0; --reset busy_cnt for next transaction
state <= home; --transaction complete, go to next state in design
END IF;
WHEN OTHERS => NULL;
END CASE;
For example at the end if the get_data instead of going to home I go to an initializing case to reset busy_cnt and i2c_ena and other signals then to another case for writing similar to get_data.
Current Situation
The code executes well in simulation, I switch the i2c_busy on and off and the behavior is as expected.
There are no warnings regarding the sensitivity list or any latches. I have a warning that 5 clock signals were routed using generic routing resource and might suffer from excessive delay and/or skew
The Problem
As I mentioned before the code is divided into several cases similar to get_data in the example above and when executing it is stuck in an infinite loop in one of them. And when I change something in the case that is stuck another case before it misbehaves and also stuck in an infinite loop. Even changing a simple signal that has nothing to do with the algorithm (LED output for debugging) in one case might cause a case before it to misbehave.
The infinite loop behavior is also strange and shows state is not set at the end of the case.
Note that I am not using the same way in the example to update state rather I use a separate Process for the state update (curr_state <= next_state;) and the next_state is the one updated.
My Speculation
I assumed that the problem could be because I have to set every output in every case. But even after setting all I could the behavior was similar.
For the sake of completion: The development environment is Lattice Diamond and the FPGA is MachXO2.
The posted code snippet has severe problems, if it's not part of a clocked process anymore according to the comments:
Me: Is the posted code still part of a clocked process?
mmahdich: #Martin In my code it's not, the clocked process only updates the curr_state <= next_state
If I embed the code from the question into the following test architecture, then the synthesis compiler XST (from ISE 14.7) reports warnings about latches for the signals busy_cnt, busy_prev and data. The reason that the OP observes no latch warnings may result from further optimizations or interference from the undisclosed code parts. (I have no Lattice Diamond at hand.)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity i2c_test is
port (
clk : in std_logic;
i2c_busy : in std_logic;
slave_addr : in std_logic;
data_to_write : in std_logic_vector(7 downto 0);
new_data_to_write : in std_logic_vector(7 downto 0);
i2c_data_rd : in std_logic_vector(7 downto 0);
i2c_ena : out std_logic;
i2c_addr : out std_logic;
i2c_rw : out std_logic;
i2c_data_wr : out std_logic_vector(7 downto 0);
data : out std_logic_vector(15 downto 0));
end i2c_test;
architecture rtl of i2c_test is
type state_t is (get_data, home);
signal curr_state : state_t := home;
signal state : state_t; -- next state is named "state" in OP code
signal busy_prev : std_logic;
begin -- rtl
process (clk)
begin -- process
if rising_edge(clk) then
curr_state <= state;
end if;
end process;
process(curr_state, busy_prev, i2c_busy, slave_addr, data_to_write, new_data_to_write, i2c_data_rd)
variable busy_cnt : integer range 0 to 4 := 0;
begin
state <= curr_state; -- next state is named "state" in OP code
i2c_ena <= '0';
i2c_addr <= '-';
i2c_rw <= '-';
i2c_data_wr <= (others => '-');
-- no default assignments for busy_prev and data here, because the usage
-- below indicates that a register was intended
case curr_state is
when home => state <= get_data;
---------------------------------------------------------------
-- Add code from question here
---------------------------------------------------------------
end case;
end process;
end rtl;
First of all, the signal for the next state seems to be named state.
Then, XST founds latches for the signals busy_prev and data. I have not added default assignments for these signals in the combinational process because the following assignments in the OP's code indicate that a register was intended:
busy_prev <= i2c_busy; --capture the value of the previous i2c busy signal
data(15 DOWNTO 8) <= i2c_data_rd; --retrieve data from command 2
data(7 DOWNTO 0) <= i2c_data_rd; --retrieve data from command 4
Finally, one cannot (easily) implement this wait counter without a clocked process:
WHEN get_data => --state for conducting this transaction
IF(busy_prev = '0' AND i2c_busy = '1') THEN --i2c busy just went high
busy_cnt := busy_cnt + 1; --counts the times busy has gone from low to high during transaction
END IF;
EDIT
Synthesizing the above would require flip-flops for busy_cnt which is triggered by all signals listed in the process sensitivity list. Of course, a new state will be loaded into the flip-flops only if the condition (curr_state = get_data and busy_prev = '0' and i2c_busy = '1') is true. For example, XST synthesizes a latch for this, which is enabled when the condition is true. But then, busy_cnt forms a combinational loop during an enabled latch. This synthesized behaviour does not match the VHDL description.
The solution would be to implement the registers busy_prev, data and busy_cnt in the clocked process.

Count Edges over specific Period of Time in VHDL

For speed measurement of an electric motor I would like to count the amount of rising and falling edges of an encoder-input in a time-interval of 10ms.
To do this I have implementet a clock divider for my 40 MHz Clock as follows:
entity SpeedCLK is
Port ( CLK : in STD_LOGIC;
CLKspeed : out STD_LOGIC);
end SpeedCLK;
architecture Behavioral of SpeedCLK is
signal CounterCLK : NATURAL range 0 to 400001;
begin
SpeedCounter : process
begin
wait until rising_edge(CLK);
CounterCLK <= CounterCLK + 1;
if CounterCLK < 400000 then
CLKspeed <= '0';
else
CLKspeed <= '1';
CounterCLK <= 0;
end if;
end process SpeedCounter;
end Behavioral;
This should make CLKSpeed '1' every 10 ms. I use this block as a component in my Toplevel VHDL-Module. In the next Block I count the Edges from my encoderinput(QEPA) with a shift register to debounce the Input Signal.
entity SpeedMeasure is
Port (
QEPA : in STD_LOGIC;
CLK : in STD_LOGIC;
CLKSpeed : in STD_LOGIC;
Speed : OUT INTEGER -- in rpm
);
end SpeedMeasure;
architecture Behavioral of SpeedMeasure is
begin
Edges : process(CLKSpeed, CLK)
variable detect : STD_LOGIC_VECTOR(5 downto 0) := "000000";
variable EdgesPerTime : INTEGER := 0;
variable CountQEPA : INTEGER := 0;
begin
if CLKSpeed = '1' then
EdgesPerTime := countQEPA;
countQEPA := 0;
ELSIF (CLK'EVENT AND CLK = '1') THEN
detect(5 downto 1) := detect(4 downto 0);
detect(0) := QEPA;
if (detect = "011111") OR (detect = "100000") then
countQEPA := countQEPA + 1;
else
countQEPA := countQEPA;
end if;
end if;
Speed <= EdgesPerTime;
end process Edges;
end Behavioral;
This should write the current value of CountQEPA in my variable edgesPerTime every 10 ms and reset the Counter afterwards.
The signal Speed gets transmitted via uart. Unfortunatly with the reset of CountQEPA every 10ms I receive a constant value of 0 for EdgesPerTime. If I remove the reset line in the code, I can receive an increasing value for EdgesPerTime until the largest number for Integer (2^16) is reached, at which Point the Counter resets to 0.
What is the correct implementation in VHDL to count rising and falling edges in a set period of time?
Any help is greatly apreciated as I am still very new to vhdl.
You're building a latch using a variable. Your synthesis tool inferred an asynchronous reset CLKSpeed for countQEPA and since your latch EdgesPerTime latches countQEPA when its write enable CLKSpeed is asserted, you only see the reset countQEPA value of 0.
You should build proper synchronous logic:
signal CountQEPA : integer := 0;
signal detect : std_logic_vector(5 downto 0) := (others => '0');
begin
edge_cnt_p : process (
CLK
)
begin
if (rising_edge(CLK)) then
-- synchronous reset
if (CLKSpeed = '1') then
countQEPA <= 0;
elsif ((detect = "011111") or (detect = "100000")) then
countQEPA <= countQEPA + 1;
end if;
end if;
end process edge_cnt_p;
edge_debounce_p : process (
CLK
)
begin
if (rising_edge(CLK)) then
detect <= detect(detect'left downto 1) & QEPA;
end if;
end process edge_debounce_p;
count_register_p : process (
CLK
)
begin
if (rising_edge(CLK)) then
-- synchronous write enable
if (CLKSpeed = '1') then
Speed <= countQEPA;
end if;
end if;
end process count_register_p;
I'm not a big fan of variables, but it seems synthesis tools got a lot smarter these days. As you can see, I made three separate processes to show what we actually want going on. CountQEPA and debounce are signals now, because they need to be readable from other processes.
I assume CLKSpeed is synchronous to CLK (40 MHz). If it isn't, then you should think about handshaking between the clock domains.
You can of course make a single process out of these individual processes. In general, I try to avoid variables, because they can easily be used to describe behavior that is not synthesizable, like you found out the hard way.
I'm not sure how long your encoder bounces, but if you do sample at 40 MHz, a 6 bit shift register will likely not work as that's only a 125 ns debounce (you use the lower 5 bits only for debouncing, the top bit for noticing state changes).
Speaking of your debouncer. Consider the following case:
debounce QEPA
111111 1
111111 0 <-- glitch/bounce on encoder line; 25 ns wide
111110 1
111101 1
111011 1
110111 1
101111 1
011111 1 <-- fake edge detected
That's probably not what you want. You should compare your debounced signal to the last stable state instead of assuming state'delayed(5 * clk_period) being a stable state.
As I said above, I'm assuming CLK is your 40 MHz clock. You needn't sample your encoder signal that fast, because a proper debouncer would take a large number of shift register bits at no added value to you, because you have to divide that clock down to 1 kHz anyway for your time-slot counting.
Instead, take into account the maximum frequency of your encoder signal. You would want to oversample that at least by double that frequency, quadruple that frequency to be safe. So you have four samples per "bit time".
Since you're expecting many edges at 1 kHz, I assume your encoder is at least two orders of magnitude fast, i.e. 100 kHz. So scale 40 Mhz down to 400 kHz and shift in QEPA for debouncing. Sample these 400 kHz down to 1 kHz for your time slot measurements.
On a side note: What kind of motor encoding only uses a single bit? Are you sure you're not dealing with a quadrature encoder?

Resources