Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronic Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Register Log in

Problems with SPI controller, intermittent glitches on SCLK.

Status
Not open for further replies.

BlackHelicopter

Full Member level 2
Joined
Jun 3, 2010
Messages
128
Helped
13
Reputation
26
Reaction score
13
Trophy points
1,298
Activity points
2,159
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.

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:

Status
Not open for further replies.
Toggle Sidebar

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Top