ST意法半导体
直播中

贾大林

8年用户 1403经验值
私信 关注
[问答]

不一致的HAL_SPI_TransmitReceive错误问题如何解决?

我正在使用 STM32F411(SPI 主设备)和 STM32F303(SPI 从设备)运行一个简单的 SPI 发送接收项目。每当我按下 STM32F4 Master 上的用户按钮时,Master 将通过 SPI 发送命令字节 (0xE1),STM32F3 Slave 预计会以 4 个特定字节响应。下面的逻辑分析器快照是我期望每个按钮都会发生的情况:

我大概可以多次得到准确的 SPI 事务。然而,大多数时候,下面的快照是发生了什么:



经过多次测试后,我几乎可以肯定是 Slave 的问题,因为:
  • Master 几乎始终传输通过逻辑分析仪观察到的正确数据
  • STM32F3 Slave 实际上接收到正确的数据(命令字节和 4 个虚拟字节)
奇怪的是我使用:
  • /* Exchange 4 bytes with SPI Master and store dummy bytes in pTempRxBuff */
  • HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)pTxBuff, (uint8_t*)pTempRxBuff, cTxLen, 10000);
接收部分工作正常,但发送部分工作不正常。
我确保 CPOL、CPHA、MSB 位在前、波特率预分频器、APB2 时钟速度(在两个 STM32 板上)、8 位数据大小和 SPI 方向 2 线在两个板之间是相同的。
我还将 STM32F4 Master 配置为以 16MHz 运行,而 STM32F3 Slave 以 64MHz(带 PLL)运行,希望从属设备可以更快地处理数据并在主设备为 SPI 计时以从中检索 4 个字节之前做好准备奴隶。它没有按预期工作。
我的主要问题:
STM32F3 Slave 大部分时间都没有发送正确的数据(通常是发送的某些字节中的 1 位)。
我的SPI从机(STM32F303)代码:
这是我的初始化代码:
  • static void MX_SPI1_Init(void)
  • {
  •    /* SPI1 parameter configuration*/
  •    hspi1.Instance = SPI1;
  •    hspi1.Init.Mode = SPI_MODE_SLAVE;
  •    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  •    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  •    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  •    hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  •    hspi1.Init.NSS = SPI_NSS_SOFT;
  •       hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;     // Recently added
  •    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  •    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  •    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  •    hspi1.Init.CRCPolynomial = 7;
  •    hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  •    hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  •    if (HAL_SPI_Init(&hspi1) != HAL_OK)
  •    {
  •       Error_Handler();
  •    }
  •    /* Set spi interrupt priority and enable spi interrupts */
  •    HAL_NVIC_SetPriority(SPI1_IRQn, 1, 1);
  •    HAL_NVIC_EnableIRQ(SPI1_IRQn);
  • }
我发送的数据:
  • #define RX_COMMAND_LENGTH                1
  • #define TX_LENGTH                        4
  • static uint16_t cRxCmdLen = RX_COMMAND_LENGTH;
  • static uint16_t cTxLen = TX_LENGTH;
  • /* SPI Receive variables */
  • /* Command byte received to be stored in pRxBuff */
  • static volatile uint8_t pRxBuff[RX_COMMAND_LENGTH] = {0x00};
  • /* 4 dummy bytes to be stored in pTempRxBuff */
  • static uint8_t pTempRxBuff[TX_LENGTH] = {0x00, 0x00, 0x00, 0x00};
  • /* SPI Send variables */
  • /* temporary dummy value to be exchanged with the command byte */
  • static const uint8_t dummybyte[1] = {0x99};
  • /* 4 bytes to be sent to the Master */
  • static const uint8_t pTxBuff[TX_LENGTH] = {0xEB, 0x00, 0xCC, 0x01};
  • /* Exchange message flag for processing in main while loop */
  • volatile FlagStatus ExchangeMessage = RESET;
SPI 中断处理程序:
  • void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
  • {
  •    /* SPI1 peripheral used to exchange data with master device */
  •    if(hspi->Instance == SPI1)
  •    {
  •       /* If command byte received is 0xE1 */
  •       if(pRxBuff[0] == 0xE1)
  •       {
  •          /* Set volatile flag to high for processing 4 byte exchange in main loop */
  •          ExchangeMessage = SET;
  •       }
  •       else
  •       {
  •          /* Ignore garbage data that was received */
  •          /* Configure microcontroller to listen to other command bytes */
  •          HAL_SPI_TransmitReceive_IT(&hspi1, (uint8_t*)dummybyte, (uint8_t*)pRxBuff, cRxCmdLen);
  •       }
  •    }
  • }
主要的 while 循环:
  • while (1) {
  •    if(ExchangeMessage == SET) {
  •       /* Exchange 4 bytes with the master device */
  •       HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)pTxBuff, (uint8_t*)pTempRxBuff, cTxLen, 10000);
  •       /* Reset volatile flag - this gets activated when a correct command byte is received*/
  •       ExchangeMessage = RESET;
  •       /* Configure microcontroller to start listening to command bytes again */
  •       HAL_SPI_TransmitReceive_IT(&hspi1, (uint8_t*)dummybyte, (uint8_t*)pRxBuff, cRxCmdLen);
  •    }
  • }
我的 SPI 主机(STM32F411)代码:
主 while 循环:
  • while (1) {
  •    /* SendCmdByte is SET whenever a GPIO interrupt (push button) fires */
  •    if(SendCmdByte == SET) {
  •       /* Transmit first command byte 0xE1 */
  •       uint8_t garbage[1] = {0x00};       // buffer for garbage value - expected: 0x99
  •       HAL_SPI_Transmit(&hspi1, (uint8_t*)pTxBuff, cTxLen, spi_timeout);
  •       /* Wait for end of spi transmission */
  •       while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
  •       /* use i<150 for ~100 us delay to wait for slave to fill data*/
  •       for(volatile uint16_t i=0; i<100; i++);
  •       /* Transmit remaining 4 bytes of dummy value */
  •       HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)pTempTxBuff, (uint8_t*)pRxBuff, cRxLen, spi_timeout);
  •       /* Toggle LED after successfully exchanging bytes with dongle */
  •       ToggleLed();
  •       /* Reset received buffer values */
  •       pRxBuff[0] = 0x00;
  •       pRxBuff[1] = 0x00;
  •       pRxBuff[2] = 0x00;
  •       pRxBuff[3] = 0x00;
  •       /* Reset volatile flag - this flag will be SET at every GPIO push button interrupt */
  •       SendCmdByte = RESET;
  •    }
  • }
我对这个问题的尝试:
  • 我已经尝试将所有 GPIO 引脚速度(FREQ_HIGH、FREQ_MEDIUM、FREQ_LOW)用于主设备和从设备上的相关 SPI 引脚,并且它对数据没有任何影响
  • 我已经尝试降低 APB2 总线速度并增加 SPI 波特率以获得更低的 SPI 速度,但这对不准确性没有帮助
  • 我已经尝试过 register 方法,它以某种方式仅在第一次尝试时有效,但在第一次测试后不适用于所有其他尝试
  • 我改变了 HAL_SPI_TransmitReceive() 函数中的 spi_timeout 参数,它有助于移动字节,但不准确的位仍然存在
  • 我还尝试在函数 HAL_SPI_TxRxCpltCallback() 上使用有限状态机方法,但我无法让它在第二个 HAL_SPI_TransmitReceive_IT() 中执行,但回调不会在第二个中断中执行(为交换的 4 字节编程)
这里可能是什么问题?我在 SPI 交易中遗漏了什么吗?如何解决此同步问题?









回帖(1)

高彬

2023-2-1 10:36:39
您的逻辑分析仪上的 CPHA 设置似乎与您设备上的 CPHA 设置不匹配。波形是一样的。
举报

更多回帖

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