Struggling with waiting for transfer completion with VHDL - vhdl

I'm needing to do continual SPI communication to read values from a dual channel ADC I have, and have written a kinda state-machine to do so. However, it doesn't seem to be getting into the state that reads the second channel and I can't figure out why. here's the VHDL...
SPI_read: process (mclk)
--command bits: Start.Single.Ch.MSBF....
constant query_x: unsigned(ADC_datawidth-1 downto 0) := "11010000000000000"; -- Query ADC Ch0 ( inclinometer x-axis)
constant query_y: unsigned(ADC_datawidth-1 downto 0) := "11110000000000000"; -- Query ADC Ch1 ( inclinometer y-axis)
begin
if rising_edge(mclk) then
-- when SPI is not busy, change state and latch Rx data from last communication
if (SPI_busy = '0') then
case SPI_action is
when SETUP =>
SPI_pol <= '0'; -- Clk low when not active
SPI_pha <= 1; -- First edge is half an SCLK period after CS activated
SPI_action <= READ_X;
when READ_X =>
SPI_Tx_buf <= query_x; -- Load in command
y_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_Y;
when READ_Y =>
SPI_Tx_buf <= query_y; -- Load in command
x_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_X;
end case;
else
SPI_send <= '0'; -- Deassert send pin
end if;
end if;
end process SPI_read;
The command is sent to the Tx buffer, and the value from the last received data is written to a signal which is output to some seven segment displays. A pulse from SPI_send is required to start the transfer, and when started, SPI_busy is set high until the transfer is completed.
Right now it'll only send the query_x over SPI, and I can know this since I can see it on the scope. Interestingly, however, It's outputting the same value to both displays which leads me to think that it's still getting into it's READ_Y state, but not changing the Tx Data it's outputting.
I've been staring at this code for hours now, and I can't figure it out. Sometimes a fresh pair of eyes makes life easier, so if you spot anything please let me know.
Also, I'm very open to suggestions of better ways to deal with this, I'm just learning VHDL so I'm not even sure I'm doing things the right way mostly!

Summarizing my comments so far into an answer.
Simulate this process/module with your SPI master component.
Your approach is generally correct but I would suggest you re-architect your state machine slightly to put explicit wait states in between each spi transaction (wait_x, wait_y) and maybe have a more robust handshake between the modules, ie stay in read_x until busy goes high, then stay in wait_x until busy goes low.
It looks like send is getting asserted for two cycles and you are transition through both read_x and read_y each cycle.
Drawn from this program
http://wavedrom.googlecode.com/svn/trunk/editor.html
with this source:
{ "signal" : [
{ "name": "clk", "wave": "P........" },
{ "name": "busy", "wave": "0..1.|0..1"},
{ "name": "SPI_Action", "wave": "====.|.==.", "data": ["SETUP", "READ_X", "READ_Y", "READ_X", "READ_Y", "READ_X", "READ_Y", ] },
{ "name": "SPI_send", "wave": "0.1.0|.1.0", "data": ["0", "1", "Load", "Start","WaitA"] },
{ "name": "SPI_Tx_buf", "wave": "x.===|..==", "data": ["query_x","query_y","query_x","query_y","query_x"],},
]}

You are thinking along the right basic lines, but there are various things not-quite-right with your state machine - as the other answers say - and these are easy to discover in simulation.
For example
when READ_X =>
SPI_Tx_buf <= query_x; -- Load in command
y_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_Y;
Now if SPI_Busy stays low for a second cycle, this will clearly not stay in state READ_X but transition directly to READ_Y which is probably not what you want.
A more normal state machine would treat the states as outermost, and interpret the input signals differently for each state :
case SPI_Action is
when READ_X =>
if SPI_Busy = '0' then -- Wait here if busy
SPI_Tx_buf <= query_x; -- Load in command
y_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READING_X;
end if;
when READING_X =>
if SPI_Busy = '1' then -- command accepted
SPI_action <= READ_Y; -- ready to send next one
end if;
when READ_Y =>
if SPI_Busy = '0' then -- Wait here if busy
You can see that this version treats the Busy signal as a handshake, and only progresses when Busy changes state. I am certain you can make your approach (IF outermost) work if you want, but you will have tofigure out how to apply the handshaking principle yourself.
There is also no "Idle" state where neither X or Y is being read; this SM will read X and Y alternately as fast as it can. Commonly you would read them both, then return to Idle until some other Start signal commanded you to leave Idle and perform a fresh set of reads.
You can possibly also make the state machine more robust with a "when others" clause. It's not a must, if you guarantee to cover all your defined states, but it can make maintenance easier. On the other hand, without such a clause, the compilers will let you know of any uncovered states, guarding against mistakes.
There is a myth that a "when others" clause is essential and synthesis tools generate safer but less optimal state machines from a "when others" clause. However there are synthesis attributes or command line options to control how synth tools generate state machines.

I have to agree with the issues raised by David and add a few notes.
There are a few things that are not very good with your code, first of all, you must have a "when others =>" in the list of your states.
None of your signals seems to have a default value except the SPI_send. It also not a good idea to put the state machine inside the if statement. And if you have to do it, then you must set all the signals in both cases or else you end up with latches instead of flip-flops. One easy way to do this is to set all the signals at the begging of your code to their default value and then change them when needed.
This way the synthesis tool knows how to handle them and you get correct.
Well, this is from a VHDL-for-synthesis document from Siemence:
If a signal or a variable is not assigned a value in all possible
*branches of an if statement, a latch is inferred*. If the intention is
not to infer a latch, then the signal or variable must be assigned a
value explicitly in all branches of the statement.
You can find the guide in PDF format at: http://web.ewu.edu/groups/technology/Claudio/ee360/Lectures/vhdl-for-synthesis.pdf

Related

What is the disadvantage of this approach to VHDL state machine design?

A frequently used style for state machines is to change state in a very simple clocked process and either in the same process or another one, a combinatorial section which defines the transition to the next state: (here I use a synchronous reset, because I have a master reset synchronizer)
process( aclk, state, next_state, bob, alice )
begin
if rising_edge( aclk ) then
if resetn = '0' then
state <= IDLE;
else
state <= next_state;
end if;
end if;
next_state <= state;
case state is
when IDLE =>
if bob = alice then
next_state <= ANOTHER_STATE;
...and so on. Some prefer to put the combinatorial section in another process, styles vary. I split the machine and various things such as counters which control state transitions into separate small processes, but I know some dislike this style.
Is there any serious problem with keeping everything in the synchronous block, as in:
process( aclk )
begin
if rising_edge( aclk ) then
if resetn = '0' then
state <= IDLE;
else
case state is
when IDLE =>
if bob = alice then
state <= ANOTHER_STATE;
end if;
when others =>
null;
end case;
end if;
end if;
end process;
I ask because when I started programming (very badly, as a software person!) I used to use the second method, and am wondering if I should rewrite the code.
I have a friend who wrote some of the ARM logic, (not Sophie! I think she used a pencil and paper...) who tells me his rule was never to create processes with anything other than the clock in the sensitivity list.
Best regards
Geoff
I don't think you can prescribe what to do. As with many coding styles some people prefer the one others the other. There is definitely not a good or a bad style.
For small simple state-machines I use the first method.
For big, complex state-machines I prefer the second method.
Tricks I like about the second method:
e.g. in state X you need a register R to have the value A. In the first method you have to track down every state transition which goes to X and add: R <= A;. Also if you make changes your state-machines you should not forget that.
The second method normally has a state and next_state variable. Then you can write:
if (next_state==X) R <= A;. You can now play around with your code and know that when you get to state X, R will be have been assigned the value A.
Break out: Suppose you need to have an 'emergency stop' or the user negates the 'enable' bit and the whole FSM needs to stop. In method 1 you have to start every state condition with: if (stop_everything) state<=IDLE else...
In method two you register part becomes:
if (stop_everything)
state <= IDLE;
else
state <= next_state;
I have worked with IP from a big CPU core vendor (You can guess their name). In their code you see only the second method even for the simplest of code. I assume it is a mandatory coding style if you work for them.

Execute two chunks of code in sequence but the code itself in parallel

I have a piece of code that needs to be executed after another. For example, I have an addition slv_reg2 <= slv_reg0 + slv_reg1; and then I need the result subtracted from a number.
architecture IMP of user_logic is
signal slv_reg0 : std_logic_vector(0 to C_SLV_DWIDTH-1); --32 bits wide
signal slv_reg1 : std_logic_vector(0 to C_SLV_DWIDTH-1);
signal slv_reg2 : std_logic_vector(0 to C_SLV_DWIDTH-1);
signal slv_reg3 : std_logic_vector(0 to C_SLV_DWIDTH-1);
signal flag : bit := '0';
begin
slv_reg2 <= slv_reg0 + slv_reg1;
flag <= '1';
process (flag)
begin
IF (flag = '1') THEN
slv_reg3 <= slv_reg0 - slv_reg2;
END IF;
end process;
end IMP;
I haven't tested the code above but I would like some feedback if my thought is correct. What is contained in the process doens't need to run in sequence, how can I make this part also run in parallel?
In summary, I have two chunks of code that need to be executed in sequence but the code itselft should run in parallel.
--UPDATE--
begin
slv_regX <= (slv_reg0 - slv_reg1) + (slv_reg2 - slv_reg3) +(slv_reg4 - slv_reg5); --...etc
process(clk) -- Process for horizontal counter
begin
if(rising_edge(clk)) then
if(flag = 1) then
flag <= 0;
end if;
end if;
end process;
It's concurrent, not parallel. Just use intermediate signals
I am afraid your thought process about VHDL is not entirely correct. You acknowledge the first assignment happening 'in parallel', but you must realise that the process is also running concurrently with the rest of the statements. Only what happens inside a process is evaluated sequentially - every time any of the signals in the sensitivity list change.
I need to make a lot of assumptions about what you need, but perhaps you're just after this style:
c <= a + b;
e <= d - c;
The signal e will contain d-(a+b) at all times. If you don't immediately understand why - this is where the difference between concurrent and parallel comes in. It is being continuously evaluated - just like if you'd hook the circuit up with copper wires.
If what you actually need is for something to happen based on a clock - you're really not there yet with your example and I recommend looking up examples and tutorials first. People will be happy to help once you provide VHDL code that is more complete.
Issues in your example
Assuming you are intending to write synthesisable VHDL, there several problems with your code:
Your process sensitivity list is not correct - you would either make it sensitive to only a clock, or to all the input signals to the process.
You are both initialising your 'flag' to '1' and assigning it a '0' in concurrent code, that doesn't make sense.
Signals ..reg0 and ..reg1 are not assigned. If they are inputs, don't declare them as signals.
You have named your signals as if they are anonymous numbered 'registers', but they are not registers, just signals: wires! (if ended up with this style because you are comparing to Verilog - let me argue that the Verilog 'reg' regularly don't make sense as they often end up not being registers.)
Try it
I haven't tested the code above but
You really should. Find code examples, tutorials, go and play!

VHDL behavioural D Flip-Flop with R & S

Hi can any of you with more experience with VHDL Quartus II please set me right on this please.
I have the following Entity and behavioural Architecture for a D Flip-Flop with Set and Reset.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY Q1 IS
PORT (D,R,S,CLK : IN std_logic;
Q : OUT std_logic
);
END ENTITY Q1;
ARCHITECTURE behavioural OF Q1 IS
BEGIN
D_FF : PROCESS (CLK,R,S)
BEGIN
IF R = '0' THEN Q <= '0';
ELSIF S = '0' THEN Q <= '1';
ELSIF (rising_edge(CLK)) THEN Q <= D;
END IF;
END PROCESS D_FF;
END ARCHITECTURE behavioural;
When I compile the code using Quartus II I get the following error message :
Warning (335093): TimeQuest Timing Analyzer is analyzing 1 combinational loops as latches.
I think it is a warning for the incomplete output assignments of the R & S inputs, but when I make a D Flip-Flop latch with only the SET input this error message does not appear when compiled. This leaves me thinking maybe I made an error when writing the architecture? If anyone has any answers or useful info that would be much appreciated.
You have described a clock-edge triggered flip-flop (FF) with both an asynchronous reset and an asynchronous set. Only one of them is supported at the same time because AFAIK, all FFs on Altera FPGAs have only an asynchronous reset.
An asynchronous set is emulated on Altera FPGAs by inverting the FF data input and output and then resetting it to low instead of setting it to high. It looks like this:
Don't overlook the inverter on the D input of the FF. If S is low, then the FF itself is asynchronously reset, but due the negation of the Q output afterwars, it behaves as an asynchronous set of output Q of your entity Q1. If S is high, the FF stores the negated input at the rising clock-edge, which is again negated at the output. As you see, the asynchronous reset port of the FF is already used, and thus, cannot be used for an additional asynchronous reset of your entity Q1.
I recommend to use flip-flops with synchronous set and reset instead:
ARCHITECTURE sync_rs OF Q1 IS
BEGIN
D_FF : PROCESS (CLK)
BEGIN
IF (rising_edge(CLK)) THEN
IF R = '0' THEN Q <= '0';
ELSIF S = '0' THEN Q <= '1';
ELSE Q <= D;
END IF;
END IF;
END PROCESS D_FF;
END ARCHITECTURE sync_rs;
Flip flops in FPGA devices usually have either asynchronous set or reset, but not both, so Altera Quartus tries to make the requested circuit with latches instead of dedicated hardware.
However, for most cases that is not what you want, so instead use flip flops with either asynchronous reset or set, or use synchronous set and and reset as Martin Zabel suggested in his answer.
Note that asynchronous reset have an advantage over synchronous reset in high speed designs, since the asynchronous reset does not add any login in the main synchronous data path, which is usually the critical path for high-speed designs.
Finally, for asynchronous reset, it is a good habit to use two if separate statements, with reset last, so clocking is not dependent on assertion of reset. It is not an issue for a single bit flip flop, but if more signals are controlled in the same process, and reset does not apply to all signals, then clocking should not be dependent on reset for those signal without reset, since that will infer latches. Code like:
D_FF : PROCESS (CLK, R)
BEGIN
IF rising_edge(CLK) THEN
Q <= D;
END IF;
IF R = '0' THEN
Q <= '0';
END IF;
END PROCESS D_FF;
Thanks for the reply, I made the R & S inputs asynchronous on purpose. I have been working through a VHDL text book "Free Range VHDL" and have come across the following question in the Exercises:
The question asks for both inputs to be asynchronous. You say this can be emulated with Altera by inverting the input and output and resetting it to low instead of high. Can you expand on this a little? Thanks

In a state machine process is there a difference if I state specifically that the state stays the same?

In a process that controls a state machine, when the state stays the same, is there a difference if specifically stated that the state signal gets the same value as it has? In the example below, are the two lines inside the process with the notes needed?
--CLK and RST are input signals
type state_machine_states is
(
st_idle, st_1
);
signal sm : state_machine_states ;
signal next_state : std_logic;
begin
--assume that there is some logic which deals with the next_state signal
states_proc: process (RST, CLK)
begin
if (RST = '1')
sm <= 'st_idle'
elsif rising_edge(CLK) then
case sm is
when st_idle =>
if (next_state = '1') then
sm <= st_1;
else --Are these two lines needed, and is there
sm <= st_idle --any difference if they are written or not?
end if;
when st_1 =>
sm <= st_idle;
end case;
end if;
end process;
This is fine with most modern tools. If you omit an else in a combinatorial process then you'll infer a latch. But in a clocked process you will not.
It treats this it as an enable to drive the register. The input is not clocked to the output when the enable is not driven.
when using an else statement, or generally when each code path is covered, then you avoid using latches
Update: when the else is omitted, you use the latch as memory
The code shown along with the original question is not appropriate for FSM implementation. You are looking at sm and next state to decide what sm should be, which does not make sense. The following must occur in ANY state machine:
1) Look at the present state and to the input to decide what the next state should be. This must be REGISTERED.
2) Look at the present state to decide what the output should be (Moore case). This should NOT BE REGISTERED, unless a special condition is required (for example, glitch-free output or pipelined construction - See, for example, "Finite State Machines in Hardware: Theory and Design (with VHDL and SystemVerilog)").

VHDL FSM set unit input and use output in same state

I am implementing a Mealy-type FSM in vhdl. I currently am using double process, although i've just read a single-process might be neater. Consider that a parameter of your answer.
The short version of the question is: May I have a state, inside of which the input of another component is changed, and, aftwerwards, in the same state, use an output of said component? Will that be safe or will it be a rat race, and I should make another state using the component's output?
Long version: I have a memory module. This is a fifo memory, and activating its reset signal takes a variable named queue_pointer to its first element. After writing to the memory, the pointer increases and, should it get out of range, it is (then also) reset to the first element, and an output signal done is activated. By the way, i call this component FIMEM.
My FSM first writes the whole FIMEM, then moves on to other matters. The last write will be done from the state:
when SRAM_read =>
READ_ACK <= '1';
FIMEM_enable <= '1';
FIMEM_write_readNEG <= '0';
if(FIMEM_done = '1') then --is that too fast? if so, we're gonna have to add another state
FIMEM_reset <= '1'; --this is even faster, will need check
data_pipe_to_FOMEM := DELAYS_FIMEM_TO_FOMEM;
next_state <= processing_phase1;
else
SRAM_address := SRAM_address + 1;
next_state <= SRAM_wait_read;
end if;
At this state, having enable and write active means data will be written on the FIMEM. If that was the last data space on the memory, FIMEM_done will activate, and the nice chunk of code within the if will take care of the future. But, will there be time enough? If not, and next state goes to SRAM_wait_read, and FIMEM_done gets activated then, there will be problems. The fact that FIMEM is totally synchronous (while this part of my code is in the asynchronous process) messes even more?
here's my memory code, just in case:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity memory is
generic (size: positive := 20);
Port ( clk,
reset,
enable,
write_readNEG: in std_logic;
done: out std_logic;
data_in: in STD_LOGIC_VECTOR(7 downto 0);
data_out: out STD_LOGIC_VECTOR(7 downto 0) );
end memory;
architecture Behavioral of memory is
subtype word is STD_LOGIC_VECTOR(7 downto 0);
type fifo_memory_t is array (0 to size-1) of word;
signal fifo_memory : fifo_memory_t :=((others=> (others=>'0')));
--Functionality instructions:
--Resetting sets the queue pointer to the first element, and done to 0
--Each cycle with enable active, a datum from the pointer position is
--written/read according to write_readNEG, and the pointer is incremented.
--If the operation was at the last element, the pointer returns to the first place
--and done is set to 1. When done is 1, enable is ignored.
Begin
process(clk,reset)
variable done_buf : std_logic;
variable queue_pointer: natural range 0 to size-1;
begin
if(reset = '1') then
queue_pointer := 0;
done_buf := '0';
elsif(rising_edge(clk)) then
if(done_buf = '0' and enable = '1') then
case write_readNEG is
when '0' =>
data_out <= fifo_memory(queue_pointer);
when '1' =>
fifo_memory(queue_pointer) <= data_in;
when others => null;
end case;
if(queue_pointer = size-1) then
done_buf := '1';
queue_pointer := 0;--check
else
queue_pointer := queue_pointer + 1;
end if;
end if; --enable x not done if
end if; --reset/rising edge end if
done <= done_buf;
end process;
End Behavioral;
More details inspired by the first comment:
The memory can read the data at the same cycle enable is activated, as seen here:
Notice how the "1", the value when enable is turned active, is actually written into the memory.
Unfortunately, the piece of code is in the asynchronous process! Although I'm VERY strongly thinking of moving to a single-process description.
In contrast to all the circuits I've designed until now, it is very hard for me to test it via simulation. This is a project in my university, where we download our vhdl programs to a xilinx spartan 3 FPGA. This time, we have been given a unit which transfers data between Matlab and the FPGA's SRAM (the functionality of which, I have no idea). Thus, I have to use this unit to transfer the data between the SRAM and my memory module. This means, in order to simulate, my testbench file will have to simulate the given unit! And this is hard..suppose I must try it, though...
first of all, whether to use a single process or a dual process type of FSM notation is a matter of preference (or company coding style rules). I find single process notation easier to write/read/manage.
your enable signal will have an effect on your memory code only after the next rising clock edge. the done signal related to the actual memory state will therefore be available one clock cycle after updating enable. I guess (and hope! but it's not visible in your posted code), your current_state<=next_state part of the FSM is synchronous! therefore your state machine will be in the SRAM_wait_read state by the time when done is updated!
btw: use a simulator! it will help to check the functionality!
thanks for adding the simulation view! strangely your done signal updates on neg. clock edge... in my simulation it updates on pos. edge; as it should, by the way!
to make the situation more clear I suggest, you move the done <= done_buf; line inside the "rising_edge-if" (this should be done anyhow when using synchronous processes!).

Resources