ZYNQ QSPI Flash读写操作详解
一、QSPI Flash
QSPI(Quad SPI)是一种高速串行通信接口,在ZYNQ SoC中常用于连接外部Flash存储器。相比标准SPI,QSPI使用4条数据线并行传输,显著提高了数据传输速率。
二、硬件连接
ZYNQ QSPI Flash典型连接方式:
- QSPI_CLK:时钟信号
- QSPI_SS:片选信号
- QSPI_IO0:数据线0(MOSI)
- QSPI_IO1:数据线1(MISO)
- QSPI_IO2:数据线2(WP#)
- QSPI_IO3:数据线3(HOLD#/RESET#)
三、软件配置
1. Vivado硬件平台配置
- 在Block Design中添加ZYNQ Processing System IP
- 在PS-PL Configuration中启用Quad SPI Flash
- 配置正确的Flash型号和参数
2. SDK/Xilinx Vitis软件配置
#include "xqspips.h" // QSPI驱动头文件
#include "xparameters.h" // 硬件参数头文件
#define QSPI_DEVICE_ID XPAR_XQSPIPS_0_DEVICE_ID
XQspiPs QspiInstance; // QSPI实例
四、初始化QSPI控制器
int init_qspi() {
XQspiPs_Config *QspiConfig;
int Status;
// 查找QSPI配置
QspiConfig = XQspiPs_LookupConfig(QSPI_DEVICE_ID);
if (QspiConfig == NULL) {
return XST_FAILURE;
}
// 初始化QSPI驱动
Status = XQspiPs_CfgInitialize(&QspiInstance, QspiConfig, QspiConfig->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
// 设置QSPI时钟
XQspiPs_SetClkPrescaler(&QspiInstance, XQSPIPS_CLK_PRESCALE_8);
// 选择Flash设备
XQspiPs_SetOptions(&QspiInstance, XQSPIPS_FORCE_SSELECT_OPTION |
XQSPIPS_MANUAL_START_OPTION);
return XST_SUCCESS;
}
五、Flash读写操作
1. 读取Flash ID
int read_flash_id(u8 *id_buffer) {
u8 command[4] = {0x9F, 0, 0, 0}; // 读取ID命令
XQspiPs_SetSlaveSelect(&QspiInstance, 0); // 选择Flash设备0
// 发送命令并接收响应
XQspiPs_PolledTransfer(&QspiInstance, command, id_buffer, 4);
return XST_SUCCESS;
}
2. 页编程(写入)操作
int write_flash_page(u32 address, u8 *write_buffer, u32 byte_count) {
u8 command[4];
u8 write_enable = 0x06; // 写使能命令
// 发送写使能命令
XQspiPs_SetSlaveSelect(&QspiInstance, 0);
XQspiPs_PolledTransfer(&QspiInstance, &write_enable, NULL, 1);
// 构建页编程命令(0x02)
command[0] = 0x02; // 页编程命令
command[1] = (address >> 16) & 0xFF; // 地址高字节
command[2] = (address >> 8) & 0xFF; // 地址中字节
command[3] = address & 0xFF; // 地址低字节
// 发送页编程命令和数据
XQspiPs_SetSlaveSelect(&QspiInstance, 0);
XQspiPs_PolledTransfer(&QspiInstance, command, NULL, 4);
XQspiPs_PolledTransfer(&QspiInstance, write_buffer, NULL, byte_count);
// 等待写入完成
return wait_for_flash_ready();
}
3. 读取操作
int read_flash_data(u32 address, u8 *read_buffer, u32 byte_count) {
u8 command[4];
// 构建读取命令(0x03)
command[0] = 0x03; // 标准读取命令
command[1] = (address >> 16) & 0xFF;
command[2] = (address >> 8) & 0xFF;
command[3] = address & 0xFF;
// 发送读取命令并接收数据
XQspiPs_SetSlaveSelect(&QspiInstance, 0);
XQspiPs_PolledTransfer(&QspiInstance, command, NULL, 4);
XQspiPs_PolledTransfer(&QspiInstance, NULL, read_buffer, byte_count);
return XST_SUCCESS;
}
4. 扇区擦除
int erase_flash_sector(u32 address) {
u8 command[4];
u8 write_enable = 0x06;
// 发送写使能命令
XQspiPs_SetSlaveSelect(&QspiInstance, 0);
XQspiPs_PolledTransfer(&QspiInstance, &write_enable, NULL, 1);
// 构建扇区擦除命令(0x20)
command[0] = 0x20;
command[1] = (address >> 16) & 0xFF;
command[2] = (address >> 8) & 0xFF;
command[3] = address & 0xFF;
// 发送擦除命令
XQspiPs_SetSlaveSelect(&QspiInstance, 0);
XQspiPs_PolledTransfer(&QspiInstance, command, NULL, 4);
// 等待擦除完成
return wait_for_flash_ready();
}
六、辅助函数
等待Flash就绪
int wait_for_flash_ready() {
u8 command[2] = {0x05, 0}; // 读取状态寄存器命令
u8 status;
do {
XQspiPs_SetSlaveSelect(&QspiInstance, 0);
XQspiPs_PolledTransfer(&QspiInstance, command, &status, 2);
} while (status & 0x01); // 检查忙标志位
return XST_SUCCESS;
}
七、注意事项
-
Flash特性:
- 写入前必须先擦除(通常以扇区为单位)
- 擦除和写入操作需要一定时间完成
- 不同Flash芯片的命令集可能略有不同
-
性能优化:
- 使用Quad模式(4线模式)提高传输速率
- 合理设置时钟分频器
- 考虑使用DMA传输大数据块
-
错误处理:
- 检查所有操作的返回值
- 实现超时机制防止死锁
- 验证写入数据的正确性
-
多设备支持:
- 通过片选信号支持多个Flash设备
- 每个设备需要独立的配置和操作
八、高级功能
- 双QSPI模式:某些ZYNQ型号支持双QSPI控制器,可并行操作提高吞吐量
- XIP(Execute In Place):配置QSPI Flash为可执行存储器,直接从Flash运行代码
- 加密:使用ZYNQ内置的加密引擎保护Flash内容
通过以上步骤和代码示例,您可以实现ZYNQ QSPI Flash的基本读写操作。根据具体应用需求,可以进一步优化和扩展这些功能。
(www.nzw6.com)