利用fpga(verilog)实现SPI-flash芯片全擦除实验
·
最近在学习spi协议,看了看野火的视频,感觉野火的代码是一坨大便,寄存器太多了,看的眼花缭乱。跟着野火的波形图做了一遍,仿真正确但是上板没成功。看了看师兄的代码,然后自己又换了一种方法实现全擦除。最后上板成功,各位大佬有更好的见解可以和我交流,代码如下:
// -----------------------------------------------------------------------------
// Create : 2023-11-29
// Revise : 2023-11-29
// Note : spi驱动,模式0,时钟默认低电平,上升沿数据有效,主机模式,目前只有单字节发送功能
// 该flash快速命令最高支持50M时钟,常规命令最高支持20M时钟,所以SPI时钟使用主时钟四分频12.5M
// -----------------------------------------------------------------------------
module spi_driver (
clk,
reset,
data,
spi_miso,
spi_flag,
spi_cs,
spi_sck,
spi_mosi
);
input clk;
input reset;
input[7:0]data; //指令数据
input spi_flag; //指令数据脉冲
input spi_miso;
output reg spi_cs;
output wire spi_sck;
output wire spi_mosi;
reg[1:0]cnt ; //用于四分频
reg[2:0]cnt_data; //用于计数当前发送的数据位
reg[7:0]data_r;
//将data向后拉一个时钟周期
always @(posedge clk or negedge reset) begin
if(!reset)
data_r <= 0;
else if(spi_flag)
data_r <= data;
end
//cnt
always @(posedge clk or negedge reset) begin
if(!reset)
cnt <= 0;
else if(!spi_cs)
cnt <= cnt+1'b1;
end
//产生12.5mhz的sck
assign spi_sck = cnt[1];
//8位数据的计数
always @(posedge clk or negedge reset) begin
if(!reset)
cnt_data <= 0;
else if(cnt == 2'b11)
cnt_data <= cnt_data+1'b1;
end
//片选信号,低电平有效
always @(posedge clk or negedge reset) begin
if(!reset)
spi_cs <= 1;
else if(spi_flag)
spi_cs <= 0;
else if(cnt_data == 3'b111&&cnt==2'b11)
spi_cs <= 1;
end
//spi协议规定先发高位,因此将cnt_data取反。
assign spi_mosi = spi_cs? 0:data_r[~cnt_data];
endmodule
// -----------------------------------------------------------------------------
// Create : 2023-11-29
// Note : spi flash全擦除实验
// 实验开发板:黑金ax301,flash芯片:M25P16
// 需要用到的命令:
// WREN(Write Enable): 06h
// BE(Bulk Erase): C7h
// 全擦除前要先写入WREN,然后cs拉高需要至少100ns才能开始下一次传输
// Revise : 2023-11-30
// -----------------------------------------------------------------------------
module spi_be (
clk,
reset,
spi_miso,
spi_mosi,
spi_cs,
spi_sck,
);
input clk;
input reset;
input spi_miso;
output spi_mosi;
output spi_sck;
output spi_cs;
reg [11:0] cnt;
//设置全擦除程序运行一次的周期位4095*20ns,当cnt为12'hfff时,cnt将保持不变。
always @(posedge clk, negedge reset) begin
if(!reset)
cnt <= 0;
else if(cnt < 12'hfff)
cnt <= cnt + 12'd1;
end
//设置指令的产生和指令标准位脉冲的产生,cnt为2000时,指令为写允许指令“00000110”,产生一个时钟周期的指令标准为脉冲,
//cnt为2050时,指令为全擦除指令“11000111”,产生一个时钟周期的指令标准为脉冲。
wire spi_flag = (cnt == 12'd2000) || (cnt == 12'd2050);
wire [7:0]data = (cnt == 12'd2000) ? 8'h06 : ((cnt == 12'd2050) ? 8'hc7 : 8'd0);
spi_driver spi_driver(
.clk(clk),
.reset(reset),
.data(data),
.spi_miso(spi_miso),
.spi_flag(spi_flag),
.spi_cs(spi_cs),
.spi_sck(spi_sck),
.spi_mosi(spi_mosi)
);
endmodule
`timescale 1ns/1ns
module spi_tb;
reg clk;
reg reset;
reg spi_miso;
wire spi_cs;
wire spi_sck;
wire spi_mosi;
spi_be spi_be(
.clk(clk),
.reset(reset),
.spi_miso(spi_miso),
.spi_cs(spi_cs),
.spi_sck(spi_sck),
.spi_mosi(spi_mosi)
);
initial clk=0;
always#10 clk=!clk;
initial begin
reset=0;
spi_miso=0;
#201;
reset=1;
#100000
$stop;
end
endmodule
仿真波形:

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)