Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16556 Discussions

State Machine for SPI Master/Slave Interface

Altera_Forum
Honored Contributor II
2,486 Views

http://www.alteraforum.com/forum/attachment.php?attachmentid=10118&stc=1  

 

Dear all, 

 

I am trying to write a state machine that checks to see if correct data is being received on the SPI link by lighting an LED. 

 

I have written a code but I am not sure if I am writing the state machine correctly, it definitely does not compile.  

 

Here is the code that I have written in relation to the test bench, please find the file attached. 

 

library IEEE; -- Reference for VHDL source code use IEEE.STD_LOGIC_1164.all; -- Package defined in the IEEE (Found in library IEEE) -- Entity declaration entity spi_statemachine is generic (n: positive := 16; -- Number of bits port (-- Master -- di_m: in std_logic_vector(15 downto 0); wren_m: in std_logic; -- Slave -- do_s: out std_logic_vector(15 downto 0); do_valid_s: out std_logic; -- Clock operation -- rst_i: in std_logic; clk_i: in std_logic; -- Output detection -- correct: out std_logic); end spi_statemachine; -- Architecture behaviour architecture detect of spi_statemachine is type state_type is (createData, writeData, delay, writeEnable, checkValid, receivedData, checkFinished, correctIndication); -- Enumeration type signal state: state_type; begin P1: process (clk_i, rst_i) -- Clock and reset variable dataLength: integer := n; -- Length of data variable count: integer := 1; begin if rst_i = '0' then -- Reset operation used initialize all signals to predetermined state state <= createData; elsif clk_i'event and clk_i = '1' then -- Signal attribute used to test for a change on a signal case state is when createData => state <= writeData; else state <= createData; end if; when writeData => di_m <= std_logic_vector(to_unsigned(dataLength,n)); -- Write data state <= delay; when delay => count := count + 1; if (count > 1) then state <= writeEnable; count := 0; else state <= delay; end if; when writeEnable => wren_m <= '1'; state <= checkValid; when checkValid => wren_m <= '0'; state <= receivedData; when receivedData => if do_s = di_m then state <= checkFinished; end if; when checkFinished => correct <= '1'; when others => null; end case; end if; end process; end detect; 

 

Any kind of help will be much appreciated.  

 

Kind regards,  

 

Deadman 

0 Kudos
10 Replies
Altera_Forum
Honored Contributor II
1,328 Views

1. you forgot to use the numeric_std library in your code (you're converting from integer to slv via an unsigned type). So put at the top 

 

use ieee.numeric_std.all;  

 

2. di_m abd wren_m are inputs , you cannot assign a value to input. (line 41, 54, 58). You can only assign values to outputs. 

3. The count variable is useless. The first time you're in the delay state it's value will be 2, and you'll go strait to write_enable (learn how signals work vs variables0 

4. You cannot read values from outputs (assuming you're trying to compile with VHDL 1993 code).  

 

 

I highly suggest you read the errors. They are usually very descriptive.
0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

 

--- Quote Start ---  

1. you forgot to use the numeric_std library in your code (you're converting from integer to slv via an unsigned type). So put at the top 

 

use ieee.numeric_std.all;  

 

2. di_m abd wren_m are inputs , you cannot assign a value to input. (line 41, 54, 58). You can only assign values to outputs. 

3. The count variable is useless. The first time you're in the delay state it's value will be 2, and you'll go strait to write_enable (learn how signals work vs variables0 

4. You cannot read values from outputs (assuming you're trying to compile with VHDL 1993 code).  

 

 

I highly suggest you read the errors. They are usually very descriptive. 

--- Quote End ---  

 

 

Thank you for your reply. 

 

I have read the errors and corrected them, the code is compiling. 

 

Do you know how to generate random numbers to inputs and outputs instead if fixed values? 

 

Kind regards, 

 

Deadman
0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

 

--- Quote Start ---  

Thank you for your reply. 

 

I have read the errors and corrected them, the code is compiling. 

 

Do you know how to generate random numbers to inputs and outputs instead if fixed values? 

 

Kind regards, 

 

Deadman 

--- Quote End ---  

 

 

There are two ways. 

1. If you need synthesisable pseudo random number, then google linear feedback shift register (LFSR). 

2. For simulation only, the ieee.math_real package has a procedure called "uniform" that generates pseudo random real values between 0.0 and 1.0. You can use these to scale any value you want. For example, a rand_int procedure in my personal testbench tools package: 

 

procedure rand_int( variable seed1, seed2 : inout positive; min, max : in integer; result : out integer) is variable rand : real; variable val_range : real; begin assert (max >= min) report "Rand_int: Range Error" severity Failure; uniform(seed1, seed2, rand); val_range := real(Max - Min + 1); result := integer( trunc(rand * val_range )) + min; end procedure;
0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

I am still trying to write a state machine that checks to see if correct data is being received between the input 'di_i' and the output 'do_o' but I get the following error message: 

 

Error (10409): VHDL Type Conversion error at spi_statemachine.vhd(89): converted type of object near text or symbol "std_logic_vector" must match integer type of target object  

 

I have highlighted the error in red below. I do not know why I am getting this error message, I have set 'std_logic_vector' and 'data_out' to 16 bits. 

 

library IEEE; -- Reference for VHDL source code use IEEE.STD_LOGIC_1164.all; -- Package defined in the IEEE (Found in library IEEE) use IEEE.numeric_std.all; -- Used to covert integer to std_logic_vector via unsigned type. -- Unsigned types represent postive values including zero. The compiler interprets each -- unsigned type as a binary number, with the digit of the left as the MSB (Most Significant Bit) -- Entity declaration entity spi_statemachine is -- Entity name -- Generics -- generic (n: positive := 16); -- Number of bits. Generic is used to specify parameters, for example, the -- length of data. port (-- Inputs -- di_i: in std_logic_vector(n-1 downto 0); -- Data in do_valid_o: in std_logic; -- Check if data is valid (No data setup glitches on the data transfer), -- valid during one clk_i rising edge -- Outputs -- do_o: out std_logic_vector(n-1 downto 0); -- Data out wren_i: out std_logic; -- Write port, valid during one clk_i rising edge -- Start operation -- start: in std_logic; -- Start state machine -- Clock operation -- rst_i: in std_logic; clk_i: in std_logic; -- Clock synchronicity with data -- Output indication -- correct: out std_logic); -- Check if data transmitted is correct end spi_statemachine; -- End entity -- Architecture behaviour architecture detect of spi_statemachine is -- Identifying the architecture type state_type is (createData, writeData, delay, writeEnable, checkValid, compareData, checkFinished, correctData); -- Enumeration types -- Signals signal state: state_type; -- State of the machine begin P1: process (clk_i, rst_i, start) -- Sensitivity list. The process wakes up when an event occurs -- on one of the signals in the sensitivity list. -- Variables -- -- Variables change immediately therefore 'rst_i' is used to stop this from happening. variable data: integer := 15; -- Data length. Integer is a data type that represents positive and negative -- whole numbers. variable error_rate: natural := 0; -- Incrementing error. Natural is a data type is used to represent natural -- (nonnegative) numbers. variable data_in: integer := 15; variable data_out: integer := 15; begin if rst_i = '1' then -- Reset operation used initialize all signals to predetermined state do_o <= (others => '0'); wren_i <= '0'; correct <= '0'; data := 15; error_rate := 0; state <= createData; data_in := 15; data_out := 15; elsif clk_i'event and clk_i = '1' then -- Signal attribute used to test for a change on a signal case state is when createData => if (start = '1') then -- Start state machine state <= writeData; else state <= createData; end if; when writeData => data_out := std_logic_vector(to_unsigned(data, n)); -- Write data state <= delay; when delay => state <= writeEnable; when writeEnable => wren_i <= '1'; state <= checkValid; when checkValid => if (do_valid_o = '1') then data_in := di_i; wren_i <= '0'; state <= compareData; else state <= writeEnable; end if; when compareData => if data_in = data_out then error_rate := error_rate-1; else error_rate := error_rate+1; state <= checkFinished; end if; when checkFinished => if (error_rate > 0) then correct <= '0'; else correct <= '1'; end if; end case; end if; end process; end detect; 

 

Kind regards, 

 

Deadman
0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

data_out is an integer variable. So is the data variable. So no need to convert to std_logic_vector.

0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

ps. data_out and data are always 15. What are you trying to do with these variables?

0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

 

--- Quote Start ---  

ps. data_out and data are always 15. What are you trying to do with these variables? 

--- Quote End ---  

 

 

I am trying to assign them to input 'di_i' and the output 'do_o' so that I can compare them, please see the code highlighted in red below. 

 

library IEEE; -- Reference for VHDL source code use IEEE.STD_LOGIC_1164.all; -- Package defined in the IEEE (Found in library IEEE) use IEEE.numeric_std.all; -- Used to covert integer to std_logic_vector via unsigned type. -- Unsigned types represent postive values including zero. The compiler interprets each -- unsigned type as a binary number, with the digit of the left as the MSB (Most Significant Bit) -- Entity declaration entity spi_statemachine is -- Entity name -- Generics -- generic (n: positive := 16); -- Number of bits. Generic is used to specify parameters, for example, the -- length of data. port (-- Inputs -- di_i: in std_logic_vector(n-1 downto 0); -- Data in do_valid_o: in std_logic; -- Check if data is valid (No data setup glitches on the data transfer), -- valid during one clk_i rising edge -- Outputs -- do_o: out std_logic_vector(n-1 downto 0); -- Data out wren_i: out std_logic; -- Write port, valid during one clk_i rising edge -- Start operation -- start: in std_logic; -- Start state machine -- Clock operation -- rst_i: in std_logic; clk_i: in std_logic; -- Clock synchronicity with data -- Output indication -- correct: out std_logic); -- Check if data transmitted is correct end spi_statemachine; -- End entity -- Architecture behaviour architecture detect of spi_statemachine is -- Identifying the architecture type state_type is (createData, writeData, delay, writeEnable, checkValid, compareData, checkFinished, correctData); -- Enumeration types -- Signals signal state: state_type; -- State of the machine begin P1: process (clk_i, rst_i, start) -- Sensitivity list. The process wakes up when an event occurs -- on one of the signals in the sensitivity list. -- Variables -- -- Variables change immediately therefore 'rst_i' is used to stop this from happening. variable data: integer := 15; -- Data length. Integer is a data type that represents positive and negative -- whole numbers. variable error_rate: natural := 0; -- Incrementing error. Natural is a data type is used to represent natural -- (nonnegative) numbers. variable data_in: integer := 15; variable data_out: integer := 15; begin if rst_i = '1' then -- Reset operation used initialize all signals to predetermined state do_o <= (others => '0'); wren_i <= '0'; correct <= '0'; data := 15; error_rate := 0; state <= createData; data_in := 15; data_out := 15; elsif clk_i'event and clk_i = '1' then -- Signal attribute used to test for a change on a signal case state is when createData => if (start = '1') then -- Start state machine state <= writeData; else state <= createData; end if; when writeData => data_out := std_logic_vector(to_unsigned(data, n)); -- Write data state <= delay; when delay => state <= writeEnable; when writeEnable => wren_i <= '1'; state <= checkValid; when checkValid => if (do_valid_o = '1') then data_in := di_i; wren_i <= '0'; state <= compareData; else state <= writeEnable; end if; when compareData => if data_in = data_out then error_rate := error_rate-1; else error_rate := error_rate+1; state <= checkFinished; end if; when checkFinished => if (error_rate > 0) then correct <= '0'; else correct <= '1'; end if; end case; end if; end process; end detect; 

 

Kind regards, 

 

Deadman
0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

di_i is a std_logic_vector, so to assign it to the data in variable you need to type convert it: 

 

data_in <= to_integer( unsigned( di_i) ); 

 

And you still have the same problem that you're doing an unnecessary (and illegal) type conversion for the data_out assignment from the data variable. 

 

There are other type conversion problems. I suggest fix the syntax errors first before worry about the functionality.
0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

I have fixed the syntax errors and my state machine is compiling. 

 

My state machine is the following code: 

 

library IEEE; -- Reference for VHDL source code use IEEE.STD_LOGIC_1164.all; -- Package defined in the IEEE (Found in library IEEE) use IEEE.numeric_std.all; -- Used to covert integer to std_logic_vector via unsigned type. Unsigned types represent postive -- values including zero. The compiler interprets each unsigned type as a binary number, with the -- digit of the left as the MSB (Most Significant Bit). -- Entity declaration entity spi_statemachine is -- Entity name. -- Generics -- generic (n: positive := 16); -- Number of bits. Generic is used to specify parameters, for example, the length of data. port (-- Inputs -- do_o: in std_logic_vector(n-1 downto 0); -- Data in. do_valid_o: in std_logic; -- Check if data is valid (No data setup glitches on the data transfer), valid during one -- clk_i rising edge. -- Outputs -- di_i: out std_logic_vector(n-1 downto 0); -- Data out. wren_i: out std_logic; -- Write port, valid during one clk_i rising edge. -- Start operation -- start: in std_logic; -- Start state machine. -- Clock operation -- rst_i: in std_logic; clk_i: in std_logic; -- Clock synchronicity with data. -- Output indication -- correct: out std_logic); -- Check if data transmitted is correct. end spi_statemachine; -- End entity -- Architecture behaviour architecture detect of spi_statemachine is -- Identifying the architecture. type state_type is (createData, writeData, delay, stopwriteEnable, checkValid, compareData, checkFinished); -- Enumeration types. -- Signals and types signal state: state_type; -- State of the machine. type int_array is array (integer range <>) of integer; begin P1: process (clk_i, rst_i, start) -- Sensitivity list. The process wakes up when an event occurs on one of the signals -- in the sensitivity list. -- Variables -- (Variables change immediately therefore 'rst_i' is used to stop this from happening) variable error_rate: natural := 0; -- Incrementing error. Natural is a data type is used to represent natural -- (nonnegative) numbers. variable data_in: std_logic_vector(n-1 downto 0); -- Data length. Integer is a data type that represents positive and -- negative whole numbers. variable data_out: std_logic_vector(n-1 downto 0); variable random_data: int_array(0 to 15); variable count: integer := 0; variable i: integer := 0; begin if rst_i = '1' then -- Reset operation used initialize all signals to predetermined state. -- Initial values for all outputs, variables and signals -- di_i <= (others => '0'); wren_i <= '0'; correct <= '0'; error_rate := 0; data_in := (others => '0'); data_out := (others => '0'); count := 0; i := 0; random_data(0) := 14492; random_data(1) := 9335; random_data(2) := 10648; random_data(3) := 21153; random_data(4) := 14657; random_data(5) := 10583; random_data(6) := 10651; random_data(7) := 18398; random_data(8) := 12598; random_data(9) := 30086; random_data(10) := 6444; random_data(11) := 25436; random_data(12) := 25025; random_data(13) := 27533; random_data(14) := 3525; random_data(15) := 31968; state <= createData; elsif clk_i'event and clk_i = '1' then -- Signal attribute used to test for a change on a signal. case state is -- When state 'createData' and if 'start' equals '1', then state is 'writeData' and 'i' increments count from -- 0 to 15. If 'i' increments count above 15 then 'i' equals 0 and otherwise state is 'createData'. when createData => if (start = '1') then state <= writeData; i := i + 1; if (i > 15) then i := 0; end if; else state <= createData; end if; -- 'random_data' is converted into 'std_logic_vector' and is then is written in to 'data_out' and 'di_i'. -- 'random_data' will be counted (i) up to 15 (n). when writeData => data_out := std_logic_vector(to_unsigned(random_data(i), n)); di_i <= std_logic_vector(to_unsigned(random_data(i), n)); state <= delay; when delay => count := count + 1; if (count > 1) then state <= stopwriteEnable; wren_i <= '1'; -- Starts transmission. count := 0; else state <= delay; end if; when stopwriteEnable => state <= checkValid; -- If 'do_valid_o' equals '1' then 'do_o' gets the value of 'data_in'. 'wren_i' equals '0' as it only as -- only equals '1' for one clock cycle. when checkValid => if (do_valid_o = '1') then data_in := do_o; wren_i <= '0'; state <= compareData; else state <= checkValid; end if; -- If 'data_in' equals 'data_out' and the error rate is below '0' then there is no error, if the error -- rate is above '0' then there is an error. when compareData => if data_in = data_out then error_rate := error_rate - 1; else error_rate := error_rate + 1; end if; state <= checkFinished; -- If the error rate is greater than '0' then correct equals '0', otherwise correct equals '1'. when checkFinished => if (error_rate > 0) then correct <= '0'; else correct <= '1'; end if; end case; end if; end process; end detect; 

 

Kind regards, 

 

Deadman
0 Kudos
Altera_Forum
Honored Contributor II
1,328 Views

I am trying to write a test bench for my state machine but I don't seem to be getting the correct results. 

 

The test bench for my state machine is the following code: 

 

library IEEE; use IEEE.STD_LOGIC_1164.all; -- Entity -- entity spi_statemachine_test is generic (n: positive := 16); end spi_statemachine_test; -- Component declaration -- architecture behaviour of spi_statemachine_test is component spi_statemachine port (do_o: in std_logic_vector(n-1 downto 0); do_valid_o: in std_logic; di_i: out std_logic_vector(n-1 downto 0); wren_i: out std_logic; start: in std_logic; rst_i: in std_logic; clk_i: in std_logic; correct: out std_logic); end component; -- Signals -- signal clk_i: std_logic; signal start: std_logic; signal rst_i: std_logic; signal wren_i: std_logic; signal di_i: std_logic_vector(n-1 downto 0); signal do_valid_o: std_logic; signal do_o: std_logic_vector(n-1 downto 0); signal correct: std_logic; -- Clock period -- constant clk_period: time := 10 ns; -- Compomemt instantiation -- begin C: spi_statemachine port map(di_i => di_i, wren_i => wren_i, do_o => do_o, do_valid_o => do_valid_o, start => start, rst_i => rst_i, clk_i => clk_i, correct => correct); -- Clock -- clk_process_slave: process begin clk_i <= '0'; wait for clk_period/2; clk_i <= '1'; wait for clk_period/2; end process clk_process_slave; -- Stimulus -- stimulus: process is variable data_v: std_logic_vector(n-1 downto 0); begin start <= '1'; rst_i <= '1'; do_valid_o <= '0'; do_o <= (others => '0'); wait for 15ns; rst_i <= '0'; wait until wren_i'event and wren_i = '1'; data_v := di_i; wait until clk_i'event and clk_i = '1'; do_o <= data_v; wait until clk_i'event and clk_i = '1'; wait until clk_i'event and clk_i = '1'; do_valid_o <= '1'; wait until clk_i'event and clk_i = '1'; do_valid_o <= '0'; wait until clk_i'event and clk_i = '1'; assert correct <= '0' report "There in an incorrect value on the output LED)" severity error; wait for 5ns; wait; end process stimulus; end behaviour; 

 

The following screenshot is of my simulation, 'correct' should be high because the correct data is being received between 'di_i' and 'do_o'. 

 

https://www.alteraforum.com/forum/attachment.php?attachmentid=10201  

 

Kind regards, 

 

Deadman
0 Kudos
Reply