spi_mosi(rst,clk,rd,wr,datain,
spics,spiclk,spido,spidi,dataout)
input
rst
//置位信号,低有效
input
clk
//时钟信号
input
rd
//接收数据命令
input
wr
//发送数据命令
input
spidi
//SPI数据输入信号
input
[7:0]
datain
//发送数据输入
output
spics
//SPI片选信号
output
spiclk
//SPI时钟信号
output
spido
//SPI数据输出信号
output
[7:0]
dataout
//接收数据输出
reg
spics
reg
spiclk
reg
spido
reg
[7:0]
dstate,
dsend,dataout,dreceive
//,cnt
reg
[1:0]
spistate
parameter
idle
=
2'b00
parameter
send_data
=
2'b01
parameter
receive_data
=
2'b10
initial
begin
spics
<=
1'b1
spiclk
<=
1'b1
spido
<=
1'b1
end
always
@(posedge
clk)
begin
if(!rst)
begin
spistate
<=
idle
//
cnt
<=
8'd0
spics
<=
1'b1
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd0
end
else
begin
case
(spistate)
2'b00:
begin
//
spics
<=
1'b1
//
spiclk
<=
1'b1
//
spido
<=
1'b1
//
if(cnt
==
8'd0)
//
begin
//
cnt
<=
8'd0
if((wr
==
1'b0)
&&
(rd
==
1'b1))
//发送资料转换
begin
spistate
<=
send_data
dstate
<=
8'd0
dsend
<=
datain
end
else
if((wr
==
1'b1)
&&
(rd
==
1'b0))
//接收数据转换
begin
spistate
<=
receive_data
dstate
<=
8'd0
end
else
begin
spistate
<=
idle
dstate
<=
8'd0
end
//
end
//
else
//
begin
//
cnt
<=
cnt
+
8'd1
//
end
end
2'b01:
//发送数据状态
begin
case
(dstate)
8'd0:
//产生片选信号有效
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd1
end
8'd1:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd2
end
8'd2:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
1'b1
dstate
<=
8'd3
end
8'd3:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
dsend[7]
//发送数据最高位
dstate
<=
8'd4
end
8'd4:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[7]
dstate
<=
8'd5
end
8'd5:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
dsend[6]
dstate
<=
8'd6
end
8'd6:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[6]
dstate
<=
8'd7
end
8'd7:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
dsend[5]
dstate
<=
8'd8
end
8'd8:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[5]
dstate
<=
8'd9
end
8'd9:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
dsend[4]
dstate
<=
8'd10
end
8'd10:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[4]
dstate
<=
8'd11
end
8'd11:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
dsend[3]
dstate
<=
8'd12
end
8'd12:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[3]
dstate
<=
8'd13
end
8'd13:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
dsend[2]
dstate
<=
8'd14
end
8'd14:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[2]
dstate
<=
8'd15
end
8'd15:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
dsend[1]
dstate
<=
8'd16
end
8'd16:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[1]
dstate
<=
8'd17
end
8'd17:
begin
spics
<=
1'b0
spiclk
<=
1'b1
//发送最低位数据
spido
<=
dsend[0]
dstate
<=
8'd18
end
8'd18:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
dsend[0]
//spiclk的下降沿让最低位数据被读取
dstate
<=
8'd19
end
8'd19:
//置片选信号无效
begin
spics
<=
1'b1
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd20
end
8'd20:
begin
spics
<=
1'b1
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd0
spistate
<=
idle
end
default
begin
spics
<=
1'b1
spiclk
<=
1'b1
spido
<=
1'b1
spistate
<=
idle
end
endcase
end
2'b10:
//接收数据状态
begin
case
(dstate)
//片选信号有效
8'd0:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd1
end
8'd1:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd2
end
8'd2:
begin
spics
<=
1'b0
spiclk
<=
1'b0
spido
<=
1'b1
dstate
<=
8'd3
end
8'd3:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd4
end
8'd4:
begin
spics
<=
1'b0
spiclk
<=
1'b0
//紧接着上升沿的下降沿数据被读取
dreceive[7]
<=
spidi
//接收数据最高位
dstate
<=
8'd5
end
8'd5:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd6
end
8'd6:
begin
spics
<=
1'b0
spiclk
<=
1'b0
dreceive[6]
<=
spidi
dstate
<=
8'd7
end
8'd7:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd8
end
8'd8:
begin
spics
<=
1'b0
spiclk
<=
1'b0
dreceive[5]
<=
spidi
dstate
<=
8'd9
end
8'd9:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd10
end
8'd10:
begin
spics
<=
1'b0
spiclk
<=
1'b0
dreceive[4]
<=
spidi
dstate
<=
8'd11
end
8'd11:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd12
end
8'd12:
begin
spics
<=
1'b0
spiclk
<=
1'b0
dreceive[3]
<=
spidi
dstate
<=
8'd13
end
8'd13:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd14
end
8'd14:
begin
spics
<=
1'b0
spiclk
<=
1'b0
dreceive[2]
<=
spidi
dstate
<=
8'd15
end
8'd15:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd16
end
8'd16:
begin
spics
<=
1'b0
spiclk
<=
1'b0
dreceive[1]
<=
spidi
dstate
<=
8'd17
end
8'd17:
begin
spics
<=
1'b0
spiclk
<=
1'b1
dstate
<=
8'd18
end
8'd18:
begin
spics
<=
1'b0
spiclk
<=
1'b0
dreceive[0]
<=
spidi
//接收数据最低位
dstate
<=
8'd19
end
8'd19:
begin
spics
<=
1'b0
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd20
dataout<=
dreceive
end
8'd20:
begin
spics
<=
1'b1
//片选信号无效
spiclk
<=
1'b1
spido
<=
1'b1
dstate
<=
8'd0
spistate
<=
idle
end
endcase
end
default:
begin
spics
<=
1'b1
spiclk
<=
1'b1
spido
<=
1'b1
spistate
<=
idle
end
endcase
//对应上面的发送数据情形
end
//对应上面的RST没有按下的情形
end
//对应最上面的always@(posedge
clk)
endmodule
// 8bit SPI master// author: jiajia.pi
// version: v1.1
// last modify date: 2014/08/19 change ready assert timing
// clk_div range: 4~255 divsion of clk
// only mode 0 and mode 3 support
// MSB send first and LSB send last
module spi_master(
clk,// global clock
reset_n, // global async low reset
clk_div, // spi clock divider
wr,// spi write
wrdata,// spi write data, 8bit
rddata,// spi recieve data, 8bit, valid when ready assert
sck,// spi master clock out
sdi,// spi master data in (MISO)
sdo,// spi master data out (MOSI)
ready// spi master ready (idle)
)
input clk
input reset_n
input [7:0]clk_div
input wr
input [7:0]wrdata
output [7:0]rddata
output sck
output sdo
output ready
input sdi
parameter clock_polarity = 1 // '0': mode 0, sck=0 when idle'1': mode 3, sck=1 when idle
reg [7:0]dat
reg rsck
reg [7:0]cnt
reg busy
reg [3:0]state
reg [7:0]rddata
wire sdo = dat[7]
wire sck = busy? rsck:clock_polarity
wire sdi_tick = (cnt==clk_div>>1)/*synthesis keep*/
wire sdo_tick = (cnt==clk_div)/*synthesis keep*/
wire ready = !(wr||busy)
always @(posedge clk or negedge reset_n)
if(!reset_n)
cnt <= 0
else if(cnt<clk_div &&busy)
cnt <= cnt + 1
else
cnt <= 1
always @(posedge clk or negedge reset_n)
if(!reset_n)
rsck <= 0
else if(sdi_tick)
rsck <= 1
else if(sdo_tick)
rsck <= 0
always @(posedge clk or negedge reset_n)
if(!reset_n)
busy <= 0
else if(wr &&!busy)
busy <= 1
else if(state==8 &&sdo_tick)
busy <= 0
always@(posedge clk or negedge reset_n)
if(!reset_n)
state <= 0
else if(wr &&!busy)
state <= 1
else if(state==8 &&sdo_tick)
state <= 0
else if(sdo_tick)
state <= state + 1
always @(posedge clk or negedge reset_n)
if(!reset_n)
dat <= 0
else if(wr &&!busy)
dat <= wrdata
else if(sdo_tick &&busy &&state!=8)
dat <= dat<<1
always @(posedge clk or negedge reset_n)
if(!reset_n)
rddata <= 0
else if(sdi_tick &&busy)
rddata <= {rddata[6:0],sdi}
endmodule
你可以先算出4倍与SPI时钟SCK的clkdiv,根据这个写出时钟SCK,然后posedge SCK读取MOSI线,negedge SCK向MISO写入数据,这样基本的SPI时序应该没问题,剩下就是发送命令接收数据的控制了,建议用上function,会将冗长的程序简化,但需要脑子里有较好的时序思想,若用着不顺就一位一位的读取和发送吧,云创出版社的verilog书中有SPI时序简单讲解,程序很好懂的欢迎分享,转载请注明来源:内存溢出
评论列表(0条)