ST意法半导体
直播中

感谢相遇

10年用户 1058经验值
擅长:嵌入式技术 制造/封装 控制/MCU
私信 关注
[问答]

STM32F405使用LL库建立SPI通讯报溢出的原因?

调试了2周,尝试各种办法,修改参数,修改速度,重新建立工程,尝试查询、中断、DAM方式接收SPI数据均提示数据溢出,并且接收的数据也不对,要么是0,要么是65525。已经排除了硬件问题,因为使用HAL库可以实现SPI通讯,下面是程序截图:

回帖(1)

廖阿朋

2025-3-17 18:01:19

针对使用LL库时SPI通讯溢出的问题,以下是可能的原因及解决方案:




1. 溢出标志未正确清除



  • 原因:SPI接收溢出(OVR标志)触发后,若未按顺序清除标志,将导致持续报错。

  • 解决方案
    // 当检测到溢出时,按顺序读取DR和SR寄存器以清除标志
    if (LL_SPI_IsActiveFlag_OVR(SPI1)) {
    LL_SPI_ClearFlag_OVR(SPI1);  // 通过读取DR和SR清除OVR标志
    }




2. SPI时钟配置与主从设备不匹配



  • 原因:CPOL(时钟极性)或CPHA(时钟相位)与从设备不一致,导致数据采样错误。

  • 解决方案
    // 检查主从设备的CPOL和CPHA设置
    LL_SPI_SetClockPolarity(SPI1, LL_SPI_POLARITY_LOW);  // CPOL=0
    LL_SPI_SetClockPhase(SPI1, LL_SPI_PHASE_1EDGE);      // CPHA=0




3. 数据位长度配置错误



  • 原因:数据帧长度(8位或16位)与实际传输的数据不匹配。

  • 解决方案
    // 明确设置数据长度为8位或16位
    LL_SPI_SetDataWidth(SPI1, LL_SPI_DATAWIDTH_8BIT);  // 8位数据




4. 接收数据未及时读取



  • 原因:在查询/中断模式下,未及时读取RX缓冲区的数据,导致新数据覆盖旧数据。

  • 解决方案(查询模式示例)
    // 发送数据后立即等待接收完成
    LL_SPI_TransmitData8(SPI1, tx_data);
    while (!LL_SPI_IsActiveFlag_RXNE(SPI1));  // 等待接收完成
    rx_data = LL_SPI_ReceiveData8(SPI1);      // 及时读取数据




5. DMA配置错误



  • 原因:DMA传输方向、内存地址或数据长度配置错误。

  • 解决方案
    // 配置DMA接收通道
    LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_0, buffer_size);
    LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_0, (uint32_t)rx_buffer);
    LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_0, LL_SPI_DMA_GetRegAddr(SPI1));
    LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_0);




6. NSS引脚管理不当



  • 原因:硬件NSS未启用或软件NSS控制逻辑错误。

  • 解决方案
    // 使用软件控制NSS时,手动拉低/拉高片选信号
    LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4);  // 拉低NSS
    // 执行SPI传输...
    LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4);     // 拉高NSS




7. SPI使能顺序错误



  • 原因:过早使能SPI外设,导致配置未生效。

  • 解决方案
    // 最后一步再使能SPI
    LL_SPI_Enable(SPI1);




调试建议



  1. 检查寄存器状态:使用调试器查看SPI的CR1CR2SR寄存器值,确认配置与实际操作一致。

  2. 信号测量:用示波器或逻辑分析仪观察SCK/MOSI/MISO波形,确认时序符合预期。

  3. 对比HAL库配置:通过HAL库生成的代码对比LL库配置,查找遗漏的步骤(如标志清除、DMA初始化顺序等)。




参考代码片段(全双工查询模式)


// SPI初始化(主机模式,8位数据)
void SPI_Init(void) {
  LL_SPI_Disable(SPI1);
  LL_SPI_SetMode(SPI1, LL_SPI_MODE_MASTER);
  LL_SPI_SetDataWidth(SPI1, LL_SPI_DATAWIDTH_8BIT);
  LL_SPI_SetClockPolarity(SPI1, LL_SPI_POLARITY_LOW);
  LL_SPI_SetClockPhase(SPI1, LL_SPI_PHASE_1EDGE);
  LL_SPI_SetBaudRatePrescaler(SPI1, LL_SPI_BAUDRATEPRESCALER_DIV8);
  LL_SPI_Enable(SPI1);
}

// 发送并接收1字节数据
uint8_t SPI_Transfer(uint8_t tx_data) {
  while (!LL_SPI_IsActiveFlag_TXE(SPI1));  // 等待发送缓冲区空
  LL_SPI_TransmitData8(SPI1, tx_data);
  while (!LL_SPI_IsActiveFlag_RXNE(SPI1)); // 等待接收完成
  return LL_SPI_ReceiveData8(SPI1);         // 读取数据
}

通过以上步骤排查,应能解决SPI溢出问题。若仍有异常,建议提供具体配置代码片段以便进一步分析。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分