我正在使用 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 交易中遗漏了什么吗?如何解决此同步问题?
0
|
|
1个回答
|
|
|
|