模块端口共有9个,5个输入4个输出。输入分别为:时钟clk,复位rst,主输入从输出miso,片选rw,需要发送的数据data_out,输出分别有,主输出从输入mosi,spi时钟sclk,接收到的数据data_in,状态标志busy。
module spi_flash(
input clk,
input rst,
input miso,
input rw,
input [7:0] data_out,
output reg mosi,
output reg sclk,
output reg [7:0] data_in,
output reg busy
);
由于需要用到spi时钟,spi时钟是一个慢速时钟,这里我所使用的是50Mhz的时钟,进行4分频得到一个12.5Mhz的spi时钟。所以需要一个俩位的计数器,当计数到1时归零,在定义一个标志位move,当计数器清零时move为高电平。但片选使能时,并且状态机处于等待使能,为了保持在传输时数据的稳定,需要把输出的数寄存到一个新的寄存器中data_out_s。在状态机处于接受完成的状态时把接受到的数据有data_in_s寄存器传出。由于spi的接收和发送的数据不在同一个时钟边沿采集,所以在接收到数据后在d为高电平时跟新数据。状态标志位当片选或状态机不处于等待使能信号时为高电平,代表发送未完成,处于忙碌的状态。
reg [1:0] d; always@(posedge clk) if(rst) d <= 0; else d <= d[1] ? 0 : d + 1;
wire move = d == 0;
reg [7:0] data_in_s; always@(posedge clk) if(st == 116) data_in <= data_in_s;
reg [7:0] data_out_s; always@(posedge clk) if(st == 10 & rw) data_out_s <= data_out;
reg miso_s; always@(posedge clk) if(d == 1)miso_s <= miso;
always@(posedge) busy <= rw || st != 10;
最后就是状态机了,0状态为输出状态,时钟和要发送的数据都为0,10状态为使能信号等待状态,当收到使能时,等待一段时间,这个时间为使能后与发送第一个数据的间隔时间,具体时间可以在数据手册中查询,我这里等待了半个多的sclk时间,然后就可以接受与发送数据了,注意在flash的接受和发送也需要数据稳定的时间,具体也可以在数据手册中找到,flash的发送数据为上升沿采样,提前在下降沿时改变数据,接受时为下降沿采样,在sclk的上升时改变数据。
reg [7:0] st;
always@(posedge clk) if(rst) st <= 0;else case(st)
0:begin sclk <= 0;mosi <= 0;st <= 10; end
10: begin sclk <= 0; mosi <= 0; if(rw) st <= 20;
20: if(move) st <= 21;
21: if(move) st <= 100;
100: begin sclk <= 0; mosi <= data_out_s[7]; if(move) st <= st + 1;end
101: begin sclk <= 1; mosi <= data_out_s[7]; data_in_s[7] <= miso_s; if(move) st <= st + 1;end
102: begin sclk <= 0; mosi <= data_out_s[6]; if(move) st <= st + 1;end
103: begin sclk <= 0; mosi <= data_out_s[7]; data_in_s[6] <= miso_s; if(move) st <= st + 1;end
104: begin sclk <= 0; mosi <= data_out_s[5]; if(move) st <= st + 1;end
105: begin sclk <= 0; mosi <= data_out_s[5]; data_in_s[5] <= miso_s; if(move) st <= st + 1;end
106: begin sclk <= 0; mosi <= data_out_s[4]; if(move) st <= st + 1;end
107: begin sclk <= 0; mosi <= data_out_s[4]; data_in_s[4] <= miso_s; if(move) st <= st + 1;end
108: begin sclk <= 0; mosi <= data_out_s[3]; if(move) st <= st + 1;end
109: begin sclk <= 0; mosi <= data_out_s[3]; data_in_s[3] <= miso_s; if(move) st <= st + 1;end
110: begin sclk <= 0; mosi <= data_out_s[2]; if(move) st <= st + 1;end
111: begin sclk <= 0; mosi <= data_out_s[2]; data_in_s[2] <= miso_s; if(move) st <= st + 1;end
112: begin sclk <= 0; mosi <= data_out_s[1]; if(move) st <= st + 1;end
113: begin sclk <= 0; mosi <= data_out_s[1]; data_in_s[1] <= miso_s; if(move) st <= st + 1;end
114: begin sclk <= 0; mosi <= data_out_s[0]; if(move) st <= st + 1;end
115: begin sclk <= 0; mosi <= data_out_s[0]; data_in_s[0] <= miso_s; if(move) st <= st + 1;end
116: begin sclk <= 0;if(move) st <= st + 1;
117: if(move) st <= 10;
default: st <= 0;
endcase
endmodule