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

STM32L0 SPI通信始终返回HAL_SPI_ERROR_MODF问题求助

STM32L0 SPI连接LSM6DSR出现HAL_SPI_ERROR_MODF错误排查

我用STM32L0通过SPI连接LSM6DSR,所有代码由CubeMX生成(包含X-CUBE-MEMS1提供的LSM6DSR驱动)。当前遇到两个核心问题:

  • 调用SPI收发函数(Transmit、Receive、Transmit/Receive)时,始终返回HAL_SPI_ERROR_MODF错误;
  • 设置SPI_POLARITY_HIGH时,SCK线无法保持空闲高电平,尝试配置GPIO内部上拉也未解决MODF错误。

SPI1仅连接LSM6DSR一个从设备,STM32L0为唯一主设备。

SPI初始化代码(CubeMX生成)

__weak HAL_StatusTypeDef MX_SPI1_Init(SPI_HandleTypeDef* hspi)
{
  HAL_StatusTypeDef ret = HAL_OK;

  hspi->Instance = SPI1;
  hspi->Init.Mode = SPI_MODE_MASTER;
  hspi->Init.Direction = SPI_DIRECTION_2LINES;
  hspi->Init.DataSize = SPI_DATASIZE_8BIT;
  hspi->Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi->Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi->Init.NSS = SPI_NSS_SOFT;
  hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi->Init.TIMode = SPI_TIMODE_DISABLE;
  hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi->Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(hspi) != HAL_OK)
  {
    ret = HAL_ERROR;
  }

  return ret;
}

IMU初始化代码

static int32_t IMU_Init(void){
  //Initialize LSM6DSR
  LSM6DSR_IO_t            io_ctx;
  uint8_t                 id;
  static LSM6DSR_Object_t lsm6dsr_obj_0;
  int32_t ret = BSP_ERROR_NONE;

    /* Configure the accelero driver */
  io_ctx.BusType     = LSM6DSR_SPI_4WIRES_BUS; /* SPI with CS */
  io_ctx.Address     = NULL; //Doesn't have an address for SPI
  io_ctx.Init        = BSP_SPI1_Init;
  io_ctx.DeInit      = BSP_SPI1_DeInit;
  io_ctx.ReadReg     = BSP_SPI1_SendRecv;
  io_ctx.WriteReg    = BSP_SPI1_SendRecv;
  io_ctx.GetTick     = BSP_GetTick;

  if (LSM6DSR_RegisterBusIO(&lsm6dsr_obj_0, &io_ctx) != LSM6DSR_OK)
  {
    ret = BSP_ERROR_UNKNOWN_COMPONENT;
  }
  else if (LSM6DSR_ReadID(&lsm6dsr_obj_0, &id) != LSM6DSR_OK) 
  {
    ret = BSP_ERROR_UNKNOWN_COMPONENT;
    Error_Handler();
  }
  else if (id != LSM6DSR_ID)
  {
    ret = BSP_ERROR_UNKNOWN_COMPONENT;
  }
  else
  {
    // Customization Part:
    // Enable Accelerometer only

    // Disable the Gyro
    if(LSM6DSR_GYRO_Disable(&lsm6dsr_obj_0) != LSM6DSR_OK)
    {
      ret = BSP_ERROR_COMPONENT_FAILURE;
    }

    //Setup Accelero
    if(LSM6DSR_ACC_SetOutputDataRate(&lsm6dsr_obj_0, 104.0f) != LSM6DSR_OK)
    {
      ret = BSP_ERROR_COMPONENT_FAILURE;
    }
    if(LSM6DSR_ACC_SetFullScale(&lsm6dsr_obj_0, LSM6DSR_ACC_SENSITIVITY_FS_4G) != LSM6DSR_OK)
    {
      ret = BSP_ERROR_COMPONENT_FAILURE;
    }

    //Setup Interrupt for wake up

    //Enable Accelero
    if(LSM6DSR_ACC_Enable(&lsm6dsr_obj_0) != LSM6DSR_OK)
    {
      ret = BSP_ERROR_COMPONENT_FAILURE;
    }

  }
  return ret;
}

排查建议

  1. 处理MODF错误根源
    MODF错误是主设备模式下检测到NSS引脚为低电平触发的。即便配置了SPI_NSS_SOFT,部分STM32L0的SPI硬件仍会监测NSS引脚状态:
  • 将NSS引脚(PA4,SPI1_NSS)配置为推挽输出,初始化时置高,SPI收发前拉低,完成后拉高;
  • 避免NSS引脚浮空,必要时外接上拉电阻。
  1. 修复SCK空闲电平异常
  • 检查SCK引脚(PA5)的GPIO配置:确保是复用推挽输出,速度等级设为高速;
  • 若内部上拉不足,外接10kΩ上拉电阻;
  • 确认HAL_SPI_Init调用的GPIO初始化参数,确保Mode和Pull配置符合要求。
  1. 降低SPI时钟速率
    当前配置SPI_BAUDRATEPRESCALER_2,若STM32L0主频为32MHz,SPI时钟达16MHz,超过LSM6DSR支持的最大10MHz速率:
  • 改为SPI_BAUDRATEPRESCALER_4(8MHz)或更低的分频系数。
  1. 完善CS引脚控制逻辑
    X-CUBE-MEMS1驱动需用户手动实现CS引脚的硬件控制:
  • 修改BSP_SPI1_SendRecv函数,在收发操作前拉低CS,完成后拉高;
  • 确保io_ctx中注册的读写函数包含完整的CS控制流程。
  1. 排查硬件接线
  • 检查SCK、MOSI、MISO、CS引脚的接线是否正确,有无虚焊、短路;
  • 确认MISO引脚未被异常拉低,避免主设备误判总线状态。

内容的提问来源于stack exchange,提问作者Travis Su

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 00:01:03