• 0

SPI slave in VHDL


Josef

Question

Hello everyone,

     I have question about possibility of realising SPI slave on FPGA using VHDL. I know that there is some open cores, free SPI libraries in VHDL, etc., but I think that do it own way gives experiences. When I coding SPI master, it was a little bit trivial, but now I try to solve SPI slave and getting into some trouble.

My question is about how is the best practice for detecting falling edges of SS (in code below CS) signal and then SCK signal for setting MISO signal, when I am using mode 0 (CPHA = 0 and CPOL = 0). I saw some sample codes of SPI slave in VHDL where author using some system clock what frequency was more greater than SCK and between two rising or falling edges of the system clock the author detected changes of relevant signal in actual state of finite state machine and doing some action, but I think there always be some uncertain delay between system clock and changes of signals what comes from SPI master and I think that some integrated circuits what using some form of serial access (not sure that SPI, but I think it) also don't have any own system clock provided by for example crystal. So I tried to code with some logic functions what leads to possibility of detecting falling edge of single signal, but it depends both on SS and SCK, but problem is when I try to detecting SS for deactivate the device and reseting the state, I cannot do it, because ISE gives me error: Cannot have such operands. When I don't detect it, I will not be able get the slave into predicated state between transaction frames if some error in communication occured, for example crosstalk or master for example try to read 9 bits, etc... I also tried for dividing into two processes (first one for falling edge of SS, second one for falling edge of SCK), but in that case I met with problem of multiple drivers on single net MISO...

So I have question, if is it possible to do it without system clock, or no?

Thanks in advance for your answer

Best regards

Josef

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    22:25:14 11/22/2020 
-- Design Name: 
-- Module Name:    main - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity SPI_Slave_Transmitter_not_CPHA is
    port( RECEIVE : in STD_LOGIC;
            DATA_IN : in STD_LOGIC_VECTOR(7 downto 0);
            CSPOL : in STD_LOGIC;
            CS : in STD_LOGIC;
            MISO : out  STD_LOGIC;
            SCK : in STD_LOGIC);
end SPI_Slave_Transmitter_not_CPHA;

architecture Behavioral of SPI_Slave_Transmitter_not_CPHA is
shared variable state : INTEGER := 0;
signal preMISO : STD_LOGIC := 'Z';
signal innerCS : STD_LOGIC := '0';
signal innerSCK : STD_LOGIC := '0';
    
begin
    innerCS <= not (CS xor CSPOL);
    innerSCK <= ((innerCS) or SCK);
    
    process(RECEIVE,innerCS,innerSCK,DATA_IN)
    begin
        if(innerCS = 1 or RECEIVE = '0') then
            preMISO <= 'Z';
            STATE := 0;
        elsif(falling_edge(innerSCK)) then
            case STATE is
                when 0 =>    
                    preMISO <= DATA_IN(0);
                when 1 =>    
                    preMISO <= DATA_IN(1);
                when 2 =>    
                    preMISO <= DATA_IN(2);
                when 3 =>    
                    preMISO <= DATA_IN(3);
                when 4 =>    
                    preMISO <= DATA_IN(4);
                when 5 =>    
                    preMISO <= DATA_IN(5);
                when 6 =>    
                    preMISO <= DATA_IN(6);
                when 7 =>
                    preMISO <= DATA_IN(7);
                when 8 =>
                    preMISO <= 'Z';
                when others =>
                    preMISO <= 'Z';
            end case;
            if(STATE < 8) then
                STATE := STATE + 1;
            else
                STATE := 0;
            end if;
        end if;
    end process;
    MISO <= preMISO;
end Behavioral;

Link to post
Share on other sites

7 answers to this question

Recommended Posts

  • 0
1 hour ago, Josef said:

My question is about how is the best practice for detecting falling edges of SS

There's no good answer to your question because it depends on what your personal specification for an SPI slave is. You did start with that didn't you?

For low speed SPI ( <25 MHz ) I've always used a 4x or higher local clock to derive or sample the SPI signals. This allows me to set timing constraints in the HDL rather than in the place and route. You don't have to do it that way. There can be reasons not to in fact. If your SCLK runs at 100 MHz and your logic is clocked with the same clock there are limited ways to detect certain conditions in real time. One possibility it to use multiple derived clocks with phase offsets. The problem with that is that most FPGA devices have limited clocking resources and if you have a lot of interfaces requiring a lot of clocks this becomes a problem.

Another question to decide is whether or not your SPI has to detect what mode it is supposed to operate in in-situ or is set by generics. It's rare that PSI modes change on the fly.

it's you IP so you can write your own specifications. My advice, if you are struggling, is to relax your specifications until you get it working and then add the difficulty later. Sometimes this requires a redesign, but rarely a complete do-over as you have past experience to work with.

It's one thing to write IP that completely implements an industry specification completely and another that just does what is needed in most cases. Either way can be fine. I just depends on what you are doing with it. Just be sure to document conditions that your IP doesn't cover.

BTW, just [tried and failed] used the idea of abandoning nomenclature that some finds as offensive. I've done that here and I have to say that it makes addressing your question more difficult. Personally, enslavement is a concept that I find horrific in terms of human interaction but has no moral implications for mechanical or logic interaction for me. But my point of view isn't what matters to someone who can't make that distinction. it's problematic regardless of your point of view but this is a real discussion among companies and standards bodies. I just mention this as something to think about; humanity hasn't progressed to the point where the concept is a relic of past ages and merely historical observation. Personally, I think of the SPI and I2C specifications in terms as they originally appeared because I don't believe that they referred to a particular form of institutional evil. I don't find it to be a great burden to avoid using specific terms that other may find offensive.

 

Edited by zygot
Link to post
Share on other sites
  • 0

Thanks for your answer.

My idea was to make own component SPI slave what can be by user setup into all 4 modes (combinations of CPOL and CPHA), also I added as in posted code CSPOL for setting what CS level is idle. Yeah, I know that my implementation is not usual as other implementation is (other implementation makes single component for all SPI, use one register what is shifted by SCK, etc.) but I can do with parallel data bus everything in higher entity and so on. I didn't try to think about automatic detection of mode by transaction, but this is also interesting idea, what I maybe try to do in future, if I solve this, but can be changed by input bits (on Basys 2 board by switches). And SPI master I coded this way of specification on oscilloscope it works correctly, but on SPI slave I'm stuck on transmitting when CPHA is 0, because there is difficulty of two signals what I need detect for falling edges and on this event changes data on MISO data line. If I will detect only falling edges of SCK, then I will transfer only lower 7 bits, because the LSB of the byte must be settled on MISO on falling edge of SS and on first falling edge of SCK is settled the second LSB bit of the byte, what I currently don't know, how write in VHDL and also syntezable.

Link to post
Share on other sites
  • 0
2 hours ago, Josef said:

what I currently don't know, how write in VHDL

In FPGAs clocks are distinct and separate from logic signals. In your code you are clocking your process with a logic signal. This is not a good practice. You should clock logic with a clock signal. The tools do synthesis and place and route based on a timing analysis between clocks and the registers that are clocked. Your innerSCK makes for a poor clock in FPGA architectures and tools. If you have one of your SPI entities in one FPGA device controlling another SPI entity in another FPGA device this is a problem.

In Xilinx Series7 FPGA devices clocks have their own routing resources and there are rules for using them. Also, not every IO pin can be used as a clock input.

For low speed SPI you are better off hiding the fact that you want to use SPI SCLK as a clock from the tools and control timing by using a system clock that is much higher in frequency than SCLK to clock your logic. This is for SCLK driver IP and SCLk receiver IP. If you can't do that then your are better off deriving SCLK from a system clock using an MMCM or PLL and providing the tools with the proper timing constraints, at least for the IP that drives SCLK. For your IP that receives SCLK you would then have to use a clock capable IO pin for SCLK and then you can either use it to clock logic, or create one or more derived clocks using an MMCM if you need to detect phasing.

The rules are a bit different for ASIC design.

Link to post
Share on other sites
  • 0

Thank you for answer.

OK, I met with warning about clock - clock dedicated route in past time in another designs, paradoxically not in this. I standardly used system clock and timing derived from it in another designs, but in SPI slave design I hesitated about using system clock or not and the reasons they made me uncertain was accurate detection of falling edges of signals (SCK and SS) and also some ICs what communicate by SPI or some variants of it don't have own system clock (for example R2R DACs), but also there can be internal RC oscillator, internal XTAL, or something like that.

So, if I fully understand it, the best practice is using some system clock (entity will have also signal CLK).  And in my code, the first if case will be controlled by RECEIVE, what will be asynchronous combined "ENABLE" or "!RESET" and second if case will detect rising or falling edge of CLK and in that if block I will make finite state machine, where I will "manually" handle changes on signals SS and SCK, respectively innerCS and innerSCK and depending on them I will change the actual state of FSM, am I right?

Best regards

Josef

Link to post
Share on other sites
  • 0

I don't want to lead, or mislead, you in your design approach.

You should use either an external clock or MMCM/PLL derived clock for all synchronous logic in your FPGA designs.

For your project you have a problem to solve if you want to use an SCLK input as a clock. Even if it is a derived clock it is not always running, and can have an inactive state of either '1' or '0'. As long as your system clocks are higher in frequency than SCLK it's possible to detect edges and phase relationships for the SPI signals. How you do this and what the requirements are for the system clocks and SCLK is for you to work out. If I gave you a design strategy then it wouldn't be your design, right?

Whatever the rules are for the device your are working with there's a way to resolve difficult problems. It's up to you to decide how difficult you want to make that effort. 

Link to post
Share on other sites
  • 0

OK, thanks.

Information provided by you

6 minutes ago, zygot said:

You should use either an external clock or MMCM/PLL derived clock for all synchronous logic in your FPGA designs.

As long as your system clocks are higher in frequency than SCLK it's possible to detect edges and phase relationships for the SPI signals.

is enough for me. And it's what I looked for.

Best regards

Josef

Link to post
Share on other sites
  • 0

hi zygot hope you are doing well..I'm here because  i had read one of your post related to lan8710a phy ethernet interfacing with a fpga,in my case its a spartan 6 lx75 fpga

i have new to this field and  also i had come across ethernet ip core in ISE 14.7  and xps with its own lwip and ethernet configuration .But the problem is i dont know how to start and where to start from. IF YOU DONT MIND CAN YOU SHARE YOUR CODE OR GUIDE ME ..HOW CAN I CONTACT YOU ..???

 

PARDON ME FOR THIS  INTERRUPTION FOR THIS THREAD.

 

THANK YOU

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now