Need Help With SPI controller (where CPHA = 1)

Status
Not open for further replies.

BlackHelicopter

Full Member level 2
Joined
Jun 3, 2010
Messages
137
Helped
13
Reputation
26
Reaction score
16
Trophy points
1,298
Visit site
Activity points
2,207
I'm having trouble with my code when CPHA = '1'. I believe I need to wait a clock pulse before I shift data in the shift register, which I'm not doing. There's probably an easy fix to this but right now I don't see it, can someone show me the right way to do this? (I'm rather new)

I also have a screenshot from a logic analyzer for reference, CPHA = 1 here and the bottom data should be x28 not x14.

Here's the code:

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;
		 CSF		 : out std_logic;
		 SYS_CLK	 : in 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_out : out std_logic_vector(7 downto 0);
--		 TEST_POINT  : out std_logic;
		 START_XFR_F : in std_logic;
		 SCLK		 : out std_logic
		 );
end SPI_controller;

architecture arch of SPI_controller is
	type state_type is (IDLE, XMIT, RCV);
	signal state : state_type;
	signal count_max  	   : integer := 20;
	signal count_half      : integer := count_max/2;
	signal clk_count	   : integer := 0;
	signal spi_clk		   : std_logic;
	signal i_spi_clk	   : std_logic;
	signal i_csf		   : std_logic;
	signal start_spi_clk   : std_logic;
--	signal i_test_point    : std_logic;
	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 word_size 	   : unsigned(2 downto 0) := "111";
	signal data_count	   : unsigned(2 downto 0);
	signal i_wr_data	   : std_logic_vector(num_bits - 1 downto 0);
	signal spi_start	   : std_logic;
	signal prev_spi_clk    : std_logic;
	signal i_busy		   : std_logic;
	
	
begin

--TEST_POINT <= i_test_point;
SCLK <= i_spi_clk;
CSF <= i_csf;

rd_data_out <= rd_shift_reg;
wr_data_out <= wr_shift_reg;

MOSI <= wr_shift_reg(0);

---==========================================
--  Generate SPI Clk (SCLK Freq)
---==========================================
CLK_DIV : process (SYS_CLK, RESET_F, i_csf)
	begin
		if RESET_F = '0' then
			spi_clk <= '0';
			clk_count <= 0;
		elsif SYS_CLK'event and SYS_CLK = '1' then
			clk_count <= 0;
			spi_clk <= '0';
			if i_csf = '0' then
				if (clk_count < count_max - 1) then
					clk_count <= clk_count + 1;
				else
					clk_count <= 0;
				end if;
				if (clk_count < count_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_test_point <= '0';
		state <= IDLE;
		rd_shift_reg <= (others => '0');
		wr_shift_reg <= x"28";
		data_count <= (others => '0');
		i_busy <= '0';
	elsif SYS_CLK'event and SYS_CLK = '1' then
		prev_spi_clk <= spi_clk;
		if prev_spi_clk = '0' and spi_clk = '1' then
--			i_test_point <= '1'; 
		else
--			i_test_point <= '0';
		end if;
		case state is
			when IDLE =>
				i_csf <= '1';
				if START_XFR_F = '0' and i_busy = '0' then
					i_busy <= '1';
					i_csf <= '0';
					state <= XMIT;
				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;
						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
					wr_shift_reg <= '0' & wr_shift_reg(7 downto 1);
				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 =>
				
		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

  • SPI Timing.png
    6 KB · Views: 82

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…