Raspberry pi通过SPI与FPGA通信

树莓引出的IO口中还有两条SPI通道,既然引出了,那不用白不用,而且SPI速度很可观。

只是不像I2C通信有地址,数据,比较好分开具化成存储器总线。


通过飞线,把树莓的CS,SCK,MOSI,MISO引到FPGA引脚上,测试了几个速率

500kbps

1Mbps

2Mbps

5Mbps

10Mbps

25Mbps

最后在25Mbps的时候,通信出现错误,在FPGA端看到是树莓的MOSI有时候是一直低电平,估计用示波器抓,

树莓的MOSI在25Mbps时已经有很大的畸变了,没法通信。


在10Mbps以下,通信是非常好的。


贴上测试代码

-- ============================================================
-- File Name	:	spi_sla.vhd
-- Author		:
-- Build Date	:
-- Version		:	V 1.1
-- ChangeLog	:
--			V1.1	remove the dependency with sp_en,so the outside
--					of sclk shall = (sclk and (not sp_en));
--					and sp_en shall be the CS signal for sub module
-- ============================================================
-- ************************************************************
-- Description	:	the spi slave device de/encoder
--				 	
-- 					
-- ************************************************************
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity spi_sla is
port
(
	clk		: in	std_logic;		--sclk freq*8
	rst		: in	std_logic;
	
	sclk	: in	std_logic;
	mosi	: in	std_logic;
	miso	: out	std_logic;
	
	dout	: in	std_logic_vector(7 downto 0);
	dprd	: out	std_logic;
	din		: out	std_logic_vector(7 downto 0);
	dpwr	: out	std_logic
);
end spi_sla;

architecture rtl of spi_sla is
type mosi_state_type is(idle,shift_in);
type miso_state_type is(idle,prepare,shift_out);
type d_type is record
	mosi_state	: mosi_state_type;
	miso_state	: miso_state_type;
	sclk		: std_logic_vector(1 downto 0);
	mosi		: std_logic_vector(1 downto 0);
	dpwr		: std_logic;
	dprd		: std_logic;
	rxcnt		: integer range 0 to 8;
	rxbuf		: std_logic_vector(7 downto 0);
	txcnt		: integer range 0 to 9;
	txbuf		: std_logic_vector(7 downto 0);
	miso		: std_logic;
	poped		: std_logic;
	sclk_gap	: integer range 0 to 7;
end record;
signal d,q	: d_type;


begin
	comb:process(q,rst,sclk,mosi,dout)
	variable w : d_type;
	variable sclk_rising	: std_logic;
	variable sclk_falling	: std_logic;
	begin
		w := q;
		
		w.sclk := q.sclk(0) & sclk;
		w.mosi := q.mosi(0) & mosi;
		
		sclk_rising := q.sclk(0) and (not q.sclk(1));
		sclk_falling := q.sclk(1) and (not q.sclk(0));
		
		if (q.sclk(0) xor q.sclk(1)) = '1' then
			w.sclk_gap := 0;
		else
			if q.sclk_gap < 7 then
				w.sclk_gap := q.sclk_gap + 1;
			end if;
		end if;
		
		w.dpwr := '0';
		w.dprd := '0';
		
		case q.mosi_state is
			when idle =>
				w.rxcnt := 0;
				if sclk_rising = '1' then
					w.rxbuf := q.rxbuf(6 downto 0) & q.mosi(1);
					w.rxcnt := 1;
					w.mosi_state := shift_in;
				end if;
			when shift_in =>
				if sclk_rising = '1' then
					w.rxbuf := q.rxbuf(6 downto 0) & q.mosi(1);
					w.rxcnt := q.rxcnt + 1;
					if w.rxcnt = 8 then
						w.rxcnt := 0;
						w.dpwr := '1';
						w.mosi_state := idle;
					end if;
				end if;
				if q.sclk_gap > 4 then
					w.mosi_state := idle;
				end if;
		end case;
		
		case q.miso_state is
			when idle =>
				if q.poped = '1' then
					w.dprd := '1';
				end if;
				w.miso_state := prepare;
			when prepare =>
				w.miso := dout(7);
				w.txcnt := 1;
				if q.poped = '1' then
					w.txbuf := dout(6 downto 0) & '0';
				end if;
				w.poped := '0';
				if sclk_falling = '1' then
					w.miso_state := shift_out;
					w.miso := q.txbuf(7);
					w.txcnt := q.txcnt + 1;
					w.txbuf := q.txbuf(6 downto 0) & '0';
				end if;
			when shift_out =>
				if sclk_falling = '1' then
					w.miso := q.txbuf(7);
					w.txbuf := q.txbuf(6 downto 0) & '0';
					w.txcnt := q.txcnt + 1;
					if w.txcnt = 9 then
						w.txcnt := 0;
						w.miso_state := idle;
						w.poped := '1';
					end if;
				end if;
				if q.sclk_gap > 4 then
					w.miso_state := prepare;
				end if;
		end case;
		
		if rst = '1' then
			w.miso_state	:= idle;
			w.mosi_state	:= idle;
			w.rxcnt			:= 0;
			w.txcnt			:= 0;
			w.rxbuf			:= (others => '0');
			w.txbuf			:= (others => '0');
			w.miso			:= '0';
			w.poped			:= '1';
		end if;
		
		dprd	<= w.dprd;
		din		<= q.rxbuf;
		dpwr	<= q.dpwr;
		miso	<= w.miso;
		d		<= w;
	end process;

	regs:process(clk)
	begin
		if rising_edge(clk) then
			q <= d;
		end if;
	end process;
end rtl;

树莓上的

#include 
#include 

int main()
{

	if (!bcm2835_init())
		return 1;
	uint8_t txbuf = 0x00;
	uint8_t err_cnt = 0;

	bcm2835_spi_begin();
	bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);      // The default
	bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);                   // The default
	bcm2835_spi_setClockDivider(25); // The default
	bcm2835_spi_chipSelect(BCM2835_SPI_CS0);                      // The default
	bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default

	while(1)
	{
		uint8_t data = bcm2835_spi_transfer(txbuf);
		printf("Write to SPI : %02X\n", txbuf);
		printf("Read from SPI: %02X\n", data);
		
		
		bcm2835_delay(100);
		
		if((data + 1) != txbuf)
		{
			err_cnt = err_cnt + 1;
		}
		printf("err_cnt is : %d\n", err_cnt);
		printf("***********\n\n");

		if(err_cnt >= 2)
		{
			break;
		}
		
		txbuf = txbuf++;
    }

	bcm2835_spi_end();
	bcm2835_close();
	return 0;
}

在10Mbps下,读写了256次,没问题

Raspberry pi通过SPI与FPGA通信_第1张图片

在首次读写时,因为根本就没上一次写,所以读出来的数据也就无从比较,err_cnt 记录1次,

在写0x00时,读回来0xFF,相差1,不过渣渣测试代码不会回转,err_cnt 记录2次

可以看出SPI在10Mbps下通信良好。

Raspberry pi通过SPI与FPGA通信_第2张图片


PS:树莓的CS在空闲时不一定保持高电平,如图,因为不仅会有bcm2835_spi_begin();bcm2835_spi_end();这些在影响,而且在测试中发现CS引脚的驱动能力不强,经常受外界干扰会抖动,所以不能以CS的下降沿来触发,你懂的。





你可能感兴趣的:(raspberry_pi)