Dick_cdz 发表于 5 天前

AI8051U QSPI BUSY问题?

AI8051U QSPI读写穿行FLASH ,地址:0000000,上电擦除后写32字节后是不时死循环在 QSPI_CheckBusy();查FIFO=0;请大神帮忙看什么原因?
void QSPI_READ_INSTR_SDATA(BYTE cmd, BYTE *pdat, WORD datalen)的 while (QSPI_CheckBusy());屏蔽后可正常写和读。



正常的数据


不正常数据,发完32字节数据就死循环检测忙标记,后面的05命令就没发了

/----------------------------------------------------------------------------------
void        DMA_QSPI_SEND(DWORD addr)
{
                while (QSPI_CheckBusy());
                BLE_SEND_DATA=~BLE_SEND_DATA;
                BLE_SEND_DATA=~BLE_SEND_DATA;
                BLE_SEND_DATA=~BLE_SEND_DATA;
                BLE_SEND_DATA=~BLE_SEND_DATA;
       
                W25Q_DMA_PageProgram_32(addr, BLE_SEND_DATA, 32);                               

}
//-----------------------------------------------------------------------------------



void W25Q_DMA_PageProgram_32(DWORD addr, BYTE *pdat, WORD datalen)                        //BYTE
{
    W25Q_WriteEnable_06();
       
    QSPI_DMA_WRITE_INSTR_SADDR24_QDATA(0x32, addr, pdat, datalen);
       
    W25Q_WaitBusy(100);
       
       
}



//-----------------------------------------------------------------------------------



void QSPI_DMA_WRITE_INSTR_SADDR24_QDATA(BYTE cmd, DWORD addr, BYTE *pdat, WORD datalen)        //byte
{
    while (QSPI_CheckBusy());       //检测忙状态
               
    QSPI_SetWriteMode();            //写模式
    QSPI_SetDataLength(datalen-1);//设置数据长度
    QSPI_SetAddressSize(2);         //设置地址宽度为24位(2+1字节)
    QSPI_SetDummyCycles(0);         //设置DUMMY时钟
    QSPI_NoInstruction();         //设置无指令模式(防止误触发)
    QSPI_NoAddress();               //设置无地址模式(防止误触发)
    QSPI_NoAlternate();             //无间隔字节
    QSPI_DataQuadMode();            //设置数据为四线模式
    QSPI_SetInstruction(cmd);       //设置指令
    QSPI_SetAddress(addr);          //设置地址
    QSPI_InstructionSingMode();   //设置指令为单线模式
    QSPI_AddressSingMode();         //设置地址为单线模式
   
    QSPI_DMA_WRITE(pdat, datalen);
}



//-----------------------------------------------------------------------------------



void QSPI_DMA_WRITE(BYTE *pdat, WORD datalen)
{
        /
                //DMA_QSPI_ITVL=0x04;
                //DMA_QSPI_ITVH=0x02;
    DMA_QSPI_AMT = datalen-1;       //设置DMA数据长度
    DMA_QSPI_AMTH = (datalen-1) >> 8;
    DMA_QSPI_TXAH = (WORD)pdat >> 8;//设置DMA的存储器起始地址
    DMA_QSPI_TXAL = (BYTE)pdat;   //设置DMA的存储器起始地址
    DMA_QSPI_STA = 0x00;            //清除DMA状态
    DMA_QSPI_CFG = 0x40;            //使能DMA写操作
    DMA_QSPI_CR = 0xc2;             //启动DMA并触发QSPI写操作
               
       
   while (!(DMA_QSPI_STA & 0x01)); //等待DMA操作完成
    DMA_QSPI_STA = 0x00;            //清除DMA状态
    DMA_QSPI_CFG = 0x00;
    DMA_QSPI_CR = 0x00;
       
               
       
   QSPI_ClearTimeout();
    QSPI_ClearMatch();
    QSPI_ClearError();
               
}

//-----------------------------------------------------------------------------------

BYTE W25Q_ReadSR1_05()
{
    BYTE dat;
   
    QSPI_READ_INSTR_SDATA(0x05, (BYTE *)&dat, 1);

    return dat;
}
//-----------------------------------------------------------------------------------
void W25Q_WaitBusy(int n)       //自动轮询周期时间单位: us
{
    while (W25Q_ReadSR1_05() & 0x01) --n;

    if (n);
//    QSPI_POLLING_READ_INSTR_SDATA(0x05, 0x01, 0x00, 12*n);
}

//-----------------------------------------------------------------------------------

void QSPI_READ_INSTR_SDATA(BYTE cmd, BYTE *pdat, WORD datalen)
{
    while (QSPI_CheckBusy());       //检测忙状态

    QSPI_SetReadMode();             //读模式
    QSPI_SetDataLength(datalen-1);//设置数据长度
    QSPI_SetDummyCycles(0);         //设置DUMMY时钟
    QSPI_InstructionSingMode();   //设置指令为单线模式
    QSPI_NoAddress();               //无地址字节
        QSPI_NoAlternate();             //无间隔字节
    QSPI_DataSingMode();            //设置数据为单线模式
    QSPI_SetInstruction(cmd);       //设置指令
            
    while (!QSPI_CheckTransfer());//等到数据传输完成
    QSPI_ClearTransfer();         //清除传输完成标志

    while (datalen)
    {
      *pdat = QSPI_ReadData();    //从FIFO中读取数据
      pdat++;
      datalen--;
    }
   
    while (QSPI_CheckFIFOLevel())   //清空FIFO
      QSPI_ReadData();
               
}



国芯人工智能 发表于 5 天前

关于AI8051U QSPI BUSY问题的分析与建议如下:

根据您提供的描述,AI8051U在使用QSPI接口对W25Q系列Flash进行读写操作时,在地址0x0000000上执行擦除后写入32字节数据的过程中,出现死循环卡在QSPICheckBusy()函数中。进一步观察发现,当屏蔽该检查语句后,程序可正常运行,表明问题可能与QSPI忙状态检测机制相关。

一、可能原因分析

1. QSPI控制器状态未正确释放
   在完成一次写操作后,QSPI控制器可能未及时释放“busy”标志,导致后续操作无法继续。这可能是由于DMA传输未完全完成,或QSPI内部状态机未进入空闲状态所致。

2. DMA配置不正确
   若DMA配置错误(如传输长度、缓冲区地址、中断触发方式等),可能导致数据未正确写入Flash,从而引发QSPI控制器持续处于“busy”状态。

3. Flash芯片响应异常
   W25Q系列Flash在接收到写指令后,会进入编程状态并返回忙状态信号(BSY)。若Flash未正确响应,或在写入过程中发生错误,可能导致QSPI控制器持续检测到“busy”。

4. QSPICheckBusy()逻辑缺陷
   QSPICheckBusy()函数可能存在逻辑问题,例如未正确读取Flash的“busy”位,或读取时机不当,导致误判。

5. 时序问题
   QSPI操作对时序要求较高,若主从设备之间的时钟相位、延迟设置不匹配,也可能导致Flash无法正确响应指令,进而引发“busy”状态持续。

二、排查建议

1. 验证QSPICheckBusy()实现
   检查QSPICheckBusy()函数是否正确读取了Flash的“busy”状态。通常可通过发送读状态寄存器指令(如0x05)并读取返回值来判断。

   c
   BYTE QSPICheckBusy(void)
   {
       BYTE status;
       QSPIWRITECMD(0x05); // 读状态寄存器指令
       QSPIREADDATA(&status, 1);
       return (status & 0x01); // BSY位为第0位
   }

   确保该函数能准确反映Flash的忙状态。

2. 检查DMA传输完整性
   确认W25QDMAPageProgram32(addr, BLESENDDATA, 32)函数是否正确配置DMA通道,并确保DMA传输完成后触发相应的中断或标志位。可在DMA传输完成后添加延时或等待标志位,以确保QSPI控制器已准备好。

3. 增加调试输出
   在QSPICheckBusy()前后添加调试信息(如打印当前状态寄存器值),帮助定位“busy”状态是否由Flash实际响应引起。

4. 测试其他地址或数据
   尝试将写入地址改为非0x0000000位置,或写入不同大小的数据(如16字节),观察是否仍出现相同问题,以判断是否为特定地址或数据的问题。

5. 检查Flash初始化流程
   确保在写入前已正确执行擦除操作,且擦除完成后Flash已恢复正常状态。某些Flash在擦除后需要一定时间恢复,若立即写入可能引发异常。

三、临时解决方案

若您暂时无法定位根本原因,可考虑以下临时措施:
在关键操作前后添加延时:例如在QSPICheckBusy()调用前后加入短延时(如1ms),以确保QSPI控制器有足够时间处理状态变化。
优化DMA传输流程:确保DMA传输完成后,QSPI控制器已释放“busy”状态后再进行下一次操作。

四、结论

综上所述,AI8051U在QSPI操作中出现死循环问题,很可能与QSPI控制器状态检测机制或Flash响应异常有关。建议优先排查QSPICheckBusy()函数的实现逻辑及DMA传输配置,并结合调试信息进一步定位问题根源。

如需进一步协助,请提供完整的QSPI驱动代码及Flash操作流程图,以便更深入分析。

[本文内容由国芯人工智能辅助生成,仅供参考]

ercircle 发表于 5 天前


使用这个例程试下,可使用编好的固件配合工具先测一下硬件
SPI / QSPI 编程外部串行Flash | 配合ISP软件中【工具 | 串行Flash编程器】,2/5 - QSPI/3组SPI/I2S/I2C,一线制温湿度传感器 国芯人工智能技术交流网站 - AI32位8051交流社区

Dick_cdz 发表于 5 天前

ercircle 发表于 2025-8-29 12:44
使用这个例程试下,可使用编好的固件配合工具先测一下硬件
SPI / QSPI 编程外部串行Flash | 配合ISP软件中 ...

用的是芯天下的FLASH XT25F64F,FLASH工具试了没反应,自己的程序可以读到ID是没问题的。写了数据也可以读到,就是写数据有时正常,有时死循环while (QSPI_CheckBusy());       //检测忙状态

ercircle 发表于 5 天前

Dick_cdz 发表于 2025-8-29 16:54
用的是芯天下的FLASH XT25F64F,FLASH工具试了没反应,自己的程序可以读到ID是没问题的。写了数据也可以读 ...


这个demo读写过大量动图没问题的。

然后,没用过XT25这款FLASH,上面这个工具默认读写的是W25Q,是否支持pin2pin先替换这个型号测试完再换回去?


或者对比下qspi读写函数差异。

Dick_cdz 发表于 5 天前

国芯人工智能 发表于 2025-8-29 12:33
关于AI8051U QSPI BUSY问题的分析与建议如下:

根据您提供的描述,AI8051U在使用QSPI接口对W25Q系列Flash ...

一、可能原因分析

1. QSPI控制器状态未正确释放
   在完成一次写操作后,QSPI控制器可能未及时释放“busy”标志,导致后续操作无法继续。这可能是由于DMA传输未完全完成,或QSPI内部状态机未进入空闲状态所致。
问:有可能,那怎样才能释放释放“busy”标志?

2. DMA配置不正确
   若DMA配置错误(如传输长度、缓冲区地址、中断触发方式等),可能导致数据未正确写入Flash,从而引发QSPI控制器持续处于“busy”状态。
答:这个可能性很少,检查过长度和地址,中断没打开,也写了中断响应处理,预防误开。而且可从FALSH读回数据,验证数据正确。

3. Flash芯片响应异常
   W25Q系列Flash在接收到写指令后,会进入编程状态并返回忙状态信号(BSY)。若Flash未正确响应,或在写入过程中发生错误,可能导致QSPI控制器持续检测到“busy”。
问:这点FLASH规格书没有看到说明在IO上有BSY返回,只读状态寄器判断,如发送命令05H.

4. QSPICheckBusy()逻辑缺陷
   QSPICheckBusy()函数可能存在逻辑问题,例如未正确读取Flash的“busy”位,或读取时机不当,导致误判。
答:这点一直在等待,while (QSPI_CheckBusy()); #defineQSPI_CheckBusy(QSPI_SR1 & 0x20) 或while (QSPI_SR1 & 0x20==0x20);换过几种方式

5. 时序问题
   QSPI操作对时序要求较高,若主从设备之间的时钟相位、延迟设置不匹配,也可能导致Flash无法正确响应指令,进而引发“busy”状态持续。
问:可以写入,也能读回。应该没问题?

二、排查建议

1. 验证QSPICheckBusy()实现
   检查QSPICheckBusy()函数是否正确读取了Flash的“busy”状态。通常可通过发送读状态寄存器指令(如0x05)并读取返回值来判断。

    答:QSPICheckBusy()只是判断AI8051U的QSPI忙标记。发05是可以读回FLASH 状态
页: [1]
查看完整版本: AI8051U QSPI BUSY问题?