SPI Flash的擦写注意事项


从规格书上看,SPI flash一般支持3种擦写方式:按sector擦写,按block擦写,整片chip擦写。

以KH25L3255E为例,

•      Serial Peripheral Interface compatible -- Mode 0 and Mode 3
•      33,554,432 x 1 bit structure or 16,777,216 x 2 bits (two I/O mode) structure or 8,388,608 x 4 bits (four I/O
mode) structure
•      1024 Equal Sectors with 4K bytes each
     - Any Sector can be erased individually
•     128 Equal Blocks with 32K bytes each
     - Any Block can be erased individually
•     64 Equal Blocks with 64K bytes each
     - Any Block can be erased individually
•     Power Supply Operation
- 2.7 to 3.6 volt for read, erase, and program operations
• Latch-up protected to 100mA from -1V to Vcc +1V

由此可以看出,KH25L3255E的sector大小是4K,block大小是32K/64K.因此,可以一次性擦除4K/32K/64K.

三种擦写方式的性能比较:
- Fast erase time: 30ms (typ.)/sector (4K-byte per sector) ; 0.25s(typ.) /block (64K-byte per block); 10s(typ.) /    
<think>我们已知SPI Flash的操作步骤包括:初始化、写使能、擦除、写入、读取和等待就绪。下面将结合引用内容,详细说明如何测试SPI Flash的擦除、读取和写入功能,并提供具体示例。 ### 一、测试准备 1. **硬件连接**:确保SPI Flash与主控(如MCU或FPGA)正确连接,包括MOSI、MISO、SCK、CS(SS)引脚。 2. **初始化SPI**:配置SPI外设的时钟极性(CPOL)、时钟相位(CPHA)、数据位宽(通常8位)和时钟频率[^1]。 3. **定义基本命令**:根据Flash芯片手册(如Winbond W25Q系列)定义操作命令[^3]: ```c #define CMD_WRITE_ENABLE 0x06 #define CMD_WRITE_DISABLE 0x04 #define CMD_READ_STATUS_REG1 0x05 #define CMD_PAGE_PROGRAM 0x02 // 页编程命令(写入数据) #define CMD_SECTOR_ERASE 0x20 // 扇区擦除命令 #define CMD_READ_DATA 0x03 // 读取数据命令 ``` ### 二、测试步骤与示例代码 #### 1. 擦除功能测试 **目标**:擦除一个扇区(通常4KB),验证擦除后该扇区所有字节变为0xFF。 **步骤**: 1. 发送写使能命令(`CMD_WRITE_ENABLE`)[^3]。 2. 发送扇区擦除命令(`CMD_SECTOR_ERASE`)并指定扇区地址。 3. 等待擦除完成(轮询状态寄存器直到忙标志位为0)。 **示例代码**: ```c // 擦除指定扇区(地址对齐到4KB边界) void spi_flash_erase_sector(uint32_t sector_addr) { // 1. 写使能 spi_cs_enable(); spi_transfer(CMD_WRITE_ENABLE); spi_cs_disable(); // 2. 发送扇区擦除命令和地址(24位地址,高位在前) spi_cs_enable(); spi_transfer(CMD_SECTOR_ERASE); spi_transfer((sector_addr >> 16) & 0xFF); // 地址高8位 spi_transfer((sector_addr >> 8) & 0xFF); // 地址中8位 spi_transfer(sector_addr & 0xFF); // 地址低8位 spi_cs_disable(); // 3. 等待擦除完成 while (spi_flash_is_busy()); // 等待Flash就绪 } ``` #### 2. 写入功能测试 **目标**:向指定地址写入数据(如"Hello"),并验证写入正确。 **步骤**: 1. 确保目标扇区已擦除(否则先擦除)。 2. 发送写使能命令。 3. 发送页编程命令(`CMD_PAGE_PROGRAM`)并指定地址,然后发送数据。 4. 等待写入完成。 **示例代码**: ```c // 向指定地址写入数据(单页内,不超过256字节) void spi_flash_write_page(uint32_t addr, uint8_t *data, uint16_t len) { // 1. 写使能 spi_cs_enable(); spi_transfer(CMD_WRITE_ENABLE); spi_cs_disable(); // 2. 发送页编程命令和地址 spi_cs_enable(); spi_transfer(CMD_PAGE_PROGRAM); spi_transfer((addr >> 16) & 0xFF); // 地址高8位 spi_transfer((addr >> 8) & 0xFF); // 地址中8位 spi_transfer(addr & 0xFF); // 地址低8位 // 3. 发送数据 for (uint16_t i = 0; i < len; i++) { spi_transfer(data[i]); } spi_cs_disable(); // 4. 等待写入完成 while (spi_flash_is_busy()); } // 测试写入"Hello"到地址0x000100 void test_write(void) { uint8_t data[] = "Hello"; spi_flash_write_page(0x000100, data, 5); } ``` #### 3. 读取功能测试 **目标**:从指定地址读取数据,验证与写入数据一致。 **步骤**: 1. 发送读命令(`CMD_READ_DATA`)并指定地址。 2. 连续读取数据。 **示例代码**: ```c // 从指定地址读取数据 void spi_flash_read(uint32_t addr, uint8_t *buf, uint16_t len) { spi_cs_enable(); spi_transfer(CMD_READ_DATA); spi_transfer((addr >> 16) & 0xFF); // 地址高8位 spi_transfer((addr >> 8) & 0xFF); // 地址中8位 spi_transfer(addr & 0xFF); // 地址低8位 // 连续读取数据 for (uint16_t i = 0; i < len; i++) { buf[i] = spi_transfer(0xFF); // 发送哑数据(0xFF)以产生时钟 } spi_cs_disable(); } // 测试读取地址0x000100的5字节数据 void test_read(void) { uint8_t buf[5]; spi_flash_read(0x000100, buf, 5); // 比较buf内容是否为"Hello" } ``` ### 三、完整测试流程 ```mermaid graph TD A[开始] --> B[初始化SPI] B --> C[擦除扇区0] C --> D[写入数据到扇区0] D --> E[从扇区0读取数据] E --> F{比较数据是否一致} F -->|一致| G[测试通过] F -->|不一致| H[测试失败] ``` ### 四、关键注意事项 1. **地址对齐**: - 扇区擦除地址必须对齐到4KB边界(如0x000000, 0x001000)[^2]。 - 页写入不能跨页(每页256字节),若写入长度超页边界需拆分操作。 2. **等待就绪**: 所有擦除/写入操作后必须检查状态寄存器忙位(Bit 0),直到为0[^3]: ```c uint8_t spi_flash_is_busy(void) { return (spi_flash_read_status() & 0x01); // Bit0=1表示忙 } ``` 3. **写保护**: 若擦除/写入失败,需检查状态寄存器的写保护位(如Bit 1,2,3)并禁用保护[^2]。 --- ### 总结 测试SPI Flash的核心操作流程为:**擦除→写入→读取→验证**。 - **擦除**:以扇区为单位,擦除后数据全为0xFF。 - **写入**:使用页编程命令,每次最多写入256字节。 - **读取**:直接发送读命令和地址即可。 > 工程提示:实际测试时建议先读取芯片ID(`CMD_READ_ID`)确认通信正常[^3],再执行擦写测试。 --- ### 相关问题 1. SPI Flash的页编程和扇区擦除有什么区别? 2. 如何通过状态寄存器判断SPI Flash的操作状态? 3. 多扇区连续写入时如何优化SPI Flash擦写速度? 4. SPI Flash的寿命和写次数有什么关系?</think>### SPI Flash功能测试指南:擦除、读取与写入 下面以常见的Winbond W25Q系列SPI Flash为例,详细说明测试流程和代码实现。测试基于SPI寄存器传输(8位模式),需确保已完成SPI初始化[^1][^3]。 --- ### 一、测试准备 1. **硬件连接** ```mermaid graph LR MCU[主控制器] -- MOSI --> Flash[SPI Flash] MCU -- MISO <-- Flash MCU -- SCK --> Flash MCU -- CS --> Flash ``` - CS(片选)低电平有效 - 典型时钟频率:1-100MHz(需查芯片手册) 2. **关键命令定义**(以W25Q128JV为例) ```c #define CMD_WRITE_ENABLE 0x06 // 写使能 #define CMD_WRITE_DISABLE 0x04 // 写禁止 #define CMD_READ_STATUS 0x05 // 读状态寄存器 #define CMD_PAGE_PROGRAM 0x02 // 页编程(写入) #define CMD_SECTOR_ERASE 0x20 // 扇区擦除(4KB) #define CMD_READ_DATA 0x03 // 读取数据 ``` --- ### 二、擦除功能测试 #### 步骤说明 1. 发送写使能命令 2. 发送扇区擦除命令 + 24位地址 3. 等待擦除完成(状态寄存器BUSY位清零) #### 示例代码 ```c /* 擦除指定扇区(4KB)*/ void erase_sector(uint32_t sector_addr) { // 1. 写使能 spi_cs_low(); // CS拉低 spi_transfer(CMD_WRITE_ENABLE); // 发送0x06 spi_cs_high(); // CS拉高 // 2. 发送擦除命令 spi_cs_low(); spi_transfer(CMD_SECTOR_ERASE); // 0x20 spi_transfer(sector_addr >> 16); // 地址高8位 spi_transfer(sector_addr >> 8); // 地址中8位 spi_transfer(sector_addr); // 地址低8位 spi_cs_high(); // 3. 等待擦除完成 while(is_busy()); // 轮询状态寄存器 } /* 检查BUSY状态位 */ uint8_t is_busy(void) { spi_cs_low(); spi_transfer(CMD_READ_STATUS); // 0x05 uint8_t status = spi_transfer(0xFF); // 读状态寄存器 spi_cs_high(); return (status & 0x01); // BIT0=1表示忙 } ``` **验证方法**: 擦除后读取扇区数据应全为`0xFF`[^2][^3]。 --- ### 三、写入功能测试 #### 步骤说明 1. 发送写使能命令 2. 发送页编程命令 + 24位地址 + 数据 3. 等待写入完成(最大页写入256字节) #### 示例代码 ```c /* 写入数据到指定地址 */ void write_data(uint32_t addr, uint8_t *data, uint16_t len) { // 1. 写使能 spi_cs_low(); spi_transfer(CMD_WRITE_ENABLE); spi_cs_high(); // 2. 发送写入命令和数据 spi_cs_low(); spi_transfer(CMD_PAGE_PROGRAM); // 0x02 spi_transfer(addr >> 16); // 地址高8位 spi_transfer(addr >> 8); // 地址中8位 spi_transfer(addr); // 地址低8位 for(int i=0; i<len; i++) { spi_transfer(data[i]); // 逐字节写入 } spi_cs_high(); // 3. 等待写入完成 while(is_busy()); } ``` **关键限制**: - 单次写入不能跨页(地址对齐256字节边界) - 写入前必须擦除目标区域[^2] --- ### 四、读取功能测试 #### 步骤说明 1. 发送读命令 + 24位地址 2. 连续读取数据(无写入等待) #### 示例代码 ```c /* 从指定地址读取数据 */ void read_data(uint32_t addr, uint8_t *buf, uint16_t len) { spi_cs_low(); spi_transfer(CMD_READ_DATA); // 0x03 spi_transfer(addr >> 16); // 地址高8位 spi_transfer(addr >> 8); // 地址中8位 spi_transfer(addr); // 地址低8位 for(int i=0; i<len; i++) { buf[i] = spi_transfer(0xFF); // 哑数据产生时钟 } spi_cs_high(); } ``` **特点**: - 读取无需等待 - 可连续读取跨页数据 --- ### 五、完整测试流程 ```mermaid graph TD A[初始化SPI] --> B[擦除测试扇区] B --> C[写入测试数据] C --> D[读取数据] D --> E{数据比对} E -->|匹配| F[测试通过] E -->|不匹配| G[测试失败] ``` **示例测试代码**: ```c // 主测试函数 void test_spi_flash(void) { uint8_t write_buf[4] = {0xAA, 0x55, 0xF0, 0x0F}; uint8_t read_buf[4] = {0}; uint32_t test_addr = 0x001000; // 测试地址 erase_sector(test_addr); // 擦除扇区 write_data(test_addr, write_buf, 4); // 写入4字节 read_data(test_addr, read_buf, 4); // 读取4字节 // 验证数据 if(memcmp(write_buf, read_buf, 4) == 0) { printf("Test PASSED\n"); } else { printf("Test FAILED\n"); } } ``` --- ### 六、调试要点 1. **状态寄存器解析**: ```c // 典型状态寄存器格式 BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 WPEN | 保留 | 保留 | BP2 | BP1 | BP0 | WEL | BUSY ``` - `BUSY=1`:芯片忙(擦除/写入中) - `WEL=1`:写使能锁存器已置位[^3] 2. **示波器观测**: - 检查CS、SCK、MOSI/MISO波形 - 验证命令序列是否符合时序图 3. **错误处理**: - 超时机制:所有等待操作需加超时判断 - 写保护检查:若写入失败,检查状态寄存器WPEN位 > **重要提示**:不同厂商Flash命令可能不同,务必查阅具体芯片手册[^3][^4]。 --- ### 相关问题 1. SPI Flash的页编程和扇区擦除有什么区别? 2. 如何通过状态寄存器判断SPI Flash的操作状态? 3. 多扇区连续写入时如何优化SPI Flash擦写速度? 4. SPI Flash的寿命和写次数有什么关系?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值