SPI interface works in simulation but not on actual hardware - vhdl

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;

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;

Synthetizable delay in VHDL FSM state

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?)

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.

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;

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