module myspi(nrst, clk, ncs, mosi, miso, sck);
input clk, nrst; input ncs, mosi, sck; output miso;
reg[2:0] sck_edge; always @ (posedge clk or negedge nrst) begin if(~nrst) begin sck_edge <= 3'b000; end else begin sck_edge <= {sck_edge[1:0], sck}; end end
wire sck_riseedge, sck_falledge; assign sck_riseedge = (sck_edge[2:1] == 2'b01); //检测到SCK由0变成1,则认为发现上跳沿 assign sck_falledge = (sck_edge[2:1] == 2'b10); //检测到SCK由1变成0,则认为发现下跳沿
reg[7:0] byte_received; reg[3:0] bit_received_cnt; reg rec_flag; reg[1:0] rec_status; //SPI接收部分状态机 reg[7:0] rec_data; reg[2:0] rec_flag_width; //SPI接收完成标志位脉冲宽度寄存器 always @ (posedge clk or negedge nrst) //每次sck都会接收数据,spi的顶端模块状态机决定是否取用 begin if(~nrst) begin byte_received <= 8'h00; bit_received_cnt <= 4'h0; rec_flag <= 1'b0; rec_status <= 2'b00; rec_flag_width <= 3'b000; end else begin if(~ncs) begin case (rec_status) 2'b00: begin if(sck_riseedge) begin byte_received <= {byte_received[6:0], mosi}; if(bit_received_cnt == 4'h7) begin bit_received_cnt <= 4'b0000; rec_status <= 2'b01; end else begin bit_received_cnt <= bit_received_cnt+1; end end end 2'b01: begin rec_data <= byte_received; rec_flag <= 1'b1; if(rec_flag_width==3'b100) begin rec_flag_width <= 3'b000; rec_status <= 2'b11; end else begin rec_flag_width <= rec_flag_width+1; end end 2'b11: begin rec_flag <= 1'b0; rec_status <= 2'b00; end endcase end end end
reg miso; reg sending_flag; //正在发送标志位 reg[7:0] byte_sended; //发送移位寄存器 reg[3:0] bit_sended_cnt; //SPI发送位计数器 reg[1:0] send_status; //SPI发送部分状态机 always @ (posedge clk or negedge nrst) begin if(~nrst) begin byte_sended <= 8'h00; bit_sended_cnt <= 4'b0000; send_status <= 2'b00; sending_flag <= 1'b0; end else begin if(~ncs) begin case (send_status) 2'b00: begin if(send_flag) begin //锁存发送数据 send_status <= 2'b01; //2'b01; byte_sended <= send_data; sending_flag <= 1'b1; miso <= send_data[7]; end end 2'b01: begin //发送数据移入移位寄存器 if(sck_riseedge) begin //miso <= byte_sended[7]; //byte_sended <= {byte_sended[6:0], 1'b0}; send_status <= 2'b11; end end 2'b11: begin //根据sck下降沿改变数据 miso <= byte_sended[7]; if(sck_falledge) ///---------------------------------------这里多移了一位 begin //miso <= byte_sended[7]; byte_sended <= {byte_sended[6:0], 1'b0}; if(bit_sended_cnt == 4'b0111) begin send_status <= 2'b10; bit_sended_cnt <= 4'b0000; sending_flag <= 1'b0; end else begin bit_sended_cnt <= bit_sended_cnt+1; end end end 2'b10: begin //数据发送完毕 send_status <= 2'b00; //sending_flag <= 1'b0; miso <= 1'b0; end endcase end end end