一、AXI QSPI的模式
1.PL端配置:
记得接中断引脚,虽然代码里没用,但是似乎涉及到一些状态机,会导致返回值错误
2.PS端初始化:
int hal_axi_spi_init(XSpi *xspi, uint16_t dev_id, uint8_t slave_id)
{
int Status;
XSpi_Config *xspi_cfg;
xspi_cfg = XSpi_LookupConfig(dev_id);
if (xspi_cfg == NULL) {
return XST_DEVICE_NOT_FOUND;
}
/* 初始化控制器 */
Status = XSpi_CfgInitialize(xspi, xspi_cfg,
xspi_cfg->BaseAddress);
if (Status != XST_SUCCESS) {
return Status;
}
/* 硬件自检 */
Status = XSpi_SelfTest(xspi);
if (Status != XST_SUCCESS) {
return Status;
}
/* 验证SPI模式是否为Quad模式 */
if (xspi->SpiMode != XSP_QUAD_MODE) {
return XST_FLASH_NOT_SUPPORTED;
}
/* 配置控制器选项 */
Status = XSpi_SetOptions(xspi,
XSP_MASTER_OPTION |
XSP_MANUAL_SSELECT_OPTION);
if(Status != XST_SUCCESS) {
return Status;
}
/* 设置从设备选择 */
Status = XSpi_SetSlaveSelect(xspi, 1 << slave_id);
if(Status != XST_SUCCESS)
{
return Status;
}
/* 启动SPI控制器 */
Status = XSpi_Start(xspi);
if(Status != XST_SUCCESS) {
return Status;
}
/* 禁用中断以使用轮询模式 */
XSpi_IntrGlobalDisable(xspi);
return XST_SUCCESS;
}
3.此时QSPI的模式:Quad Output
也就是命令和地址发送使用1线,数据收发使用4线;
二、读写w25q256之类大容量flash,Xilinx的坑
(笔者多次提到的,xilinx坑爹的印度程序老哥,能用就行,从不多测试 TAT )
1.xilinx的例程
默认只支持3Byte地址模式,使用指令0x6B读取,0x32写入,0x20擦除;
这是笔者测试完成的,3Byte读写擦的,部分关键代码:
(这里有个疑惑,为什么要用0x01 00 02,设置quad模式,这和手册上的完全对不上)
int qspi_w25qxx_init(QSPI_W25QXX_T *qspi_w25qxx,
int (*qspi_transf)(uint8_t *tx, uint8_t *rx, uint16_t len),
void (*delay)(uint32_t us))
{
memset(qspi_w25qxx, 0, sizeof(QSPI_W25QXX_T));
qspi_w25qxx->hal.qspi_transf = qspi_transf;
qspi_w25qxx->hal.delay = delay;
qspi_w25qxx->status.error = 0;
// reboot
// qspi_w25qxx_reboot(qspi_w25qxx);
// enable QSPI 4 line (QUAD) mode
qspi_w25qxx_quad_en(qspi_w25qxx);
// enable 4byte address mode
#if ADDR4BYTE_EN
qspi_w25qxx_addr4byte_en(qspi_w25qxx);
#endif
// read ID
qspi_w25qxx_read_id(qspi_w25qxx);
//check
if((qspi_w25qxx->reg.id & 0x00EF0000) != 0x00EF0000)
{
//Quad mode error
qspi_w25qxx->status.error |= 1<<(0);
}
if((qspi_w25qxx->reg.state[1] & 0x02) == 0)
{
//Quad mode error
qspi_w25qxx->status.error |= 1<<(1);
}
// if((qspi_w25qxx->reg.state[2] & 0x01) == 0)
// {
// //4Byte Addr mode err
// qspi_w25qxx->status.error |= 1<<(2);
// }
return qspi_w25qxx->status.error;
}
static void qspi_w25qxx_quad_en(QSPI_W25QXX_T *qspi_w25qxx)
{
qspi_w25qxx_write_en(qspi_w25qxx);
qspi_w25qxx->buf.tx[0] = 0x01;
qspi_w25qxx->buf.tx[1] = 0x00;
qspi_w25qxx->buf.tx[2] = 0x02; // Status Register-2的QE位(Bit 1)
qspi_w25qxx_transf(qspi_w25qxx, qspi_w25qxx->buf.tx, NULL, 3, TIMEOUT_MAX_US);
qspi_w25qxx->buf.tx[0] = READ_REG_2_CMD;
qspi_w25qxx->buf.tx[1] = 0x00;
qspi_w25qxx_transf(qspi_w25qxx, qspi_w25qxx->buf.tx, qspi_w25qxx->buf.rx, 2, 0);
qspi_w25qxx->reg.state[1] = qspi_w25qxx->buf.rx[1];
}
2.针对4Byte模式的修正
(2025-4-10,zzl:目前这个我还没测试通过,后续测试成功后,我把代码放在这里)
如果需要使用4Byte地址模式,应该使用0x6C读取,0x34写入,0x21擦除;
(2025-5-21,zzl:测试了几天,实在无法兼容Quad模式,改用Standard模式,裸机和petalinux都正常了)
引脚用Q0 Q1 CLK CS即可,flash手册和zynq的io设置都有标注