How to implement time delay into Verilog FSM - time

always #(posedge clock)
case(state)
`STATE0: begin
state <= `STATE1;
// Code here
// Wait 5ms before advancing
end
`STATE1: begin
state <= `STATE2;
// Code here
// Wait 5ns before advancing
end
`STATE2: begin
state <= `STATE0;
// Code here
// Wait 5s before advancing
end
default:begin
state <= `STATE0;
// Code here
end
endcase
end
Is it possible to add wait statements into the design where it must wait x amount of time units before it can proceed to the next state?
I know it can be manually done in my testbench using # but my design requires that there needs to be a certain wait time before I can proceed.

For short delays (a few clock cycles), it might be easiest to implement a few "dummy" states as intermediaries between the intended states.
For longer delays, use a counter as the enable signal to transfer between the states:
reg [31:0] count;
always#(posedge clock)
if (SOME RESET) count <=0;
else count <= count + 1;
always #(posedge clock)
//...
STATE_N: if (count == SOME_NUMBER_OF_CYCLES) state <= STATE_NPLUSONE;
else state <= STATE_N;

Related

how to delay a signal for several clock cycles in vhdl

I'm trying to delay a signal for five clock cycles..
process (read_clk)
begin
if (rising_edge(read_clk)) then
rd_delay <= rd_en;
end if;
end process;
delay3 <= not(rd_en) and rd_delay;
By edge detecting technique,this will give me a one clock cycle delay, but i need five clock cycles.
Thank you all.
The slightly more elegant version of Matthew's proposal could be, for instance:
constant dn: positive := 5;
signal delay: std_ulogic_vector(0 to dn - 1);
...
process (read_clk)
begin
if rising_edge(read_clk) then
delay <= rd_en & delay(0 to dn - 2);
end if;
end process;
rd_en_d5 <= delay(dn - 1);
Your signal delay3 is not a delayed version of the signal rd_en, it is a pulse that is '1' for one clock cycle following a falling edge on the signal rd_en.
If you simple want to delay rd_en for five clock cycles, then add 5 flip-flops:
process (read_clk)
begin
if rising_edge(read_clk) then
rd_en_d5 <= rd_en_d4;
rd_en_d4 <= rd_en_d3;
rd_en_d3 <= rd_en_d2;
rd_en_d2 <= rd_en_d1;
rd_en_d1 <= rd_en;
end if;
end process;
(Or if you have the VHDL knowledge do something a bit more elegant with an array and perhaps a for loop.)
If you then want to detect a falling edge as well, then go ahead and use something similar to the process in your question.

Using If condition to do "something" once every 10 clock cycles. what if "something" takes more than 1 clock cycle?

I am working on some VHDL code that will be used (on an FPGA) to read in a 16 bit digital signal, do some processing, and then write out the 16 bit processed signal. Currently it is setup so it should read the input every 10 clock cycles, do some processing on the next clock cycle (it currently does nothing, just outputs the input) and then just increment the counter for the remaining 8 clock cycles.
What happens if the processing takes longer than one clock cycle to complete (Which it will), will it continue until it finishes and stop the counter incrementing until it does? Or will the counter keep incrementing in parallel while it processes the signal?
I will set it up such that the process completes before the 8 clock cycles are up (in time to be written to the output).
The pseudocode looks something like this:
Do (on rising clock edge):
if (n = 10) then
n <= 1;
Output <= ProcessedSignal;
InputSignal <= Input;
elsif (n = 1) then
n <= n + 1
Output <= Output;
-- do some signal processing here (e.g. a filter)
ProcessedSignal <= InputSignal;
else
n <= n + 1;
Output <= Output;
ProcessedSignal <= ProcessedSignal;
end if;
It all depends on how you write the code; any kind of behavior is possible. Your pseudocode is nearly valid VHDL and will do what you want if I understand you correctly. Here is a suggestion for real code: (without architecture/signal declarations, also missing reset)
process (clock)
begin
if rising_edge(clock) then
n <= n + 1; -- default assignment
if (n = 10) then
n <= 1; -- overrides default assignment
Output <= ProcessedSignal;
InputSignal <= Input;
elsif (n = 1) then
-- do some signal processing here (e.g. a filter)
ProcessedSignal <= InputSignal;
elsif (n = 2) then
-- do more processing
end if;
end if;
end process;
Note that there is no need to write a signal to itself in a clocked process, unless you want to make it explicit that the signal keeps its old value.

SPI interface works in simulation but not on actual hardware

I am trying to send multiple bytes on the SPI bus during the transmit window. Initially I am acquiring data from the flash ADC when the input pulse is high, then calculating its average and transmitting each average value sequentially on the SPI bus. I got the SPI vhdl module working, it was able to send data when I tried sending a single byte, but when I try to send more than 1 byte it just does not work. There is logic 0 on the MOSI line and the SS line is constantly high. This is the part where I try to send multiple bytes.
process(SPITrig, Clock, TX_Done, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= "0101010101010101";
end case;
end process;
process(SPIBusy, SPITrig, SPI_Clock_base, data_count, TX_Start)
begin
if falling_edge(SPITrig) then
SPIBusy <= '1';
TX_Start <= '0';
data_count <= 0;
delay_counter <= 0;
end if;
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if data_count < 3 then
if delay_counter = 128 then
TX_Start <= not TX_Start;
delay_counter <= 0;
elsif delay_counter < 128 then
delay_counter <= delay_counter + 1;
end if;
elsif data_count >= 3 then
TX_Start <= '0';
delay_counter <= 0;
SPIBusy <= '0';
end if;
end if;
if rising_edge(TX_Start) then
data_count <= data_count + 1;
end if;
end process;
It works perfectly well in simulation, but theres no output on the hardware. Need your help in finding out whats wrong.
PS: This is my first FPGA project, so my code may not be so efficient.
I have also attached the ISIM screenshot.
clickable
tx = TX Done pin
trig = TX Start ping
c1 = data count
Note: SPI transmission sequence starts when average outputs are available and it is triggered using an internal signal"SPITRig".
Take a look at the synthesis and timing (STA) warnings, since these will indicate if the synthesis tool could not implement the design to match the RTL VHDL code.
The edge condition by rising_edge(...) or falling_edge(...) should only be used on a single common clock signal, unless there is a good reason for use of multiple clock signals; and usually only rising_edge(...) is used.
In your design you have three different signal SPITrig, SPI_Clock_base, and TX_Start that work like clocks, and this is likely to give a timing violation.
As example, in the first if of the large process, the TX_Start and data_count are both updated on the falling_edge(SPITrig), and in the last if the rising_edge(TX_Start) is used to update data_count again based on current data_count value. This may work fine in simulation, but in HW you have signal propagation delay, which depends on routing and other factors that may wary for different signals, so a design construction like that is likely to give problems in implementation.
If you have a full Static Timing Analysis (STA) setup for your design, which you probably don't have for a first time FPGA project, then the STA tool will report if the timing can be meet, and a construction like the above is likely to not meet timing.
So instead, rewrite your design to use only a single clock edge, for example rising_edge(SPI_Clock_base). It is also much easier to make a correct STA timing setup for such a design, and the sensitivity list of the processes should then only contain the clock and any asynchronous reset signals, if used, like:
process (SPI_Clock_base) is
begin
if rising_edge(SPI_Clock_base) then
...
end if;
end process;
Finally, the sensitivity list of the initial process should be reduced to only contain the signals that are read in the process, since the process need only to be sensitive to the these signals. The design won't fail if more signals are included, it makes the reader wonder what is wrong; the sensitivity list or the code.
As suggested by Morten Zilmer, I made the necessary changes to synchronize everything with the Clock. following is the code and it is working. Might post a screenshot from an oscilloscope later.
process(SPITrig, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= x"0000";
end case;
end process;
SPICycler : process(delay_counter, data_count, SPITrig, SPI_Clock_base, SPIBusy)
begin
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if delay_counter < 511 then
delay_counter <= delay_counter + 1;
TX_Start <= '0';
else
delay_counter <= 0;
TX_Start <= '1';
data_count <= data_count + 1;
end if;
end if;
if rising_edge(SPI_Clock_base) then
if SPITrig = '1' then
SPIBusy <= '1';
data_count <= 0;
end if;
if data_count = 3 then
SPIBusy <= '0';
end if;
end if;
end process;

Make a signal wait until falling edge

I have this signal that should be zero until another signal Start = 0. How can I accomplish this? Here is the relevant code:
din<=0;
wait until falling_edge(start);
for i in 0 to 63 loop
wait until clk = '1' and clk'event;
if i = 0 then
Start <= '1','0' after clk_period;
end if;
if (i < 24) then
din <= 255;
elsif (i > 40) then
din <= 255;
else
din <= 0;
end if;
end loop;
wait;
I thought I could just make din = 0 until the falling edge of start but it stops at the rising edge of start. I want to start reading the din values when start =0. Before that din = 0.
Here is a pic:
EDIT: Actually I got it to start at the correct signal values but the dout value always has an intermediate value that isn't necessary. In this case its 78450. I know this has to do with the testbench code but I can't get it to just calculate the correct value at the correct time. What changes can be made to the code below to get rid of the intermediate value?
din<=0;
for i in 0 to 63 loop
wait until clk = '1' and clk'event;
if i = 0 then
Start <= '1','0' after clk_period;
elsif (i < 24) then
din <= 255;
elsif (i > 40) then
din <= 255;
else
din <= 0;
end if;
end loop;
First of all I assume (and hope) you are writing a testbench. If not, you should avoid using wait statements, as these have very limited support in synthesis tools.
Even in a testbench, it is best to use time-based wait or after statements only to generate the clock, and make all other signals dependent on an event (e.g. rising_edge(clk)). This avoids the problem of having multiple signals changing during delta cycle 0 along with the clock.
Consider the following code for a typical register:
process(clk) begin
if(rising_edge(clk)) then
a <= b;
end if;
end process;
and assume that clk and b are generated in a testbench as follows:
clk <= not clock after 1 ns;
process begin
b <= '1', '0' after 10 ns;
wait;
end process;
At time 0 delta 0, clk changes to '1' and b would change to '1'.
At time 0 delta 1, the register process would run since clk changed, and a would change to '1'.
No further sensitivity exists, so time would update to the next event at 1 ns.
At time 1 delta 0, clk changes to '0'.
At time 1 delta 1, the register process is run since clk changed, but nothing happens because rising_edge(clk) is false.
The above repeats for time 2-9 ns.
At time 10 delta 0, clk changes to '1' and b changes to '0'. Note that clk and b change in the same delta cycle.
At time 10 delta 1, the register process runs and a changes to '0'! As far as the result is concerned, this means that b changed before the rising clock edge!
Even if this behavior is understandable in this simple system, it can lead to some incredibly difficult to find simulation bugs. It is therefore better to base all signals off of the appropriate clock.
process begin
-- Initialize b to 1.
b <= '1';
-- Wait for 5 cycles.
for i in 1 to 5 loop
wait for rising_edge(clk);
end loop;
-- Set b to 0.
b <= '0';
-- Done.
wait;
end process;
This avoids unexpected behavior, since all signals will change at least one delta cycle after the associated clock, meaning causality is maintained throughout all of your processes.
I have this signal that should be zero until another signal Start = 0. How can I accomplish this?
Maybe you can use a handshake signal and put it in the sensitive list of the process. It will behave like a reset signal.
process (handshake_s, ...)
begin
if (handshake_s = '1') then -- failing edge of start
din <= 0;
else
-- do something
end if;
end process;
Use another process to update handshake_s.
process (start, ...)
begin
if failing_edge(start) then
handshake_s <= '1', '0' after 10 ns; -- produce a pulse
end if;
-- do something
end process;
Would you mind post all your code here so that we could understand the waveform better?
Testbench or RTL code?
For a testbench, your coding style is mostly ok, however, your signal Start has a problem and will never be '1' during a rising edge of clock. It goes to '1' just after the rising edge of clock and will return to '0' either simultaneously with clock or 1 delta cycle before clock (depending on your clock setup). Either way, anything running on rising_edge clock, such as your design, will not see it as a '1'.
A simple way to avoid this is to use nominal delays (25% of tperiod_Clk) on all of your testbench outputs that go to the DUT (Device Under Test). The pattern for a pulse is as follows.
wait until clk = '1' ; -- I recommend using rising_edge(Clk) for readability
Start <= '1' after tpd, '0' after tpd + tperiod_clk ;
Alternately, you can avoid this issue by not using waveform assignments. Such as the following. In this case, you don't need the tpd, however, if it really is a testbench, I recommend using it.
wait until clk = '1' ;
if i = 0 then
Start <= '1' after tpd ;
else
Start <= '0' after tpd ;
end if ;
For RTL code, you need to explore a different approach. Very briefly one way to approach it is as follows. Note do not use any delays, waveform assignments, or loops.
-- Counter to count from 0 to 63. Use "+ 1". Use "mod 64" if using type integer.
-- Start logic = decoder (can be coded separately)
-- Din Logic = decoder (can be coded separately)

How to use more than one delay counter in same process in VHDL

Need implement multiple delay counter for following wait for clock cycle, synthesizable.
if(clk'event and clk='1')then
if (StartTX = 1)then
TxBusy <= '1';
StartTxp <= '1';
Wait for 1 clock cycles;
StartTxp <= '0';
End IF;
IF (StartTX = 1)then
Wait x clock cycles ;
StartTxM <= '1';
Wait 1 clock cycles;
StartTxM<= '0';
End IF ;
IF (StartCal = 1) AND (StartInut =1 ) AND (IValid = 1)then
Wait 78 ns ;
Interrupt <= '1' ;
Wait 1 clock cycle
Interrupt = 0
End IF
you can react on state change events of the control signal as starting point. example:
if(clk'event and clk='1')then
StartTx_Last<=StartTx; -- 1 clock cycle delayed copy of control signal
StartTxp <= '0'; -- default value
if (StartTX = 1 AND StartTx_Last=0) then -- activate signals only for one clock
TxBusy <= '1';
StartTxp <= '1';
DelayCounter <= X; -- start delay counter
End IF;
-- set StartTxM after X clocks for 1 cycle
case DelayCounter is
when 1 => -- activity state
StartTxM <= '1';
DelayCounter<=0;
when 0 => -- idle state
StartTxM <='0';
when others => -- delay states
DelayCounter<=DelayCounter - 1;
end case;
....
for the 78ns delay you need a clock with a period t and a n-counter where n*t=78ns
Rewrite as three separate state machines. These can be combined into one process if you must, but one process for each is probably simpler and clearer.
Use a counter for "wait X cycles" : load it with X in the idle state when you see StartTX; decrement it while in the wait state, and transition back to the idle state when it reaches 0.
Translate 78ns into an appropriate number of cycles for the third state machine, and implement it the same way as the second.

Resources