您好,我正在尝试与 STM32 IoT 开发套件中的 ES-WIFI 模块进行通信。 wifi模块默认通过SPI2连接(要使用UART,我必须使用SPI刷新模块的固件)。我想将 AT 命令从 UART 串行监视器传输到 wifi 模块,并接收返回到 PC 串行监视器的响应。所以,我想接收来自USART1(pc-uart)的消息并将数据传输到SPI2。同样,应从 SPI2 读取响应并将其传输到 USART1。还有一点是,数据传输应该是可变长度的。
当我运行程序时,调试器在 SPI 状态寄存器 TXE 不为空时停止。并且 FIFO 传输级别已满(FTLVM:11)。谁能告诉我我做错了什么。
void USART1_IRQHandler(void)
{
while (!((USART1->ISR) & USART_ISR_TXE));
char temp1 = USART1->RDR;
SPI2->DR = temp1;
while (!(USART1->ISR & USART_ISR_TC)); // Checking transfer complete bit from UART status register
while (!((SPI2->SR)& SPI_SR_TXE)); //Checking Transmit buffer empty from SPI status register
while (((SPI2->SR)& SPI_SR_BSY)); //Checking SPI busy flag from status register
uint8_t temp2 = SPI2->DR; // To clear Data and status register
temp2 = SPI2->SR;
}
我的SPI2初始化函数是
void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 7;
hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
我的UART初始化函数是
void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_8;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
从根本上来说,我们需要处理两种情况:
我认为你已经理解了这部分内容。
当您进行连续传输而不是单个字节时,问题就会出现。除非传输时序完全相等(这在现实世界中是不可能的),否则一个外设将比另一个外设更快地发送/接收数据。考虑夸张的例子以使其更直观:
设 SPI 为 1Mbit/s。
让 UART 为 9600b/s。
您可以看到,如果您接收到多于一个字节的 SPI 数据并连接到 UART,UART 将无法处理它,它根本无法足够快地移出数据。它正在移出第一个字节,但已经有更多字节通过 SPI 传入。如果您通过慢速 UART 接收,但通过更快的 SPI 发送,您可以看到,当输入一个完整字节的 UART 数据时,SPI 可以轻松地将其移出并休息一下,同时 UART 数据的第二个字节仍在输入. 当速度接近时,仍然会存在不匹配,并且无论是从 UART 到 SPI 还是从 SPI 到 UART,输入都会比输出快。
让我们考虑一下,SPI 比 UART 更快,就像我上面编写的示例一样。如果您的情况相反也没关系,这与概念有关。
当快速 SPI 上的字节传入时,可能有两种情况:
因此,我相信您需要退一步,也许拿起笔和纸,考虑您的应用程序中可能出现的不同场景。您必须选择哪个方向更快,因此不需要任何缓冲区,而另一个方向则必须使用预定长度的 FIFO 缓冲区数组。 MCU 确实几乎立即处理传入的数据(与物理通信速度相比),但将数据移出另一个外设的物理过程需要时间,没有办法绕过它。
考虑到您的 MCU 移动数字的速度非常快(可能比数据物理移出至少快一个数量级),并且您可以简单地以这样的方式实现它,即始终发送传入的 SPI 缓冲区 SPI_RX_BUFFER[0]通过 UART 输出并立即将所有其他元素下移一个元素。您只需要一个 FIFO“满度”计数器即可知道何时停止。例如,将其称为 SPI_RX_BUFFER_LAST_ELEMENT,每次通过 UART 发送内容时,都会将其递减(以便在发送 FIFO 中的最后一个元素时它为 -1)。每次 SPI 数据进入时,SPI_RX_BUFFER_LAST_ELEMENT 都会增加 1,并且新数据存储在该位置。
即使您的 ST-Link 及其 USB-UART 桥接器也具有有限的 FIFO。如果你用 USB 数据淹没它,它就会溢出,并且会发生某种错误事件。例如,基于STM32F103的ST-Link的UART最大速度为4.5Mbps,而其USB接口最高支持12Mbps。
在这里,我花了一点时间画了一些插图,因为用图来谈论这些事情更容易。
底线是,您需要退一步重新考虑您的算法,决定缓冲区的深度并逐步实现它。在一个方向上,你的算法将是“我收到了数据,只需将其放入另一个接口的 TX 中”,因为那里肯定已经完成了先前的数据(尽管“if”语句不会造成伤害)。从另一个方向来说,它必须是“我将数据放入下一个空闲的 FIFO 位置。如果 FIFO 为空,则开始传输”,并且“我已经发送了一个字节并且传输数据寄存器为空,我需要检查 FIFO 是否有任何内容”否则将被发送。如果是,则将其加载到发送寄存器中,并将 FIFO 中的所有数据和指针移至最后一个元素”。