VHDL state machine is not looping - vhdl

Fellow SO users,
I'm programming my ADC (ADC0804 which is mounted on a breadboard connected to a Spartan-3 FPGA board). Now, I'm using this ADC to provide digital output for my humidity sensor. The ADC outputs an 8-bit value which I'm displaying on the LEDs on the FPGA board.
Now, I'm writing the state machine in such a way that the ADC would always continue to keep outputting values even when I vary the humidity level. But as for the current implementation I have, eventhough I'm looping back to the first state, I'm not getting a continuous stream of values. I'm only getting one 8-bit value at a time (I.E.; I have to keep pressing the reset button to update the value displayed on the LEDs). The following is my code.
FSM_NEXT_STATE_INIT : PROCESS (CLK, RST)
BEGIN
IF (RST = '1') THEN
CURR_STATE <= STARTUP;
ELSIF (CLK'EVENT AND CLK = '1') THEN
CURR_STATE <= NEXT_STATE;
END IF;
END PROCESS;
START_FSM : PROCESS (CURR_STATE, INTR)
BEGIN
CASE CURR_STATE IS
WHEN STARTUP =>
NEXT_STATE <= CONVERT;
WR <= '0';
READ_DATA <= '0';
WHEN CONVERT =>
IF (INTR = '0') THEN
NEXT_STATE <= READ1;
ELSE
NEXT_STATE <= CONVERT;
END IF;
WR <= '1';
READ_DATA <= '0';
WHEN READ1 =>
NEXT_STATE <= READ2;
WR <= '1';
READ_DATA <= '1';
WHEN READ2 =>
NEXT_STATE <= STARTUP;
WR <= '1';
READ_DATA <= '0';
WHEN OTHERS =>
NEXT_STATE <= STARTUP;
END CASE;
END PROCESS;
PROCESS (CLK, RST)
BEGIN
IF (RST = '1') THEN
Y <= (OTHERS => '0');
ELSIF (CLK'EVENT AND CLK = '1') THEN
IF (READ_DATA = '1') THEN
Y <= D7&D6&D5&D4&D3&D2&D1&D0; --Concatenate the 8-bit ADC output
END IF;
END IF;
END PROCESS;
You'll notice that in state 'READ2', I'm looping back to the beginning (so that I can keep reading values continuously as the states transition) but somehow I don't think this is working. Could anyone please provide some assistance on how to go about solving this?

After a look on the data sheet for the ADC0804 I found following which could be the/a possible reason:
Note: Read strobe must occur 8 clock periods (8/fCLK) after assertion of interrupt to guarantee reset of INTR.
Inserting a WAIT state between CONVERT and READ1 might fix the problem.

Related

VHDL Synthesis Error and Code Suggestions [duplicate]

I've a module that have a 8bit input and a serial output, I want to serialize input data and synchronize it with a clock.
I want to set my data when falling edge then wait when clock rise, when clock fall again I set another data. I don't want to connect the directly reference clock to the output because when I don't use this module I want a 1 state on clock output.
I've tried this code:
process(Clock, ModuleReset)
begin
if ModuleReset = '0' then
OutData <= '0';
OutCK <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutCK <= '0';
OutData <= Data(counter);
elsif rising_edge(Clock) then
OutCK <= '1';
end if;
end process;
The synthesizer gives me this error:
"Asynchronous load of non-constant data for SCK is not supported"
When I separate the code in two blocks like this:
process(Clock, ModuleReset)
begin
if ModuleReset = '0' then
OutData <= '0';
OutCK <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutCK <= '0';
OutData <= Data(counter);
end process;
process(Clock)
if rising_edge(Clock) then
OutCK <= '1';
end if;
end process;
I have these two errors:
"Multiple non tristate drivers for net SCK"
"Unresolved tristate drivers for net SCK"
Another code I've tried is:
process(Clock, ModuleReset)
if ModuleEN = '1' then
OutCK <= Clock;
end if;
begin
if ModuleReset = '0' then
OutData <= '0';
OutCK <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutCK <= '0';
OutData <= Data(counter);
end if;
end process;
But the output clock looks strange with a different frequency.
Your last idea, which I understand ended up working for you, is sub-optimal. If your clock is slow, it should be fine, but I suggest you fix it nevertheless.
if ModuleEN = '1' then
OutCK <= Clock;
else
OutCK <= '1';
end if;
Yields combinational logic with the clock signals for the output. Having the clock used as a logic signal is never recommended, since clocks use clock paths which doesn't route well to general routing resources. The output signal will have potential glitches (very bad for an output interface!) and large delay/skew.
Your first approach, to use a DDR register to forward the clock, is indeed the correct and best approach. With this scheme, your clock only use clock paths, and if both the registers outputing the clock and data are situated in IO blocks, they will have the same output delay with very little skew.
You didn't specify the technology you're using, but I suggest you lookup how to write code that maps to DDR register for your synthesizer. Alternatively, you can manually instantiate the DDR output register primitive, likely ODDR for Xilinx or ALTDDIO_OUT for altera.
The problem with your attempts is indeed that you have multiple drivers for the same signal, or that you assign a signal on both rising and falling edge of a clock. This is not synthesizable.
Try this:
process(Clock, ModuleReset, ModuleEN)
begin
if ModuleEN = '1' then
OutCK <= Clock;
else
OutCK <= '1';
end if;
if ModuleReset = '0' then
OutData <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutData <= Data(counter);
end if;
end process;

Drive input clock to output

I've a module that have a 8bit input and a serial output, I want to serialize input data and synchronize it with a clock.
I want to set my data when falling edge then wait when clock rise, when clock fall again I set another data. I don't want to connect the directly reference clock to the output because when I don't use this module I want a 1 state on clock output.
I've tried this code:
process(Clock, ModuleReset)
begin
if ModuleReset = '0' then
OutData <= '0';
OutCK <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutCK <= '0';
OutData <= Data(counter);
elsif rising_edge(Clock) then
OutCK <= '1';
end if;
end process;
The synthesizer gives me this error:
"Asynchronous load of non-constant data for SCK is not supported"
When I separate the code in two blocks like this:
process(Clock, ModuleReset)
begin
if ModuleReset = '0' then
OutData <= '0';
OutCK <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutCK <= '0';
OutData <= Data(counter);
end process;
process(Clock)
if rising_edge(Clock) then
OutCK <= '1';
end if;
end process;
I have these two errors:
"Multiple non tristate drivers for net SCK"
"Unresolved tristate drivers for net SCK"
Another code I've tried is:
process(Clock, ModuleReset)
if ModuleEN = '1' then
OutCK <= Clock;
end if;
begin
if ModuleReset = '0' then
OutData <= '0';
OutCK <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutCK <= '0';
OutData <= Data(counter);
end if;
end process;
But the output clock looks strange with a different frequency.
Your last idea, which I understand ended up working for you, is sub-optimal. If your clock is slow, it should be fine, but I suggest you fix it nevertheless.
if ModuleEN = '1' then
OutCK <= Clock;
else
OutCK <= '1';
end if;
Yields combinational logic with the clock signals for the output. Having the clock used as a logic signal is never recommended, since clocks use clock paths which doesn't route well to general routing resources. The output signal will have potential glitches (very bad for an output interface!) and large delay/skew.
Your first approach, to use a DDR register to forward the clock, is indeed the correct and best approach. With this scheme, your clock only use clock paths, and if both the registers outputing the clock and data are situated in IO blocks, they will have the same output delay with very little skew.
You didn't specify the technology you're using, but I suggest you lookup how to write code that maps to DDR register for your synthesizer. Alternatively, you can manually instantiate the DDR output register primitive, likely ODDR for Xilinx or ALTDDIO_OUT for altera.
The problem with your attempts is indeed that you have multiple drivers for the same signal, or that you assign a signal on both rising and falling edge of a clock. This is not synthesizable.
Try this:
process(Clock, ModuleReset, ModuleEN)
begin
if ModuleEN = '1' then
OutCK <= Clock;
else
OutCK <= '1';
end if;
if ModuleReset = '0' then
OutData <= '0';
counter <= 7;
elsif falling_edge(Clock) then
OutData <= Data(counter);
end if;
end process;

Handling Interrupt in VHDL

We are using OR1200 for our project and we would like to assign an interrupt to the 8th button of FPGA Board. Here is the code to generate interrupt:
inrpt: process(CLK_I, RST_I)
begin
if RST_I = '1' then
butt_int_pul <= '0';
butt_int_tmp <= '0';
elsif rising_edge(CLK_I) then
if(DATA_I(8) = '1' and butt_int_tmp = '0') then
butt_int_pul <= '1';
else
butt_int_pul <= '0';
end if;
butt_int_tmp <= DATA_I(8);
end if;
end process inrpt;
process(CLK_I, RST_I)
begin
if RST_I = '1' then
butt_int <= '0';
elsif butt_int_pul = '1' then
butt_int <= '1';
elsif clear_int = '1' then
butt_int <= '0';
end if;
end process;
We only want this interrupt to be handled only once (holding the button should not call the interrupt again), that's why we included a flag to check this (butt_int_tmp).
The problem is that the interrupt call is not stable. It does not call each time we press the button. When we remove the flag, it works, but in this case, it is handled as many as we hold the button.
What are we doing wrong?
To start with, that second process is not properly written. It should have a structure equivalent to the first process (i.e., if(rising_edge(CLK_I)) surrounding all but the reset logic). You are currently describing a latch with multiple enable signals and wrong sensitivity list.
Moving on, there's no real reason you need that second process at all. You just need one register to act as interrupt (butt_int), and one to keep track of the previous state of the button (butt_prev). The interrupt is triggered for one cycle when DATA_I(8) is '1' while butt_prev is '0' (i.e., the button changed from not-pressed to pressed).
process(CLK_I, RST_I) begin
if(RST_I='1') then
butt_prev <= '0';
butt_int <= '0';
elsif(rising_edge(CLK_I)) then
if(DATA_I(8)='1' and butt_prev='0') then
butt_int <= '1';
else
butt_int <= '0';
end if;
butt_prev <= DATA_I(8);
end if;
end process;
Note that this will only work if your button is properly debounced, otherwise you are likely to get multiple interrupts triggered when you press (or even release) the button.
Its best not to think about interrupts. As you're targetting an FPGA, you're describing digital logic, not a software processor.
There a numerous way to build a circuit with the behaviour you want.
The simplest is probably a re-timed latch
signal latched_button : std_logic;
signal meta_chain : std_logic_vector(2 downto 0);
p_async_latch: process(rst_i,data(8))
begin
if rst_i = '1' then
latched_button <= '0';
elsif data(8) = '1' then
latched_button <= '1';
end if;
end process;
p_meta_chain: process(rst_i,clk_i)
begin
if rst_i = '1' then
meta_chain <= (others => '0');
elsif rising_edge(clk_i) then
meta_chain <= meta_chain(1 downto 0) & latched_button;
end if;
end process;
button_int <= '1' when meta_chain(2 downto 1) = "01" else '0';
This causes the button press to be latched asynchronously. The latched signal is then clocked along a shift register, and the interrupt is only valid for one cycle, which is the first clock cycle that the latch is seen on the clock domain.

Communication between processes in VHDL

I have problems on communicating between the processes. I used to use flag and clearFlag to tackle this, but it's kind of annoying and not looking good. What is the best practice to handle this? Here is a sample code on how I did it before:
Proc_A : process (clk, reset, clrFlag)
begin
if clrFlag = '1' then
flag <='0';
elsif reset = '0' then
A <= (others => '0');
elsif rising_edge (clk) then
A <= in;
flag <= '1';
end if;
end process;
Proc_B : process (clk, reset)
begin
if reset = '0' then
B <= (others => '0');
elsif rising_edge (clk) then
if flag = '1' then
B <= data;
clrFlag <= '1';
else
clrFlag <= '0';
end if;
end if;
end process;
This way works but I don't think it is nice method. I have to write a flag and clrFlag couple to do this task. All I want to do is when something happened (e.g. A <= in;), it triggers another proc, Proc_B for example, to run once or a number of times. What is the best practice to this problem? Thanks!
For simulation, you can make a process wait on a signal:
Proc_B : process
begin
wait until flag'event;
B <= data;
end process;
and just write the flag with its inverse every time you need something to happen.
In synthesisable logic, you either have to exchange flag signals, as you do, or use some other higher-level communication (like a FIFO, messagebox, or similar).
However, if all your proc_b logic takes place in a single cycle - so you can guarantee not to miss a flag, and to be able to keep up even if flag is asserted all the time (as it looks like you do) - you can do this (and combine the two processes):
Proc : process (clk, reset, clrFlag)
begin
flag <='0';
if reset = '0' then
A <= (others => '0');
B <= (others => '0');
elsif rising_edge (clk) then
if some_trigger_event = '1' then
A <= in;
flag <= '1';
end if;
-- recall that due to VHDL's scheduling rules, this "if" will take place
-- one clock cycle after the flag is written to, just as if it were in a
-- separate process
if flag = '1' then
B <= data;
end if;
end if;
end process;
Side note - your code is not ideal for synthesis... you really only want the reset part outside the clocked part:
Proc_A : process (clk, reset)
begin
if reset = '0' then
A <= (others => '0');
elsif rising_edge (clk) then
if clrFlag = '1' then
flag <='0';
else
A <= in;
flag <= '1';
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