2020-10-04

秦韵FPGA 转载或原创(四)

spi slave 的实现

前几天在做一个项目,fpga和cpu之间做一个数据通路,原定的uart,但是在数据的传输上
有瓶颈,因此就选择了标准的spi接口,spi_sclk采用20Mhz,基本上满足要求,
记录一下,调试过程中的问题。
标准spi接口协议,默认4-wire,MISO,MOSI 可实现全双工。
简单的介绍一下spi的模式,有4种模式,有CLOCK_PHASE和 CLOCK_POLARITY
来确定其工作在哪一种模式下,即Mode0,Mode1,Mode2,Mode3.
`define     TRANS_DIRECTION     0   // 0: MSB->LSB , 1: LSB -> MSB
`define     CLOCK_PHASE         0   
`define     CLOCK_POLARITY      0
`define     DATA_LENGTH         32
CLOCK_PHASENote
00:数据在 SCLK 的第一个沿有效
11:数据在 SCLK 的第二个沿有效
CLOCK_POLARITYNote
00:SCLK 高电平有效
11:SCLK 低电平有效

TRANS_DIRECTION : 表示开始传输数据是是先发送MSB还是线发送LSB
DATA_LENGTH :我定义32bit ,采用高2bit实现读写( data_slave[31:30] ),data_slave[29:16] 作为地址,data_slave[15:0] 用来传输数据。

  • 当时在做的时候,采用了两种方式:
  • 1 ,在每次进行读写数的时候,都会将地址写下来,然后进行解析
  • 2 . 只有在第一次读写数的时候,写一次地址,然后进行数据流传输,不需要进行地址控制,spi_master 模块只需要进行接收,在第一次读数据之前,会先读取所要读取的数据长度。
    第二种方式,效率要高一些,节省了频繁对地址解码的过程,也节省了地址占带块的一半,不过考虑极限情况,在工作环境极不友好的情况下,还是使用方式1稳妥一些。
module spi_slave(
    input SCLK,
    input MOSI,
    output MISO,
    input SSn ,
    //usr logic
    .......
    //   //简单介绍一下实现过程:
/*
* 首先,作为从机,需要对主机的sclk 进行采样,在fpga片内,
* 主时钟域在100M,使用sclk的沿来进行传输数据,*(至于在第一个上升沿
* 还是第二个上升沿,需要看你之前的配置模式,这个需要跟master 一样,
* 避免接收的数据错误)。
* 
*/
always@(posedge clk_x2 or negedge rst_n)
if(!rst_n) 
    mosi_shift_reg <= 32'h0;
else begin
      if(SSn)       /*这里直接使用cs信号,为了是代码简单,易于理解*/
          mosi_shift_reg <= 32'h0;
      else if(!SSn && (recev_cnt < `DATA_LENGTH) && sclk_rpls)begin
          if(`TRANS_DIRECTION )    //LSB -> MSB
              mosi_shift_reg <= {MOSI,mosi_shift_reg[`DATA_LENGTH-1:1]};
          else                    //MSB -> LSB
              mosi_shift_reg <= {mosi_shift_reg[`DATA_LENGTH-2:0],MOSI};
      end
      else
          mosi_shift_reg <= 32'h0;
end

always@(posedge clk_x2 or negedge rst_n)
if(!rst_n)
    recev_cnt  <= 5'd0;
else begin
    if(SSn)
        recev_cnt <= 5'd0;
    else if( recev_cnt == `DATA_LENGTH - 1)  
        recev_cnt <= 0;
    else if(sclk_rpls)
        recev_cnt <= rx_cnt + 1;
end
always@(posedge clk_x2 or negedge rst_n )
if(!rst_n) begin 
    trans_cnt <= 0;
    miso_shift_reg <= 0;
end
else begin
    if(SSn)
        trans_cnt <= 0;
    else if(trans_cnt >= `DATA_LENGTH - 1)begin
        miso_shift_reg <= mosi_shift_reg;
        trans_cnt <= 0;
    end
    else if(sclk_rpls )
        trans_cnt <= trans_cnt + 1;
end

assign MISO = SSn ? 1'bz :`TRANS_DIRECTION ? miso_shift_reg[trans_cnt] :  miso_shift_reg[`DATA_LENGTH-trans_cnt-1] ;   
                                     
endmodule

简单的写这么多吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值