You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F4 QuadSPI读取W25Q32JV厂商/设备ID值异常问题

QSPI读取Flash ID异常:如何发送3个0x00哑字节?

我需要向外部Flash发送指令0x90,随后发送3个0x00哑字节,其余配置无问题。厂商ID为1字节,设备ID为2字节,因此读取长度设为3,地址为0x00,但目前读取的值不正确。以下是相关代码:

QSPI初始化函数

static void MX_QUADSPI_Init(void)
{

/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 0;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 23;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_2;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
}

读取Flash ID的函数

void QSPI_Flash_ID_Read(uint8_t *data, int length, uint32_t address){

QSPI_AutoPollingMemReady(&hqspi);
QSPI_CommandTypeDef sCommand;

sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;

/* Reading Sequence ------------------------------------------------ */
sCommand.Instruction = 0x90;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.Address     = address;
sCommand.NbData      = length;
sCommand.DataMode    = QSPI_DATA_4_LINES;
sCommand.DummyCycles = 0;

HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);

HAL_QSPI_Receive(&hqspi, data, 1000);
}

问题分析与解决方案

0x90指令的典型时序是指令(1线) → 24位地址(1线) → 3个0x00哑字节 → 4线读取ID数据。当前代码的核心问题是跳过了"发送3个0x00哑字节"的步骤,直接在地址后开始读取数据,导致时序不匹配。

方案:分阶段发送指令、哑字节并读取ID

通过两次QSPI命令完成完整时序:先发送指令、地址和3个哑字节,再保持CS拉低的状态下读取ID数据。修改后的函数如下:

void QSPI_Flash_ID_Read(uint8_t *data, int length, uint32_t address){
    QSPI_AutoPollingMemReady(&hqspi);
    QSPI_CommandTypeDef sCommand;
    uint8_t dummy_bytes[3] = {0x00, 0x00, 0x00};

    // 第一阶段:发送指令、24位地址、3个0x00哑字节
    sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
    sCommand.AddressMode       = QSPI_ADDRESS_1_LINE;
    sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
    sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
    sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
    sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
    
    sCommand.Instruction = 0x90;
    sCommand.Address     = address;
    sCommand.NbData      = 3;          // 指定发送3个哑字节
    sCommand.DataMode    = QSPI_DATA_1_LINE;  // 用1线模式发送哑字节
    sCommand.DummyCycles = 0;

    HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
    HAL_QSPI_Transmit(&hqspi, dummy_bytes, 1000);

    // 第二阶段:读取ID数据(无需重复发送指令和地址)
    sCommand.InstructionMode   = QSPI_INSTRUCTION_NONE;
    sCommand.AddressMode       = QSPI_ADDRESS_NONE;
    sCommand.NbData            = length;
    sCommand.DataMode          = QSPI_DATA_4_LINES;

    HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
    HAL_QSPI_Receive(&hqspi, data, 1000);
}

关键说明

  1. 哑周期≠哑字节:DummyCycles参数对应的是时钟周期数,不是字节数。你需要的是发送3个0x00字节,因此必须通过数据发送阶段完成,无法通过修改DummyCycles实现。
  2. 时钟速度验证:ClockPrescaler = 0会让QSPI时钟等于AHB时钟,需确保该速度在你的Flash芯片允许范围内,否则可能导致数据读取错误。
  3. Flash容量匹配:FlashSize = 23对应2^24字节(16MB),如果你的Flash容量不符,需调整该参数。

内容的提问来源于stack exchange,提问作者Ahmed Jamal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:25:46