2020-10-04

    科技2022-07-17  119

    秦韵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_PHASENote00:数据在 SCLK 的第一个沿有效11:数据在 SCLK 的第二个沿有效 CLOCK_POLARITYNote00: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

    简单的写这么多吧。

    Processed: 0.009, SQL: 8