- 若该文为原创文章,未经允许不得转载
- 风释雪
- QQ:627833006
- E-mail:hn.cy@foxmail.com
- CSDN博客地址:https://blog.csdn.net/weixin_46718879
目录
1.版本说明
Data | Author | Version Revision |
---|---|---|
2021/12/11 | abner | 1.0 初定版本 |
2. 目标
zynq PS端裸核下实现QSPI FLASH的擦除、读、写,并保存用户所需要的信息。
FPGA芯片 : ZYNQ7010
FLASH芯片 :N25Q128A
硬件连接为 :Single SS 4-bit IO => Data Mode x4
3.FLASH芯片分析
3.1 FLASH芯片 :N25Q128A
支持协议:Extended SPI, dual I/O, and quad I/O , 分别对应数据线x1/x2/x4
擦除大小:4KB/64KB/Full-chip
容量/扇区:128 = 128Mbit = 16MByte
= 256个sectors x 64KB(每个sectors的容量)
= 256个sectors x 16个subsectors x 4KB (每个sectors包含16个subsectors,每个subsectors容量为4KB)
= 4066个subsectors x 4KB (每个subsectors容量为4KB)
= 65536 x 256Byte(page size)
需要注意,写的时候以page为单位,但是擦除的时候最小单位是4KB
3.2 FLASH操作指令
标准命令适用于不同厂家不同型号的FLASH
3.2.1 FLASH操作指令之读设备ID
接口形式 :Extended SPI
指令数据 :9Fh + Manufacturer identification (1Byte) + Device identification (2Byte)+ UID
指令格式 :TX CMD + RX DATA x N (N实际常用值为3)
以上三个输出由芯片厂家决定,当前N25Q128A 输出为:20h BAh 18h
3.2.2 FLASH操作指令之写使能
接口形式 :Extended SPI/D-SPI/Q-SPI
指令数据 :06h
3.2.3 FLASH操作指令之写失能
接口形式 :Extended SPI/D-SPI/Q-SPI
指令数据 :04h
3.2.4 FLASH操作指令之读状态寄存器
接口形式 :Extended SPI/D-SPI/Q-SPI
指令数据 :05h + Status (1Byte)
8bit映射 : 7-2bit 大部分情况下可忽略, 写使能锁定1bit,擦除/写正在进行/设备忙0bit
3.2.5 FLASH操作指令之擦除指令
接口形式 :Extended SPI/D-SPI/Q-SPI
指令数据 :20h/D8h/C7h
操作步骤 :
- 写使能 06h
- 可选1 写擦除指令“全片擦除” C7h
- 可选2 写擦除指令“64K擦除” D8h + Addr (3Byte)
- 可选3 写擦除指令“4K擦除” 20h + Addr (3Byte)
- 重复查状态寄存器直到确定设备处于空闲状态
- 重点要注意,单次擦除的最小区域是4K,所以对于不想擦除的数据需要预先读出来,然后擦除,最后同要写的数据一起更新到FLASH
3.2.6 FLASH操作指令之写指令
接口形式 :Extended SPI/D-SPI/Q-SPI
指令数据 :03h + Addr (3Byte) + TX (Max 256byte)
操作步骤 :
- 写使能 06h
- 写指令 03h + Addr (3Byte) + TX (Max 256byte)
- 重复查状态寄存器直到确定设备处于空闲状态
- 重点要注意,该写数据过程为页编程,因此单词最大可编程空间为256Byte
3.2.7 FLASH操作指令之读指令
接口形式 :Extended SPI/D-SPI/Q-SPI
指令数据 :02h + Addr (3Byte) + RX (Nbyte)
可选读指令比较多,如没有性能要求,最基本的读即可完成,若对性能有要求可以开启QSPI然后快速输出
3.2.8 FLASH操作指令之使能Q-SPI模式
暂时没有需求(但是原理一样,通过指令完成操作)
3.XILINX资料分析
XILINX的QSPI FLASH控制器支持三种模式:I/O mode, linear addressing mode, and legacy SPI mode
I/O mode : 读写QSPI FLASH时使用;支持QSPI并不是说一定要使用QSPI模式读写FLASH,仍然可以可以SPI接口操作FLASH
linear addressing mode : 只读FLASH时使用,通过地址映射后,可以像访问内存一样读数据,需要注意单个FLASH只能映射到16MB
legacy SPI mode : 传统SPI模式,此时控制器就是一个普通的SPI控制器;
3.1.XILINX QSPI接口配置流程
- XQspiPs_LookupConfig 硬件信息
- XQspiPs_Config 配置
- XQspiPs_CfgInitialize 初始化
- XQspiPs_SelfTest 自检
- XQspiPs_SetOptions 设置操作模式
- XQspiPs_SetClkPrescaler 设置时钟
- XQspiPs_SetSlaveSelect 选择FLASH设备
3.2.初始化代码
printf("----- info : Init QSPI \r\n");
XQspiPs_Config *QspiConfig;
/* Initialize the QSPI driver so that it's ready to use*/
QspiConfig = XQspiPs_LookupConfig(XPAR_XQSPIPS_0_DEVICE_ID);
if (QspiConfig == NULL)
{
return false;
}
Status = XQspiPs_CfgInitialize(&QspiInstance, QspiConfig,
QspiConfig->BaseAddress);
if (Status != XST_SUCCESS)
{
return false;
}
/* Perform a self-test to check hardware build*/
Status = XQspiPs_SelfTest(&QspiInstance);
if (Status != XST_SUCCESS)
{
return false;
}
/*
* Set Manual Start and Manual Chip select options and drive HOLD_B
* pin high.
*/
XQspiPs_SetOptions(&QspiInstance, XQSPIPS_MANUAL_START_OPTION |
XQSPIPS_FORCE_SSELECT_OPTION |
XQSPIPS_HOLD_B_DRIVE_OPTION);
XQspiPs_SetClkPrescaler(&QspiInstance, XQSPIPS_CLK_PRESCALE_8);
XQspiPs_SetSlaveSelect(&QspiInstance);
3.3.测试代码
uint8_t FlashWriteBuffer[10];
uint8_t FlashReadBuffer [10];
FlashWriteBuffer[0] = 0x9F;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, &FlashReadBuffer, 1+3);
if (Status != XST_SUCCESS) {
return false;
}
// 读状态
FlashWriteBuffer[0] = 0x05;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, &FlashReadBuffer,1+1);
if (Status != XST_SUCCESS) {
return false;
}
// 写使能
FlashWriteBuffer[0] = 0x06;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, NULL, 1+0);
if (Status != XST_SUCCESS) {
return false;
}
// 读状态
FlashWriteBuffer[0] = 0x05;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, &FlashReadBuffer,1+1);
if (Status != XST_SUCCESS) {
return false;
}
// 擦除整片
FlashWriteBuffer[0] = 0xC7;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, NULL, 1+0);
if (Status != XST_SUCCESS) {
return false;
}
do
{
// 查询 设备状态
FlashWriteBuffer[0] = 0x05;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, &FlashReadBuffer, 1+1);
if (Status != XST_SUCCESS) {
return false;
}
} while (FlashReadBuffer[1] != 0x00);
// 读数据擦除后全是FF
FlashWriteBuffer[0] = 0x03;
FlashWriteBuffer[1] = 0; // Addr
FlashWriteBuffer[2] = 0; // Addr
FlashWriteBuffer[3] = 0; // Addr
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, &FlashReadBuffer, 4+6);
if (Status != XST_SUCCESS) {
return false;
}
// 写使能
FlashWriteBuffer[0] = 0x06;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, NULL, 1+0);
if (Status != XST_SUCCESS) {
return false;
}
// 写数据
FlashWriteBuffer[0] = 0x02;
FlashWriteBuffer[1] = 0;
FlashWriteBuffer[2] = 0;
FlashWriteBuffer[3] = 0;
FlashWriteBuffer[4] = 4;
FlashWriteBuffer[5] = 5;
FlashWriteBuffer[6] = 6;
FlashWriteBuffer[7] = 7;
FlashWriteBuffer[8] = 8;
FlashWriteBuffer[9] = 9;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, NULL, 4+6);
if (Status != XST_SUCCESS) {
return false;
}
do
{
// 查询 设备状态
FlashWriteBuffer[0] = 0x05;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, &FlashReadBuffer,1+1);
if (Status != XST_SUCCESS) {
return false;
}
} while (FlashReadBuffer[1] != 0x00);
// 读数据校验
FlashWriteBuffer[0] = 0x03;
FlashWriteBuffer[1] = 0;
FlashWriteBuffer[2] = 0;
FlashWriteBuffer[3] = 0;
Status = XQspiPs_PolledTransfer(&QspiInstance, &FlashWriteBuffer, &FlashReadBuffer, 4+6);
if (Status != XST_SUCCESS) {
return false;
}
4.注意事项
不同型号的FLASH,操作命令,单次擦除空间会有区别,需要根据Datasheet来更改
5.可扩展
QSPI模式下的相关操作暂未实现。