BlackHelicopter
Full Member level 2

I'm having trouble when CPOL = '1', a small glitch occurs on the clock line almost immediately after the CS (or SS) goes low. It also seems to be intermittent, sometimes my logic analyzer will decode just fine, other times it won't. I've attached my code. Could it be that there is a race condition of some sort? Maybe I should be controlling SCLK differently? I wonder if the logic analyzer is trigger off of noise of some sort since it's intermittent?:?:
I've attached some screenshots from the logic analyzer.
I've attached some screenshots from the logic analyzer.
Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SPI_controller is
generic(num_bits : positive := 8);
port(RESET_F : in std_logic;
SYS_CLK : in std_logic;
CSF : out std_logic;
SCLK : out std_logic;
CPHA : in std_logic;
CPOL : in std_logic;
MOSI : out std_logic;
MISO : in std_logic;
-- RD_DATA_OUT : out std_logic_vector(7 downto 0);
WR_DATA_IN : in std_logic_vector(7 downto 0);
START_XFR_F : in std_logic;
START_RCV_F : in std_logic;
BUSY : out std_logic
);
end SPI_controller;
architecture arch of SPI_controller is
type state_type is (IDLE, XMIT, RCV);
signal state : state_type;
-- clock generator
constant SYS_FREQ : integer := 50000000; -- 50MHz
constant SPI_FREQ : integer := 1000000; -- 1MHz
signal cnt_max : integer := (SYS_FREQ/SPI_FREQ)-1;
signal cnt_half : integer := (SYS_FREQ/SPI_FREQ)/2-1;
signal clk_cnt : integer range 0 to cnt_max;
signal spi_clk : std_logic;
signal i_spi_clk : std_logic;
signal prev_spi_clk : std_logic;
-- registers
signal wr_shift_reg : std_logic_vector(7 downto 0);
signal rd_shift_reg : std_logic_vector(7 downto 0);
signal rd_data_buf : std_logic_vector(7 downto 0);
signal i_wr_data : std_logic_vector(num_bits - 1 downto 0);
-- counters
signal word_size : unsigned(2 downto 0) := "111";
signal data_count : unsigned(2 downto 0);
-- auxiliary signals
signal i_csf : std_logic;
signal spi_start : std_logic;
signal start_spi_clk : std_logic;
signal i_busy : std_logic;
signal xmit_shift_en : std_logic;
begin
-- SPI enable
spi_start <= (not START_XFR_F) xor (not START_RCV_F);
-- assign signals
SCLK <= i_spi_clk;
CSF <= i_csf;
MOSI <= wr_shift_reg(0);
-- read data
--RD_DATA_OUT <= rd_shift_reg;
-- busy flag
BUSY <= i_busy;
---==========================================
-- Generate SPI Clk (SCLK Freq)
---==========================================
CLK_DIV : process (SYS_CLK, RESET_F, i_csf)
begin
if RESET_F = '0' then
spi_clk <= '0';
clk_cnt <= 0;
elsif SYS_CLK'event and SYS_CLK = '1' then
clk_cnt <= 0;
spi_clk <= '0';
if i_csf = '0' then
if (clk_cnt <= cnt_max) then
clk_cnt <= clk_cnt + 1;
else
clk_cnt <= 0;
end if;
if (clk_cnt <= cnt_half) then
spi_clk <= '0';
else
spi_clk <= '1';
end if;
end if;
end if;
end process;
---==========================================
-- State Machine
---==========================================
STATE_MACHINE : process (SYS_CLK, RESET_F, CPHA)
begin
if RESET_F = '0' then
i_csf <= '1';
i_busy <= '0';
data_count <= (others => '0');
rd_shift_reg <= (others => '0');
xmit_shift_en <= '0';
state <= IDLE;
elsif SYS_CLK'event and SYS_CLK = '1' then
prev_spi_clk <= spi_clk;
case state is
when IDLE =>
i_csf <= '1';
if spi_start = '1' then
if START_XFR_F = '0' and i_busy = '0' then
wr_shift_reg <= WR_DATA_IN;
i_busy <= '1';
i_csf <= '0';
state <= XMIT;
elsif START_RCV_F = '0' and i_busy = '0' then
i_busy <= '1';
i_csf <= '0';
state <= RCV;
end if;
end if;
when XMIT =>
if prev_spi_clk = '1' and spi_clk = '0' then
if (data_count < word_size) then
data_count <= data_count + 1;
else
data_count <= (others => '0');
rd_data_buf <= rd_shift_reg;
xmit_shift_en <= '0';
state <= IDLE;
end if;
end if;
-- CPHA Handler for SPI Clk
if CPHA = '0' and prev_spi_clk = '0' and spi_clk = '1' then
rd_shift_reg <= MISO & rd_shift_reg(7 downto 1);
elsif CPHA = '0' and prev_spi_clk = '1' and spi_clk = '0' then
wr_shift_reg <= '0' & wr_shift_reg(7 downto 1);
elsif CPHA = '1' and prev_spi_clk = '0' and spi_clk = '1' then -- Need to wait one clock first
if xmit_shift_en <= '0' then
xmit_shift_en <= '1';
else
wr_shift_reg <= '0' & wr_shift_reg(7 downto 1);
end if;
elsif CPHA = '1' and prev_spi_clk = '1' and spi_clk = '0' then
rd_shift_reg <= MISO & rd_shift_reg(7 downto 1);
end if;
when RCV =>
state <= IDLE;
end case;
end if;
end process;
---==========================================
-- CPOL Handler for SPI Clk
---==========================================
OUTPUT_PROC : process (SYS_CLK, RESET_F, CPOL)
begin
if RESET_F = '0' then
elsif SYS_CLK'event and SYS_CLK = '1' then
if CPOL = '1' then
i_spi_clk <= not spi_clk;
else
i_spi_clk <= spi_clk;
end if;
end if;
end process;
end arch;
Attachments
Last edited: