Synthetizable delay in VHDL FSM state - vhdl

i am currently in the midst of writing a VHDL description of the unit(s) controlling a Sitronix ST7066U and LCD Module 1602A-1 for Xilinx Virtex-7, using Vivado Suite as my environment.
the Message Processing Unit is modeled with a 2-states (next state and outputs/conditions) FSM, but I have a huge issue.
Since the display has its own "operating times", as in the datasheet, I need to realize synthetizable delays inside my FSM when it reaches the states where the display itself is doing its things, and we cannot proceed with more character sending.
Such part was originally written like this:
when count_i => --waits for I_MAX cycles for the internal setup of the display
if (I = I_MAX_tb) then
I <= 0;
TRIGGER <= '1';
op_flag <= '1';
else
I <= I + 1;
end if;
if op_flag = '1' then
op_flag <= '0';
next_state <= init_state;
else
next_state <= count_i;
end if;
but, in simulation, the state machines stays in count_i state and doesn't realize that a new state assignment has happened.
I have tried the following construct
if (state'event) then
I<=I+1;
if (I = I_MAX_tb) then
I <= 0;
TRIGGER <= '1';
op_flag <= '1';
end if;
end if;
but it doesn't come close to working.
I am pretty sure it is a simple implementation issue, but, still...
(might be something related to my process' sensitivity list also?)

Related

Signal assignment method

I am new to VHDL and have had some difficulty in performing the assignment of two different values to the same signal inside a process. For example,
process(CLK)
if rising_edge(CLK) then
OUTPUT0 <= X(0);
OUTPUT1 <= X(1);
OUTPUT2 <= X(2);
LED0 <= VALUE;
OUTPUT0 <= Y(0);
OUTPUT1 <= Y(1);
OUTPUT2 <= Y(2);
LED1 <= VALUE;
end if;
end process;
Note that VALUE is an output dependent on the values assigned to OUTPUT0, OUTPUT1, OUTPUT2.
From what I understand in a process is that the last assignment to the same signal is always applied. What I am trying to do is apply two different sets of values to one set of inputs, map the output and it be done sequentially. I have tried separate processes tied to the same clock, a FSM to attempt to move sequentially and so on. At this point I have exhausted my knowledge of things to try.
My question is: What would be the best way to sequentially assign two values to one input and map its output in order?
EDIT:
As per Brian's suggestion on the state machine I had went ahead and implemented one again and found my error and fixed it. This gave the sequential assignment I was looking for.
I was reading 2 addresses from one instance of 32x1 distributed RAM which is the reason for a sequential assignment. Apologies for not providing the best example. Below is my final implementation:
RAM_READ_FSM : process(CLOCK) -- FSM to read the RAM addresses sequentially
begin
if rising_edge(CLOCK) then
case curr_state is
when S0 => if SW2 = '1' then
RAMADDR0 <= XYVEC(5); -- Y addresses
RAMADDR1 <= XYVEC(6);
RAMADDR2 <= XYVEC(7);
RAMADDR3 <= XYVEC(8);
RAMADDR4 <= XYVEC(9);
LED1 <= RAMOUT;
curr_state <= S1;
else
curr_state <= S0;
end if;
when S1 => if SW2 = '1' then
RAMADDR0 <= XYVEC(0); -- X addresses
RAMADDR1 <= XYVEC(1);
RAMADDR2 <= XYVEC(2);
RAMADDR3 <= XYVEC(3);
RAMADDR4 <= XYVEC(4);
LED2 <= RAMOUT;
curr_state <= S0;
else
curr_state <= S1;
end if;
end case;
end if;
end process;
The signals should be driven from the same process : multiple drivers would interfere with each other..
See Is process in VHDL reentrant? on signal assignment semantics.
now you can see there is need for some delay (even just 2 delta cycles, if the logic calculating VALUE is just a simple signal assignment) between the X and LED0 assignments.
You were on the right lines with a state machine but you didn't say anything about how it failed. Worth adding that to the Q to get a fuller answer.
Meanwhile there is a simple way to add delay :
like
LEDS : process is
begin
wait until rising_edge(CLK);
OUTPUT0 <= X(0);
OUTPUT1 <= X(1);
OUTPUT2 <= X(2);
wait until rising_edge(CLK);
LED0 <= VALUE;
wait until rising_edge(CLK);
OUTPUT0 <= Y(0);
-- etc
end process LEDS;

VHDL - Inferred Latch With Reset - FSM

I have an issue with this process where if I include a reset statement, I get an inferred latch. However, if I do not include the reset statement, I do not get an inferred latch on duty_cycle_triangle.
SIGNAL duty_cycle_triangle : INTEGER := 0;
SIGNAL count_up : STD_LOGIC;
SIGNAL tick_zero : STD_LOGIC;
triangle_count: PROCESS(clk, reset signal, tick_zero)
BEGIN
IF (reset = '1') THEN
duty_cycle_triangle <= 0;
ELSIF (RISING_EDGE(clk)) THEN
IF (tick_zero = '1') THEN
IF (count_up = '1') THEN
duty_cycle_triangle <= duty_cycle_triangle + 2;
ELSE
duty_cycle_triangle <= duty_cycle_triangle - 2;
END IF;
END IF;
END IF;
END PROCESS;
I am trying to design an FSM that will output a triangle wave using a PWM and an FSM shown below:
FSM_comb: PROCESS(currentState, duty_cycle_triangle)
BEGIN
CASE currentState IS
WHEN triangle_up =>
PWM_enable <= '1';
count_up <= '1';
IF (duty_cycle_triangle > 99) THEN
nextState <= triangle_down;
ELSE
nextState <= triangle_up;
END IF;
WHEN triangle_down =>
PWM_enable <= '1';
count_up <= '0';
IF (duty_cycle_triangle < 1) THEN
nextState <= triangle_up;
ELSE
nextState <= triangle_down;
END IF;
END CASE;
END PROCESS;
FSM_seq: PROCESS(clk, reset)
BEGIN
IF (reset = '1') THEN
currentState <= triangle_up;
ELSIF (RISING_EDGE(clk)) THEN
currentState <= nextState;
END IF;
END PROCESS FSM_seq;
Basically, after every "tick" I want the duty cycle of the triangle wave to increase by 2. After the duty cycle reaches 100, I want the duty cycle to decrease by 2 until the duty cycle reaches 0. Once the duty cycle reaches 0, I want the duty cycle to start increasing from 0 again until it reaches 100 and it starts over.
Does anyone see any problems with my code or can anyone point me in the right direction to correcting any issues?
If you want to create a sequential process, only include a reset and a clock in your sensitivity list. I suspect that it's inferring the latch because you're including too many signals in this process:
triangle_count: PROCESS(clk, reset signal, tick_zero)
It should just be
triangle_count: PROCESS(reset, clk)
The tools don't see that as a sequential process and make it combinational and that's how you get your latch.
Without trying it out i'm wondering if when the reset statement is removed, the tool is recognising the process as a synchronous process and inferring registers. In this case you don't need to explicitly define duty_cycle_triangle for each outcome of the process as the value is stored in a register.
With the reset statement included it may be treating the process as combinatorial and therefore inferring latches to store the state of duty_cycle_triangle when it's not explicitly defined.
Either way I agree with Russell's suggestion of changing the process sensitivity list which should get rid of the latch.

How can I generate a "tick" inside a process in VHDL?

I am writing a specified UART component in VHDL.
send: process(send_start)
variable bit_index : integer range 0 to 2 := 0;
begin
if (falling_edge(send_start)) then
if (start = '0' and transceiver_start = '1') then
bit_index := 0;
end if;
transceiver_start <= '1';
if (bit_index = 0) then
temp_data <= data.RE;
bit_index := 1;
transceiver_start <= '0';
delay_counter <= 0;
elsif (bit_index = 1) then
temp_data <= data.IM;
bit_index := 2;
transceiver_start <= '0';
end if;
end if;
end process;
The falling edge of the transceiver_start signal triggers the sub-component to run. I wanted to trigger it twice, but I do not know how to generate a second falling edge.
I thought about using a concurrent process, which would basically reset the transceiver_start signal to it's hi-state after delay_counter reaches some limit. Therefore I could bring it down inside the send process again to generate a falling edge. However, this makes me have two driving processes for the delay_counter signal, and I read that having resolution functions is not a good practice for synthesis (this code needs to be synthesizable.)
Is there any way for me to generate that falling edge when bit_index = 1?
FPGA devices and related synthesis tools are optimized for synchronous logic,
thus VHDL where a clock triggers process execution. Using a specific signal to
trigger process execution, as in the question code, is thus not in line with
the indented FPGA and VHDL design methodology.
Instead, use an internal clock to trigger process execution, usually the rising
edge of the clock. Actual update inside the process can then be conditional on
detection of change to a control signal, which can be send_start.
process (clock) is
begin
if rising_edge(clock) then
send_start_prev <= send_start; -- Previous for edge detection
if ((send_start = '0') and (send_start_prev = '1')) then -- Falling edge of send_start
... -- More code
end if;
end if;
end process;
For rerunning of conditional process code, for example based on bit_index = 1, the process contents can be updated like:
send_start_prev <= send_start; -- Previous for edge detection
rerun_request <= '0'; -- Default no rerun
if ((send_start = '0') and (send_start_prev = '1')) or -- Falling edge of send_start
(rerun_request = '1') then -- Rerun request
if bit_index = 1 then
rerun_request <= '1';
end if;
... -- More code
end if;

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;

VHDL - setting sampling rate for a sensor

Fellow SO users,
I'm trying to sample my resistive humidity sensor at a frequency of 5Hz (5 samples a second). I'm using an ADC to read the output. Now, I've been told that you can run the ADC at any frequency but you need to use a 5hz clock to initiate the conversion and read values from the ADC.
The way I'm doing this is by having a process that initiates the conversion by running at 5hz and having a flag, say "start_convert" to '1' on the rising edge of the clock.
PROCESS (CLK_5HZ)
BEGIN
IF (CLK_5HZ'EVENT AND CLK_5HZ = '1') THEN
START_CONVERT <= '1';
END IF;
END PROCESS;
And then I have a state machine for the ADC;
PROCESS (CURR_STATE, INTR)
BEGIN
CASE CURR_STATE IS
WHEN STARTUP =>
WR <= '0';
READ_DATA <= '0';
IF (START_CONVERT = '1') THEN
NEXT_STATE <= CONVERT;
ELSE
NEXT_STATE <= STARTUP;
END IF;
WHEN CONVERT =>
IF (INTR = '0' AND STREAM = '1') THEN
NEXT_STATE <= WAIT500;
ELSIF (INTR = '0' AND STREAM = '0') THEN
NEXT_STATE <= READ1;
ELSE
NEXT_STATE <= CONVERT;
END IF;
WR <= '1';
READ_DATA <= '0';
WHEN WAIT10 =>
IF (COUNTER_WAIT = 10) THEN
NEXT_STATE <= READ1;
ELSE
NEXT_STATE <= WAIT10;
END IF;
COUNTER_WAIT <= COUNTER_WAIT + 1;
WHEN READ1 =>
NEXT_STATE <= CONVERT;
WR <= '1';
READ_DATA <= '1';
WHEN OTHERS =>
NEXT_STATE <= STARTUP;
END CASE;
END PROCESS;
And then I'm using another process at 5hz to detect whenever READ_DATA is 1 so that I read the values from the ADC.
PROCESS (CLK_5HZ, RST)
BEGIN
IF (RST = '1') THEN
Y <= (OTHERS => '0');
ELSIF (CLK_5HZ'EVENT AND CLK_5HZ = '1') THEN
IF (READ_DATA = '1') THEN
Y <= DATA_IN (0) & DATA_IN (1) &
DATA_IN (2) & DATA_IN (3) &
DATA_IN (4) & DATA_IN (5) &
DATA_IN (6) & DATA_IN (7);
END IF;
END IF;
END PROCESS;
Could anyone please advice me whether this is the right approach or not?
EDIT: I'm interfacing the ADC (ADC0804) using a Spartan-3 board.
It's a bit hard to give specific advice, when not knowing the specifics of the device you are trying to interface to.
However, a couple of general comments regarding your code:
Your asynchronous process (the PROCESS (CURR_STATE, INTR)) will generate quite a few latches when synthesizing it, since you are not setting all your signals in all cases. WR and READ_DATA are for instance not being set in your WAIT10 state. This will most probably lead to severe timing issues, so correcting this is something you'd absolutely want to do.
The WAIT10 state in the same process will give you a combinatorial loop, as it runs whenever COUNTER_WAIT is updated. As that state also updates COUNTER_WAIT, it will in theory just keep running, but in practice most synthesizers will just give you an error (I think). You'll need to move the incrementing to a synchronous/clocked process instead, which will also give you control over how long each cycle takes.
Your 5 Hz processes seem to run on a separate clock (CLK_5HZ). I presume that the rest of your system is running at a faster clock? This essentially gives you two (or more) clock domains, that will need special interface logic for interfacing them with each other. A much, much better solution is to run everything on the same (fast) clock, and control slower processes using clock enables. Everything is thus inherently synchronized, and shouldn't give you any nasty timing surprises.

Resources