#5607·embassy

STM32N6 SPI 吊挂

作者: jake-taf创建于 2026年3月5日更新于 2026年9月11日

blocking_read 执行的步骤

  1. 禁用 SPI (清除 CR1.SPE)。Embassy 文档中提到,这需要“避免过溢导致 SPI RX 状态机卡死…?”。
  2. 设置字节大小 (CFG1.DSIZE = 0x7 (8 位)),如果已经设置则跳过。
  3. 启用 SPI (设置 CR1.SPE)。
  4. 清空 RX FIFO (从 RX 数据寄存器中读取数据,直到 RXP 置位)。
  5. 等待 TX FIFO 中有空间 (SR.TXP 置位) (或 TI 帧格式错误,模式故障,CRC 错误,过溢)。
  6. 向 TX 数据寄存器写入零。
  7. 启动主机传输 (设置 CR1.CSTART)。
  8. 等待 RX FIFO 中有数据 (SR.RXP 置位) (或 TI 帧格式错误,模式故障,CRC 错误,过溢) [在此处陷入,因为 RXP 标志从未置位]
  9. 从 RX 数据寄存器读取数据。

测试代码

以下代码用于触发问题。实际上,它向 SPI 发送写入和读取请求。请注意,SPI 总是同时发送数据两个方向。写入实际上是(发送数据,丢弃接收数据),而读取是(发送零,接收数据)。 此代码写入两个随机选择的字节,然后读取数据。

zzterm4zz
let mut spi_config = spi::Config::default();
spi_config.frequency = Hertz(100_000);
let spi = spi::Spi::new_blocking(
  p.SPI5, // SPI
  p.PE15, // SCK
  p.PG2,  // MOSI
  p.PH8,  // MISO
  spi_config,
);
let mut chip_select = Output::new(p.PA3, Level::High, Speed::VeryHigh);
loop {
    let mut spi_buf = [33_u8; 1];
    info!("SPI Buffer: {}", spi_buf);
    chip_select.set_low();
    spi.write(&[0x03_u8, 0x2c_u8]);
    spi.read(&mut spi_buf);
    chip_select.set_high();
    info!("SPI Buffer: {}", spi_buf);
}

RXP 标志(参考手册)

该标志由硬件改变。它监控当 SPI 启用时 RxFIFO 中当前可用的数据总数。RXP 值取决于 FIFO 阈值 (FTHLV[3:0])、数据帧大小 (SPI 模式下的 DSIZE[4:0] 和 I2S/PCM 模式下的 DATLEN[1:0]) 以及实际通信流。如果通过连续从 SPI_RXDR 中读取数据来读取数据包,则必须再次检查 RXP 标志,直到从 RxFIFO 中读取完整的数据包。

内容来源: embassy-rs/embassy