【FPGA】深入解析M25P16 SPI-FLASH的读写操作与Verilog实现
1. M25P16 SPI-FLASH基础解析
第一次接触M25P16时,我被它精巧的封装和强大的功能惊艳到了。这款只有8个引脚的芯片,竟然能存储2MB数据,而且支持10万次擦写循环。作为FPGA开发者最常用的外置存储器之一,理解它的工作原理是进行嵌入式存储开发的基础。
M25P16采用标准的SPI接口协议,支持模式0和模式3。这里有个容易混淆的点:虽然SPI有4种模式,但M25P16只支持其中两种。在实际项目中,我遇到过因为模式设置错误导致通信失败的案例。后来用逻辑分析仪抓取波形才发现,问题出在CPHA参数的配置上。
存储结构方面,M25P16采用三级寻址方式:
- 32个扇区(Sector),每个扇区256页
- 每页256字节
- 总容量正好是16Mb(2MB)
这种结构直接影响我们的操作方式。比如进行页编程时,如果写入数据超过256字节,超出的部分会从当前页开头覆盖,这个特性我在早期开发时踩过坑。有次连续写入300字节数据,结果前44字节被意外覆盖,导致系统异常。
2. 关键操作指令详解
2.1 基本指令集剖析
M25P16的指令系统非常精简,但每个指令都有严格的操作时序。根据我的项目经验,最常用的指令主要有以下几类:
读取类指令:
- READ(03h):基础读取指令
- FAST_READ(0Bh):带时钟延时的快速读取
- RDID(9Fh):读取芯片ID
写入类指令:
- WREN(06h):写使能(必须先执行)
- PP(02h):页编程指令
- SE(D8h):扇区擦除
- BE(C7h):整片擦除
状态控制指令:
- RDSR(05h):读状态寄存器
- WRSR(01h):写状态寄存器
在Verilog实现时,我习惯用宏定义这些指令码:
`define CMD_WREN 8'h06 `define CMD_PP 8'h02 `define CMD_READ 8'h03 `define CMD_SE 8'hD8 2.2 典型操作时序分析
写使能(WREN)时序: 这是最基础也最容易出错的环节。很多新手会忽略这个步骤直接进行写入操作。正确的流程应该是:
- 拉低CS片选
- 发送WREN指令(06h)
- 拉高CS
- 等待tWRL(典型值3μs)
页编程(PP)时序: 这是我调试时间最长的操作,关键点包括:
- 必须先执行WREN
- 指令+3字节地址+数据必须连续发送
- CS拉高后需要等待tPP(最大5ms)
// 页编程状态机示例 always @(posedge clk) begin case(state) IDLE: if(start_pp) state <= WREN; WREN: if(wren_done) state <= PP_CMD; PP_CMD