kk_omnisys

spi.vhd error?

13 posts in this topic

Hello All

 

I've been working on some external SPI hardware that wants new data on falling edge of SCK and samples at rising edge.

 

I've hooked up my Papilio to a logic analyzer to watch the SPI stream, but to my dismay it seems that the MOSI only clocks out data on rising edge of SCK and the SPI blocks do not listen to the samprise input of spi.vhd

 

I'm just wondering if this is intentionally so or if it is in error?

 

Regards

Kalle

Share this post


Link to post
Share on other sites

Hello Kalle,

 

What SPI code are you using? Is it from the ZPUino, the AVR8, or some standalone code?

 

Thanks,

Jack.

Share this post


Link to post
Share on other sites

Hi Jack

 

I'm using the standard spi.vhd from zpu\hdl\zpuino\spi.vhd

 

In particular I believe that the process which shifts the MOSI on lines 107-122 should also depend on samprise and clkfall and not just clkrise.

 

Currently it states the following

  process(ready_q, clkrise)  begin    if ready_q='0' and clkrise='1' then      do_shift<='1';    else      do_shift<='0';    end if;  end process;

I propose that it should say something like

process(ready_q, clkrise, clkfall)begin    if ready_q='0' and samprise = '1' and clkrise='1' then		do_shift <= '1';	elsif ready_q='0' and samprise = '0' and clkfall = '1' then		do_shift <= '1';    else		do_shift<='0';    end if;end process;

But then we end up with something that does not align correctly, the data is shifted on falling edge of SCK, but the first bit is not shifted until the first clock has passed, i.e you try to send 0x80 for example and the logic analyzer takes this as 0x40...

 

Regards

Share this post


Link to post
Share on other sites

On second thought I think that it really should say

process(ready_q, clkrise, clkfall)begin    if ready_q='0' and samprise = '0' and clkrise='1' then		do_shift <= '1';	elsif ready_q='0' and samprise = '1' and clkfall = '1' then		do_shift <= '1';    else		do_shift<='0';    end if;end process;

So that data is shifted on the opposite edge of the sampling edge... But I might be wrong..

Share this post


Link to post
Share on other sites

Hello Kalle,

 

If you set SPICPOL=1 and SPISRE=0 you will get the expected behavior: the data will be clocked on the falling edge, and sampled on the rising edge.

 

The VHDL model is correct. The clkrise/fall will be swapped when generating the clock.

Share this post


Link to post
Share on other sites

Here's a screenshot in simulation, with SPICPOL=1 and SPISRE=0:

 

spi-inverted.png

 

As you can see, data (MOSI) is clocked out on falling edge, and the sample event is just before the rising edge.

Share this post


Link to post
Share on other sites

I agree that the signals look like they align good enough for the different SPI modes, but:

 

I think that the data should be pushed out so that the MOSI data is already on the data line half a SCK cycle before the leading edge on mode 0,0 because if the data is pushed at the same time as SCK is driven high there will be racing conditions occuring when interfacing with external hardware.. 

 

I have attached the actual waveform captured with my logic analyzer as well as a template of how I thought that mode 0,0 should look

 

Best Regards

Kalle

post-36776-0-42774600-1381831940_thumb.j

post-36776-0-96598700-1381831992_thumb.j

Share this post


Link to post
Share on other sites

I think I understood now. Your problem is with CPHA (phase), not with CPOL.

 

So, with CPHA, you want the output to occur "before" the first rising edge.

 

Let me do some quick testing over here, and I'll let you know the best way to ensure all the common PHA/POL alignments. Truth is, most devices do use (1,1) as their preferred standard, so I actually never had to use (0,0).

 

Sorry for not having understood the issue right away.

 

Best,

Alvie

Share this post


Link to post
Share on other sites

Ok, looks like we are forcing CPHA to '1' on the output.

 

Do you really need to use 0,0 mode ? If so, I will spend a few time "fixing" the issue w/o adding too much complexity to the design.

Share this post


Link to post
Share on other sites

I fixed the spi.vhd (also modded the spiclk.vhd to get an extra clkfall at transfer start to push first bit to stream, changes below) to support both cpha modes, but now i get into trouble with ZAP.

The flash is no longer recognized by ZAP, some help?

 
----  SPI interface-- --  Copyright 2010 Alvaro Lopes <alvieboy@alvie.com>-- --  Version: 1.0-- --  The FreeBSD license--  --  Redistribution and use in source and binary forms, with or without--  modification, are permitted provided that the following conditions--  are met:--  --  1. Redistributions of source code must retain the above copyright--     notice, this list of conditions and the following disclaimer.--  2. Redistributions in binary form must reproduce the above--     copyright notice, this list of conditions and the following--     disclaimer in the documentation and/or other materials--     provided with the distribution.--  --  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY--  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A--  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE--  ZPU PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,--  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES--  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS--  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)--  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,--  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)--  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF--  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--  --library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity spi is  port (    clk			: in  std_logic;    rst			: in  std_logic;    din			: in  std_logic_vector(31 downto 0);    dout		: out std_logic_vector(31 downto 0);    en			: in  std_logic;    ready		: out std_logic;    transfersize: in  std_logic_vector(1 downto 0);    miso		: in  std_logic;    mosi		: out std_logic;    clk_en		: out std_logic;    clkrise		: in  std_logic;    clkfall		: in  std_logic;    samprise 	: in  std_logic -- Sample on rising edge, shift data on falling edge);end entity spi;architecture behave of spi issignal read_reg_q		: std_logic_vector(31 downto 0);signal write_reg_q		: std_logic_vector(31 downto 0);	signal ready_q			: std_logic;signal count			: integer range 0 to 32;--signal count_val_q:   integer range 0 to 32;signal sample_event		: std_logic;signal do_shift			: std_logic;signal ignore_sample_q	: std_logic;begindout <= read_reg_q;process(samprise,clkrise,clkfall)begin	sample_event <= '0';	if (clkfall = '1' and samprise = '0') then		sample_event <= '1';	elsif (clkrise = '1' and samprise='1') then		sample_event <= '1';	end if;end process;process(ready_q, en)begin	ready <= ready_q;end process;process(ready_q, clkrise, clkfall, samprise, en)begin	if ready_q = '0' and samprise = '0' and clkrise = '1'  then		do_shift <= '1';	elsif ready_q = '0' and samprise = '1' and clkfall = '1'  then		do_shift <= '1';	else		do_shift<='0';	end if;end process;process(clk)begin	if rising_edge(clk) then		if do_shift = '1' then			case transfersize is				when "00" =>					MOSI <= write_reg_q(7); -- 8-bit write				when "01" =>					MOSI <= write_reg_q(15); -- 16-bit write				when "10" =>					MOSI <= write_reg_q(23); -- 24-bit write				when "11" =>					MOSI <= write_reg_q(31); -- 32-bit write				when others => NULL;			end case;		end if;	end if;end process;process(ready_q, clkrise, clkfall, count)begin	if ready_q = '1' then		clk_en <= '0';	else		if count/=0 then			clk_en <= '1';		else			if samprise = '0' then				clk_en <= not clkrise;			elsif samprise = '1' then				clk_en <= not clkfall;			end if;		end if;	end if;end process;process(clk)begin	if rising_edge(clk) then		if rst='1' then			ready_q <= '1';			count <= 0;		else			if ready_q = '1' then				if en = '1' then					ready_q <= '0';					write_reg_q <= din(31 downto 0);					ignore_sample_q <= not samprise;										-- Shift the 32-bit register					case transfersize is						when "00" =>							count <= 8;						when "01" =>							count <= 16;						when "10" =>							count <= 24;						when "11" =>							count <= 32;						when others => NULL;					end case;									end if;			else 				if count/=0 then					if do_shift = '1' then						count <= count - 1;					end if;				else					if clkrise = '1' and ready_q = '0' and samprise = '0' then						ready_q <= '1';					elsif clkfall = '1' and ready_q = '0' and samprise = '1' then						ready_q <= '1';					end if;				end if;			end if;			if ready_q = '0' and sample_event = '1' then				ignore_sample_q <= '0';								if ignore_sample_q = '0' then					write_reg_q(31 downto 0) <= write_reg_q(30 downto 0) & '0';					read_reg_q(31 downto 0) <= read_reg_q(30 downto 0) & MISO;				end if;			end if;		end if;	end if;end process;end behave;
----  SPI Clock generator-- --  Copyright 2010 Alvaro Lopes <alvieboy@alvie.com>-- --  Version: 1.0-- --  The FreeBSD license--  --  Redistribution and use in source and binary forms, with or without--  modification, are permitted provided that the following conditions--  are met:--  --  1. Redistributions of source code must retain the above copyright--     notice, this list of conditions and the following disclaimer.--  2. Redistributions in binary form must reproduce the above--     copyright notice, this list of conditions and the following--     disclaimer in the documentation and/or other materials--     provided with the distribution.--  --  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY--  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A--  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE--  ZPU PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,--  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES--  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS--  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)--  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,--  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)--  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF--  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--  --library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity spiclkgen is  port (    clk:   in std_logic;    rst:   in std_logic;    en:    in std_logic;    cpol:  in std_logic;    pres:  in std_logic_vector(2 downto 0);    clkrise: out std_logic;    clkfall: out std_logic;    spiclk:  out std_logic  );end entity spiclkgen;architecture behave of spiclkgen issignal running_q: std_logic;signal clkrise_i: std_logic;signal clkfall_i: std_logic;component prescaler is  port (    clk:    in std_logic;    rst:    in std_logic;    prescale:   in std_logic_vector(2 downto 0);    event:  out std_logic                         );end component prescaler;signal prescale_q: std_logic_vector(2 downto 0);signal clk_i: std_logic;signal prescale_event: std_logic;signal prescale_reset: std_logic;signal enq : std_logic;beginclkrise <= clkrise_i;clkfall <= clkfall_i;pr: prescaler  port map (    clk => clk,    rst => prescale_reset,    prescale => prescale_q,    event => prescale_event  );genclk: process(clk)begin  if rising_edge(clk) then    if rst='1' or en='0' then      spiclk <= cpol;    else      if clkrise_i='1' then        spiclk<=not cpol;      end if;      if clkfall_i='1' then        spiclk<=cpol;      end if;    end if;  end if;end process;    process(clk)begin	if rising_edge(clk) then		enq <= en;				if rst='1' then			prescale_q <= (others => '0');			running_q <= '0';			prescale_reset <= '0';		else			if en='1' then				prescale_reset<='0';				running_q <= '1';				if running_q='0' then					prescale_q <= pres;					prescale_reset<='1';				end if;			else				running_q <= '0';			end if;		end if;	end if;end process;process(clk)begin	if rising_edge(clk) then		if rst='1' then			clkrise_i<='0';			clkfall_i<='0';			clk_i<='0';		else			clkrise_i <= '0';			clkfall_i <= '0';						if en = '1' and enq = '0' then				clkfall_i <= '1';			end if;						if running_q='1' and en='1' then				if prescale_event='1' then						clk_i <= not clk_i;					if clk_i='0' then						clkrise_i <= '1';					else						clkfall_i <= '1';					end if;				end if;			else				clk_i <= '0';			end if;		end if;	end if;end process;end behave;

post-36776-0-34778100-1383404949_thumb.j

Share this post


Link to post
Share on other sites

Bump!

 

Should I post this on GITHUB somehow so that it gets merged and so that Alvie or someone can fix the remaining trouble with the ZPUino??

 

Regards

Kalle

Share this post


Link to post
Share on other sites

Yes, that would be good if you could do a pull request on github.

 

I might need to improve on that so that an extra clockin cycle can be used.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now