You are on page 1of 5

Chapter 15 ■ Two-Way Communications with Your Raspberry Pi: SPI

Figure 15-12.  SPI clock cycle counter VHDL code

15.3.3.3 SPI Data in 8-Bit Shift Register


The Raspberry Pi SPI master changes the MOSI data line when SPI clock is falling edge, which means the
MOSI data is not stable at that time. We wait a half clock cycle to let the MOSI stabilize so we should shift
in the data when SPI clock is rising edge, which is stable for shift data in. Figure 15-13 shows the spi_in_p
process shift rspi_mosi data in to the spi_datain_shifter register when spi_clk_rising_edge is equal to '1.' We
don't need to clear the spi_datain_shifter because we only use it when the spi_clk_count is equal to 8.

Figure 15-13.  SPI data in 8-bit shift register VHDL code

15.3.3.4 Read/Write Cycle
Once the first eight bits of SPI DATA are in the shift register (spi_datain_shifter), we can design it is a read
cycle or write cycle. We need to make this decision when the spi_clk_counter is equal to 8 and the spi_clk_
falling_edge is '1.' This allows us enough time before the ninth rising clock edge comes in. Figure 15-14
shows the VHDL code that will set the spi_write_cycle equal to '1' when we receive a byte value of 0x00 in the
first byte from the Master SPI. The spi_write_cycle value will remain stable until the slave select is equal to '1'
which is when the cycle is finished.

355
Chapter 15 ■ Two-Way Communications with Your Raspberry Pi: SPI

Figure 15-14.  Read/write cycle VHDL code

15.3.3.5 Write Input Process


The second eight bits from MOSI will continue to shift in to the spi_datain_shifter after read_write_cycle_p
decides whether the current cycle is a write or read cycle. When the current cycle is a write cycle (spi_write_
cycle = '1') and all of the second eight bits are shifted in to the spi_datain_shifter (line 112 in Figure 15-15),
write_input_p will generate a pulse on wr_enable and copy the spi_datain_shifter 8-bit data to the data_out
port. data_out will keep the value until the next write cycle. Figure 15-15 shows one of the ways to create this
write input process.

Figure 15-15.  Write input process VHDL code

15.3.3.6 Read Output
If the first byte from Raspberry Pi, which is stored in spi_datain_shifter, is equal to 0x01(hex), which means
read cycle, then it is time to provide a byte to Raspberry Pi. It copies the FPGA data (data_in) from other logic
to an 8-bit shift register (spi_dataout_shifter).
In Figure 15-16, lines 130-131, shift the data to the left (high bit) when SPI clock is falling edge after it
copied the FPGA data_in to the shift register. Line 136 connects the most significant bit of the shift register
(bit 7) to the rspi_miso pin which connected to Raspberry Pi 3 SPI data input.

356
Chapter 15 ■ Two-Way Communications with Your Raspberry Pi: SPI

Figure 15-16.  Read output process VHDL code

Listing 15-1 provides the whole spi_slave module VHDL design file.

Listing 15-1.  spi_slave.vhd


library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity spi_slave is
port(
-- general purpose
sys_clock : in std_logic; -- system clock
sys_rst : in std_logic; -- system reset active low
-- serial I/O side
rspi_sclk : in std_logic; -- SPI clock from raspberry SPI Master
rspi_ss : in std_logic; -- SPI chip select from raspberry SPI Master
rspi_mosi : in std_logic; -- SPI data from raspberry SPI Master
rspi_miso : out std_logic; -- SPI data to raspberry SPI Master
-- Register read/write interface
wr_enable : out std_logic; -- Write Enable: Data_out data is valid
data_out : out std_logic_vector(7 downto 0); -- 8 Bit data from raspberry
data_in : in std_logic_vector(7 downto 0) -- 8 bit data read back
);
end entity;

--=============================================================================
-- architecture declaration
--=============================================================================

architecture arch of spi_slave is

signal spi_clk_rising_edge : std_logic;


signal spi_clk_falling_edge : std_logic;
signal spi_write_cycle : std_logic;
signal spi_clk_dly_line : std_logic_vector(2 downto 0);

357
Chapter 15 ■ Two-Way Communications with Your Raspberry Pi: SPI

signal spi_clk_count : unsigned(5 downto 0); -- count # of clock cycles


signal spi_datain_shifter : std_logic_vector(7 downto 0);
signal spi_dataout_shifter : std_logic_vector(7 downto 0);

begin

-- edge detection process


-- This method require sys_clock is at least 4 times faster than spi clock
spi_clk_edge_detect_p : process(sys_clock)
begin
if(rising_edge(sys_clock)) then
-- delay spi_clk three system clock cycles
spi_clk_dly_line <= spi_clk_dly_line(1 downto 0) & rspi_sclk;

-- Rising edge detected when two clock cycles low and then two clock cycles
High
if(spi_clk_dly_line(2) = '0' and spi_clk_dly_line(1) = '0' and
spi_clk_dly_line(0) = '1' and rspi_sclk = '1') then
spi_clk_rising_edge <= '1';
else
spi_clk_rising_edge <= '0';
end if;
-- Falling edge detected when two clock cycles high and then two clock
cycles Low
if(spi_clk_dly_line(2) = '1' and spi_clk_dly_line(1) = '1' and
spi_clk_dly_line(0) = '0' and rspi_sclk = '0') then
spi_clk_falling_edge <= '1';
else
spi_clk_falling_edge <= '0';
end if;
end if;
end process;

spi_clock_cycles_counter_p : process(sys_clock)
begin
if(rising_edge(sys_clock)) then
if(rspi_ss = '1') then -- reset counter to zero when not chip select
spi_clk_count <= (others =>'0');
else
if(spi_clk_rising_edge = '1') then -- every rising edge add one
if(spi_clk_count = 16) then
spi_clk_count <= (others => '0');
else
spi_clk_count <= spi_clk_count + 1;
end if;
end if;
end if;
end if;
end process;

358
Chapter 15 ■ Two-Way Communications with Your Raspberry Pi: SPI

-- Every time SPI chip select go low, it will have 16 bit data (Read/Write(8bit)+data(8it)
spi_in_p : process(sys_clock)
begin
if(rising_edge(sys_clock)) then
if(spi_clk_rising_edge = '1') then
spi_datain_shifter <= spi_datain_shifter(6 downto 0) & rspi_mosi;
end if;
end if;
end process;

read_write_cycle_p: process(sys_clock, sys_rst)


begin
if(sys_rst = '0') then
spi_write_cycle <= '0';
elsif(rising_edge(sys_clock))then
if(rspi_ss = '1') then
spi_write_cycle <= '0';
elsif(spi_clk_count = 8 and spi_datain_shifter = x"00" and spi_clk_falling_
edge = '1') then
spi_write_cycle <= '1';
end if;
end if;
end process;

write_input_p: process(sys_clock, sys_rst)


begin
if(sys_rst = '0') then
wr_enable <= '0';
data_out <= (others =>'0');
elsif(rising_edge(sys_clock))then
if(rspi_ss = '1') then
wr_enable <= '0';
elsif( spi_clk_count = 16 and spi_write_cycle = '1' and spi_clk_falling_edge =
'1') then
wr_enable <= '1';
data_out <= spi_datain_shifter;
else
wr_enable <= '0';
end if;
end if;
end process;

read_output_p : process(sys_clock, sys_rst)


begin
if(sys_rst = '0') then
spi_dataout_shifter <= (others => '0');
elsif(rising_edge(sys_clock))then

if(spi_clk_count = 8 and spi_datain_shifter = x"01" and spi_clk_falling_edge = '1')


then
spi_dataout_shifter <= data_in;

359

You might also like