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

