STM32 B-L4S5I-IOT01A板BlueNRG-MS SPI通信无响应求助
STM32L4S5与BlueNRG-MS SPI通信收全0问题排查与解决
我使用B-L4S5I-IOT01A开发板(主控为STM32L4S5VIT6),该板通过SPI3连接BlueNRG-MS模块。我通过以下函数配置BLE相关的SPI:
HAL_StatusTypeDef ble_init() { __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitTypeDef gpio; gpio.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; // PC10 - SPI3_CLK, PC11 - SPI3_MISO, PC12 - SPI3_MOSI gpio.Mode = GPIO_MODE_AF_PP; gpio.Alternate = GPIO_AF6_SPI3; HAL_GPIO_Init(GPIOC, &gpio); __HAL_RCC_GPIOD_CLK_ENABLE(); GPIO_InitTypeDef gpio_cs; gpio.Pin = GPIO_PIN_13; // PD13 - SPBTLE-RF-SPI3_CSN gpio.Mode = GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(GPIOD, &gpio_cs); __HAL_RCC_SPI3_CLK_ENABLE(); spi.Instance = SPI3; spi.Init.Mode = SPI_MODE_MASTER; spi.Init.Direction = SPI_DIRECTION_2LINES; spi.Init.NSS = SPI_NSS_SOFT; spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; HAL_StatusTypeDef status = HAL_SPI_Init(&spi); __HAL_SPI_ENABLE(&spi); return status; } HAL_StatusTypeDef spi_send_recv(uint8_t *send_buf, uint8_t *recv_buf, size_t size) { HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(&spi, send_buf, recv_buf, size, HAL_MAX_DELAY); return status; }
我理解SPI通信流程应为:拉低CS引脚,收发数据,再拉高CS引脚。根据BlueNRG-MS蓝牙手册,第一个接收字节应返回正确状态值0x02,但目前我接收的所有字节均为0。请问还需要执行哪些额外步骤才能正常使用该SPI通信?
主函数代码如下:
int main() { SystemCoreClock = 4000000; HAL_Init(); ble_init(); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET); while (1) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET); uint8_t tx[5] = {0x0a,0,0,0,0}; uint8_t rx[5]; spi_send_recv(tx, rx, 5); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET); } }
排查与解决步骤
补全SPI关键初始化参数:当前SPI配置缺少时钟极性、相位等核心参数,必须与BlueNRG-MS的默认配置匹配:
spi.Init.CLKPolarity = SPI_POLARITY_LOW; // 模块默认时钟空闲为低电平 spi.Init.CLKPhase = SPI_PHASE_1EDGE; // 第一个时钟沿采样数据 spi.Init.DataSize = SPI_DATASIZE_8BIT; // 明确8位数据传输 spi.Init.FirstBit = SPI_FIRSTBIT_MSB; // 蓝牙模块通常采用MSB先发修正CS引脚初始化错误:代码中定义了
gpio_cs结构体,但初始化时错误传入了&gpio,导致PD13配置失效,修正后需加上上拉和速度配置:GPIO_InitTypeDef gpio_cs; gpio_cs.Pin = GPIO_PIN_13; gpio_cs.Mode = GPIO_MODE_OUTPUT_PP; gpio_cs.Pull = GPIO_PULLUP; // 上拉避免引脚浮空 gpio_cs.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOD, &gpio_cs);执行BlueNRG-MS复位流程:模块上电后需要复位才能进入工作状态,需按硬件设计操作复位引脚(查B-L4S5I-IOT01A原理图确认复位引脚,比如PD12):
// 示例:假设复位引脚为PD12 __HAL_RCC_GPIOD_CLK_ENABLE(); GPIO_InitTypeDef gpio_rst; gpio_rst.Pin = GPIO_PIN_12; gpio_rst.Mode = GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(GPIOD, &gpio_rst); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); HAL_Delay(10); // 拉低复位至少10ms HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); HAL_Delay(50); // 等待模块初始化完成修正系统时钟配置:不要直接硬写
SystemCoreClock,应调用SystemCoreClockUpdate()获取实际时钟值,确保SPI时钟计算准确:int main() { HAL_Init(); SystemCoreClockUpdate(); // 替换硬写的SystemCoreClock赋值 ble_init(); // ... 后续代码 }增加时序延迟:拉低CS后需给模块足够的检测时间,收发完成后确保数据传输完毕再拉高CS:
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET); HAL_Delay(1); // 短延迟确保模块识别CS拉低 spi_send_recv(tx, rx, 5); HAL_Delay(1); // 等待最后一个字节传输完成 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);验证命令格式合法性:确认发送的
0x0A命令符合BlueNRG-MS的帧格式要求,部分命令需要前缀、长度字段或校验位,需严格遵循手册定义的通信协议。
内容的提问来源于stack exchange,提问作者Witnes
相关产品推荐
相关产品推荐

