FPGA: SPI Controller

The Serial Peripheral Interface (SPI) Bus is a full duplex synchronous serial communication standard. SPI is common in embedded applications due to it’s high throughput and relatively simple interface. This is a simple SPI controller implementation with an 8 bit word length and a single slave select line.

The ability to change data word length is built in to the code. Support for additional slave devices can be added with simple modifications.
An 8 bit counter from a previous example is used to provide input to the SPI controller. The Master Out Slave In (MOSI) line is connected directly back into the Slave Out Master In line. This allows comparison of the RX data line to the counter input. The logic analyzer screenshot shows that the data is clocked out, and back in, as expected. Further testing with a real SPI device will be required to verify the timings are adequate.

[cc lang="vhdl"]

ENTITY SPI_Controller IS
    wordLength : INTEGER := 8
  PORT (
    clock   : IN  STD_LOGIC;
    reset   : IN  STD_LOGIC;
    enable  : IN  STD_LOGIC;
    busy    : OUT STD_LOGIC;
    tx_data : IN  STD_LOGIC_VECTOR(wordLength-1 DOWNTO 0);
    rx_data : OUT STD_LOGIC_VECTOR(wordLength-1 DOWNTO 0);
    mode    : IN  STD_LOGIC_VECTOR(1 DOWNTO 0);

    sclk    : BUFFER STD_LOGIC;
    mosi    : OUT    STD_LOGIC;
    miso    : IN     STD_LOGIC;
    ss      : BUFFER STD_LOGIC
end SPI_Controller;

ARCHITECTURE structure of SPI_Controller IS
  SIGNAL clockCount : INTEGER RANGE 0 TO wordLength*2+2;
  SIGNAL txBuffer : STD_LOGIC_VECTOR(wordLength-1 DOWNTO 0);
  SIGNAL rxBuffer : STD_LOGIC_VECTOR(wordLength-1 DOWNTO 0);

  PROCESS(clock, reset)
    if reset = '1' then
      busy <= '1';
      sclk <= mode(1);
      sPhase <= mode(0);
      txBuffer <= tx_data;
    elsif (clock'EVENT and clock = '1') then
      if enable = '1' then
        if clockCount < wordLength*2 then
           if sclk = sPhase then
             mosi <= txBuffer(wordLength-1);
             txBuffer <= txBuffer(wordLength-2 DOWNTO 0) & '0';
             rxBuffer <= rxBuffer(wordLength-2 DOWNTO 0) & miso;
           end if;
           sclk<= NOT sclk;
           clockCount <= clockCount + 1;
        elsif clockCount = wordLength*2 then
          ss <= '1';
          busy <= '0';
          clockCount <= clockCount + 1;
        elsif clockCount = wordLength*2+1 then
          txBuffer <= tx_data;
          rx_data <= rxBuffer;
          clockCount <= clockCount + 1;
        elsif clockCount = wordLength*2+2 then
          mosi <= txBuffer(wordLength-1);
          ss <= '0';
          busy <= '1';
          clockCount <= 0;
        end if;
      end if;
    end if;
  end process;
end structure;

Serial Peripheral Interface Bus
Serial Peripheral Interface (SPI) Master (VHDL)
Related Posts:
FPGA: 4-Bit Counter
[download id=7]

Leave a Reply

Your email address will not be published. Required fields are marked *