• 正文
  • 相关推荐
申请入驻 产业图谱

STM32 XSPI 禁用自动校准时钟实战:GPIO 片选驱动双 QSPI LCD 解决方案

12/22 14:36
147
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

XSPI 默认会在数据传输前(片选高电平时)输出自动校准时钟,确保通信稳定性,但使用 GPIO 替代硬件片选驱动多 QSPI 设备时,该时钟会导致数据同步异常(如 LCD 点不亮)。核心解决方案:在最后一次写 XSPI_DCR2/CCR 寄存器与下一次传输之间,读写一次 XSPI_CALSOR 或 XSPI_CALSIR 寄存器,即可禁用自动校准时钟输出。

资料获取:开发经验 | LAT1548 如何让XSPI不输出自动校准时钟

1. 问题背景:校准时钟引发的多设备驱动异常

1.1 应用场景

客户使用 STM32 的 XSPI 外设驱动两个 QSPI LCD,通过普通 GPIO 软件控制片选(分时切换两个设备),而非 XSPI 硬件片选引脚

1.2 异常现象

LCD 初始化时无法点亮,逻辑分析仪抓取到关键问题:

  • XSPI 在 GPIO 片选拉低(有效)前,会输出一串额外时钟(自动校准时钟);
  • 硬件片选场景下,片选高电平时的校准时钟不影响通信,但 GPIO 软件片选无法同步该时钟,导致 LCD 接收无效数据,启动失败。

2. 核心原理:XSPI 自动校准的触发与禁用规则

2.1 自动校准的作用

XSPI 的自动校准是默认行为,传输前通过输出校准时钟更新校准参数,补偿时序偏差,确保高速通信的可靠性。

2.2 禁用自动校准的关键条件

根据 STM32 参考手册,满足以下条件即可跳过自动校准(不输出校准时钟):

  • 最后一次写 XSPI_DCR2(设备配置寄存器 2)或 XSPI_CCR(命令配置寄存器) 之后;
  • 下一次 XSPI 传输启动之前;
  • 执行一次XSPI_CALSOR(校准输出寄存器)或 XSPI_CALSIR(校准输入寄存器)的读写操作

2.3 核心逻辑

手动读写 CALSOR/CCSIR 寄存器后,XSPI 会认为已通过软件配置校准参数,无需再执行自动校准,从而避免额外时钟输出。

3. 实操方案:代码实现与验证

以 STM32H7S3 Nucleo 板为例,外扩 Quad PSRAM 验证方案有效性,核心是在 XSPI 传输前添加 CALSOR 寄存器操作,以下是完整实现代码。

3.1 关键代码修改(禁用校准时钟)

XSPI 写操作(禁用校准时钟)

uint8_t XSPI_RAM_Write(uint32_t addr, uint8_t *data, uint32_t size) {
  XSPI_RegularCmdTypeDef sCommand = {0};
  __IO uint32_t xspi_calsor;  // 存储校准寄存器值

  // 1. 配置XSPI命令(根据设备手册调整指令、地址模式等参数)
  sCommand.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
  sCommand.IOSelect = HAL_XSPI_SELECT_IO_3_0;
  sCommand.Instruction = 0x38;  // QSPI写指令(需匹配设备)
  sCommand.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
  sCommand.AddressMode = HAL_XSPI_ADDRESS_4_LINES;
  sCommand.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
  sCommand.Address = addr;
  sCommand.DataLength = size;
  sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
  sCommand.DataMode = HAL_XSPI_DATA_4_LINES;
  sCommand.DummyCycles = 0;
  sCommand.DTRMode相关 = HAL_XSPI_DTR_DISABLE;  // 禁用DTR模式

  // 2. 发送XSPI命令(配置DCR2/CCR寄存器)
  if (HAL_XSPI_Command(&hxspi1, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
    return false;
  }

  // 3. 关键操作:读写CALSOR寄存器,禁用自动校准
  xspi_calsor = hxspi1.Instance->CALSOR;  // 读CALSOR
  hxspi1.Instance->CALSOR = xspi_calsor;  // 写回原数值(无修改,仅触发禁用逻辑)

  // 4. 传输数据(此时无校准时钟输出)
  if (HAL_XSPI_Transmit(&hxspi1, data, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
    return false;
  }
  return true;
}

XSPI 读操作(保留校准时钟,对比验证)

uint8_t XSPI_RAM_Read(uint32_t addr, uint8_t *data, uint32_t size) {
  XSPI_RegularCmdTypeDef sCommand = {0};

  // 配置XSPI读命令(指令0xEB为快速读指令,需匹配设备)
  sCommand.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
  sCommand.IOSelect = HAL_XSPI_SELECT_IO_3_0;
  sCommand.Instruction = 0xEB;
  sCommand.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
  sCommand.AddressMode = HAL_XSPI_ADDRESS_4_LINES;
  sCommand.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
  sCommand.Address = addr;
  sCommand.DataLength = size;
  sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
  sCommand.DataMode = HAL_XSPI_DATA_4_LINES;
  sCommand.DummyCycles = 6;  // 读操作需配置虚拟周期

  // 发送命令+接收数据(未操作CALSOR,保留校准时钟)
  if (HAL_XSPI_Command(&hxspi1, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
    return false;
  }
  if (HAL_XSPI_Receive(&hxspi1, data, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
    return false;
  }
  return true;
}

3.2 验证结果

通过逻辑分析仪抓取波形,关键结论:

  • 写操作(已禁用校准):GPIO 片选拉低前,无额外校准时钟输出,数据传输正常;
  • 读操作(未禁用校准):片选拉低前,仍有校准时钟输出(符合预期);
  • 实际应用:将该写操作逻辑移植到双 QSPI LCD 驱动中,成功避免无效时钟,LCD 正常点亮。

4. 关键注意事项

  1. 校准参数保障:禁用自动校准前,需确保 XSPI 已完成有效校准(如初始化时执行一次读 ID、复位命令,触发自动校准获取初始参数);
  2. 寄存器选择:CALSOR 和 CALSIR 均可,推荐使用 CALSOR(操作更简洁,无需额外配置);
  3. 命令顺序:必须在 “最后一次写 DCR2/CCR”(即 HAL_XSPI_Command 之后)和 “传输启动”(HAL_XSPI_Transmit/Receive 之前)之间操作 CALSOR;
  4. 设备兼容性:该方案适用于所有支持 XSPI 的 STM32 系列(如 H7、U5、H5),需根据设备手册调整指令、地址宽度等参数。

XSPI 的自动校准时钟是默认的可靠性保障,但在 GPIO 软件片选、多设备分时驱动等场景下会成为障碍。通过 “传输前读写 CALSOR/CCSIR 寄存器” 的简单操作,即可禁用该时钟,且不影响通信稳定性。核心是利用 XSPI 的软件校准优先级高于自动校准的设计逻辑,兼顾灵活性与可靠性。

相关推荐