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简单的写这么多吧。