SPI可以说是FPGA最重要的接口了,它的可以发送任何自定义bit流。但是我们系统时钟是一个固定值,当我们要调整SPI的发送串行时钟时,采用FIFO既可以实现跨时钟域处理,有可以充当缓存。
但是我们需要注意的是FIFO输出模式,有正常模式,也有数据提前准备的模式。其中正常模式,数据要读使能的下个时钟出来,新手往往很难处理这种情况。
我们建议使用状态机来简化对FIFO的读出测操作。
上代码
module array_spi_tx(
input CLK_i ,//系统时钟
input RST_i ,
input spi_tx_clk , // 可以更改
input [351 :0] spi_tx_data ,// 串口读到需下发数据
input [11 :0] spi_tx_length ,// 串口读到数据字长
input spi_tx_en ,
output reg spi_tx_o
);
localparam tx_idle = 2'b00 ,
tx_delay = 2'b01 ,
tx_pack = 2'b10 ,
tx_send = 2'b11 ;
reg [1 :0] tx_state ;
reg [11 :0] tx_count ;
reg [11 :0] spi_tx_length_r ;
reg [351 :0] tx_data0 ;
reg rd_en ;
wire [363 :0] dout ;
wire full, empty ;
spi_tx_fifo u_spi_tx_fifo (
.wr_clk ( CLK_i ),// input
.wr_rst ( ~RST_i ),// input 1复位
.wr_en ( spi_tx_en ),// input
.wr_data ( {spi_tx_length, spi_tx_data} ),// input [289:0]
.wr_full ( full ),// output
.almost_full ( ),// output
.rd_clk ( spi_tx_clk ),// input
.rd_rst ( ~RST_i ),// input 1复位
.rd_en ( rd_en ),// input
.rd_data ( dout ),// output [289:0]
.rd_empty ( empty ),// output
.almost_empty ( ) // output
);
always @(posedge spi_tx_clk or negedge RST_i)begin
if(~RST_i)begin
spi_tx_o <= 1'b1 ;
tx_count <= 12'd0 ;
tx_data0 <= 352'd0 ;
rd_en <= 1'b0 ;
tx_state <= tx_idle ;
end
else case (tx_state)
tx_idle:begin
if(empty == 1'b0)begin
rd_en <= 1'b1 ;
tx_state <= tx_dely ;
end
else begin
rd_en <= 1'b0 ;
tx_state <= tx_idle ;
end
end
tx_delay:begin
rd_en <= 1'b0 ;
tx_state <= tx_pack ;
end
tx_pack:begin
tx_data0 <= dout[351 : 0] ;
tx_count <= dout[363-:12] ;
spi_tx_length_r <= dout[363-:12] ;
tx_state <= tx_send ;
end
tx_send:begin
if( tx_count > 12'd0 ) begin
tx_count <= tx_count - 1 ;
spi_tx_o <= tx_data0[spi_tx_length_r - 1] ;
tx_data0 <= tx_data0<<1 ;
end
else begin
spi_tx_o <= 1'b1 ;
tx_state <= tx_idle ;
end
end
default:
tx_state <= tx_idle ;
endcase
end
endmodule
处理的诀窍增加了一个状态delay来等一拍 因为有些FIFO读取时序是这样,如果不需要,修改去掉delay这个状态即可
我们来总结一个这个模块:
1 FIFO引入实现了跨时钟域和数据缓存
2 delay状态的有无照顾各种类型的FIFO
3 数据中带有需要发送SPI比特流的长度信息,实现任意长度的SPI数据发送(当然受制于FIFO的数据宽度)
4 SPI的时钟可以随时自己更改
结论:
这是一个优秀的设计,非常值得FPGA的初学者参考或直接用于项目中。
下期再见
发表回复