german010 发表于 2012-9-5 15:30:03

大家谁做过FPGA的spi 发送和接收?我的spi 干扰很大

如下面所示:
module spi_ctrl(
clk,rst_n,
spi_miso,spi_mosi,spi_clk,
spi_tx_en,spi_tx_rdy,spi_rx_en,spi_rx_rdy,spi_tx_db,spi_rx_db
);
inputclk;          //FPAG输入时钟信号50MHz
inputrst_n;//FPGA输入复位信号
inputspi_miso;          //SPI主机输入从机输出数据信号
output spi_mosi;          //SPI主机输出从机输入数据信号
output spi_clk;         //SPI时钟信号,由主机产生
inputspi_tx_en;         //SPI数据发送使能信号,高有效
output spi_tx_rdy;      //SPI数据发送完成标志位,高有效
inputspi_rx_en;         //SPI数据接收使能信号,高有效
output spi_rx_rdy;      //SPI数据接收完成标志位,高有效
inputspi_tx_db;    //SPI数据发送寄存器
output spi_rx_db;    //SPI数据接收寄存器
//模拟SPI的时序模式为CPOL=1, CPHA=1,模拟速率为50Mbit

//------------------------------------------------------
//SPI时序控制计数器,所有SPI时序由该计数器值控制
reg cnt8;//SPI时序控制计数器,计数范围在0-18
always @(posedge clk or negedge rst_n)
        if(!rst_n)
                        cnt8 <= 5'd0;
                else if(spi_tx_en || spi_rx_en)
                begin    //SPI工作使能
                        if(cnt8 < 5'd18)
                                cnt8 <= cnt8 + 1'b1;   //计数到18停止,等待撤销spi使能                           
                        else cnt8 <= 5'd0;                     //SPI关闭,计数停止
                end
//--------------------------------------------------------
//SPI时钟信号产生
reg spi_clkr;//SPI时钟信号,由主机产生
always @(posedge clk or negedge rst_n)
        if(!rst_n)
                spi_clkr <= 1'b1;                           //spi时钟只有在spi启用过程中才有效
        else if(cnt8>5'd1 && cnt8<5'd18)
                spi_clkr <= ~spi_clkr;//在cnt8处于2-17时SPI时钟有效翻转

assign spi_clk = spi_clkr;
//-------------------------------------------------------
//SPI主机输出数据控制
reg spi_mosir; //SPI主机输出从机输入数据信号   
always @(posedge clk or negedge rst_n)
if(!rst_n) spi_mosir <= 1'b1;
else if(spi_tx_en) begin
case(cnt8)      //不判断最低位,则数据在cnt8两次加一后才有一次变化,这里刚好和接收的时钟分开
4'd1: spi_mosir <= spi_tx_db;    //发送bit7相当于cnt8=2
4'd2: spi_mosir <= spi_tx_db; //发送bit6相当于cnt8=4
4'd3: spi_mosir <= spi_tx_db; //发送bit5相当于cnt8=6
4'd4: spi_mosir <= spi_tx_db; //发送bit4相当于cnt8=8
4'd5: spi_mosir <= spi_tx_db; //发送bit3相当于cnt8=10
4'd6: spi_mosir <= spi_tx_db; //发送bit2相当于cnt8=12
4'd7: spi_mosir <= spi_tx_db; //发送bit1相当于cnt8=14
4'd8: spi_mosir <= spi_tx_db; //发送bit0相当于cnt8=16
default: spi_mosir <= 1'b1;            //spi_mosi没有输出时应保持高电平
//如果这里只是单纯地使用cnt8的2、4、6..在default里面有所不同,如果是246之类的那么在357的时候default会有效,而本例中是无效的
endcase
end
   else spi_mosir <= 1'b1; //spi_mosi没有输出时应保持高电平
assign spi_mosi = spi_mosir;
//---------------------------------------------------------------
//SPI主机输入数据控制
reg spi_rx_dbr;//SPI主机输入从机输出数据总线寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n) spi_rx_dbr <= 8'hff;
else if(spi_rx_en) begin
case(cnt8)         //取cnt8的奇数,这样可以和发送时钟错开
5'd3 : spi_rx_dbr <= spi_miso;   //接收bit7
5'd5 : spi_rx_dbr <= spi_miso; //接收bit6
5'd7 : spi_rx_dbr <= spi_miso; //接收bit5
5'd9 : spi_rx_dbr <= spi_miso; //接收bit4
5'd11: spi_rx_dbr <= spi_miso; //接收bit3
5'd13: spi_rx_dbr <= spi_miso; //接收bit2
5'd15: spi_rx_dbr <= spi_miso; //接收bit1
5'd17: spi_rx_dbr <= spi_miso; //接收bit0
default: ; //区别上个always里面的default,这里也是无操作
endcase
end
assign spi_rx_db = spi_rx_dbr;

//-----------------------------------------------------------------
//SPI数据发送完成标志位,高有效
assign spi_tx_rdy = (cnt8 == 5'd18);
//------------------------------------------------------------------
//SPI数据接收完成标志位,高有效
assign spi_rx_rdy = (cnt8 == 5'd18);

endmodule

xieshuangok 发表于 2012-9-5 16:19:21

FPGA接的是什么串行芯片?下载一个测试模型看看

xieshuangok 发表于 2012-9-6 10:41:52

//-----------------------------------------------------------------
//SPI数据发送完成标志位,高有效
assign spi_tx_rdy = (cnt8 == 5'd18);
//------------------------------------------------------------------
//SPI数据接收完成标志位,高有效
assign spi_rx_rdy = (cnt8 == 5'd18);


纯组合逻辑输出,比较器又为5位,极易出现竞争冒险,产生毛刺,在时序仿真时就有,建议加寄存器输出

always @(posedge clk or negedge rst_n)
begin
        if(!rst_n) spi_tx_rdy <= 0;
        else
                if(cnt8 == 5'd17)
                        spi_tx_rdy <= 1;
                else
                        spi_tx_rdy <= 0;
end

always @(posedge clk or negedge rst_n)
begin
        if(!rst_n) spi_rx_rdy <= 0;
        else
                if(cnt8 == 5'd17)
                        spi_rx_rdy <= 1;
                else
                        spi_rx_rdy <= 0;
end

加寄存器输出后,总共用的逻辑反而小了一个。

最后,时序约束一定要完整。

wye11083 发表于 2012-9-6 10:55:21

跟接口电路有关了。我的老式的接口电路接1.5MHz就罢工了,只能用1.2MHz以下。

german010 发表于 2012-9-27 11:35:43

可能代码的问题,状态机写的不好,完全重新写了一个,

wangshaosh123 发表于 2012-10-21 13:43:32

用xilinx的IP32M跑起来毫无压力

preferpan 发表于 2012-11-30 16:23:49

最近也在玩这个想操作一个ADC 串行SPI的学习先 到时候多多指教

sky5566 发表于 2012-12-1 16:19:19

簡單的方式類似單片機,判斷訊號上下緣傳送接收.
複雜的設計方式,有些要將 clock 分成10分頻,然後取 1/2 分頻方式傳送接收...你可以參考 {Verilog HDL 那些事兒 - 第三章4.doc} 的設計方式

独在异乡为异客 发表于 2012-12-4 20:24:36

马上要开始搞了,先记下

SightNeng 发表于 2013-5-2 12:30:15

MARKMARKMARKMARKMARK

mhw 发表于 2013-5-2 12:39:02

注意MISO这根线,一般最好上拉一下

自己搞的话,所有线驱动能力都要测试一下……

爱走来的那天 发表于 2015-7-20 15:01:57

MARK下,{:biggrin:}{:biggrin:}

爱走来的那天 发表于 2015-7-20 15:03:56

话说为什么SPI接口的发射时钟和接收时钟要错开啊?

y595906642 发表于 2015-7-20 15:46:05

爱走来的那天 发表于 2015-7-20 15:03
话说为什么SPI接口的发射时钟和接收时钟要错开啊?

常用的是 上升沿让对方读数 下降沿刷新数据

爱走来的那天 发表于 2015-7-21 16:33:43

y595906642 发表于 2015-7-20 15:46
常用的是 上升沿让对方读数 下降沿刷新数据

难怪呢,我现在用的SPI都是上升沿触发==

guolh_bj 发表于 2015-7-29 16:31:22

wangshaosh123 发表于 2012-10-21 13:43
用xilinx的IP32M跑起来毫无压力

xilinx的SPI有源码么???
页: [1]
查看完整版本: 大家谁做过FPGA的spi 发送和接收?我的spi 干扰很大