STM32 UART到SPI可变长度数据传输
嗨,我正在尝试在STM32 IoT开发套件中与我的ES-WIFI模块进行通信。默认情况下,WiFi模块是通过SPI2连接的(要使用UART我必须使用SPI刷新模块的固件)。我想从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 init函数是
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 init函数是
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 */
}
Hi I'm trying to communicate with my ES-WIFI module in STM32 IoT development kit. The wifi module by default is connected through SPI2 (to use UART I have to flash the module's firmware using SPI). I want to transmit AT commands from UART serial monitor to the wifi module and receive the response back to the PC's serial monitor. So, I want to receive the message from USART1 (pc-uart) and transmit the data to the SPI2. Likewise, the response should be read from SPI2 and transmitted to USART1. Also the key point is, data transmission should be of variable leangth.
When I run the program, the debugger stops at SPI status register TXE not empty. And the FIFO transmission level is full (FTLVM: 11). Can anyone please tell me what am I doing wrong.
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;
}
My SPI2 init function is
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 */
}
My UART init function is
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 */
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从根本上讲,我们需要处理两种情况:
我认为您可以得到那部分。
当您进行连续传输而不是单个字节时,问题开始。除非传输时机完全相等(在现实世界中,这是不可能的),一个外围时间将比另一个外围传输更快地发送/接收数据。考虑夸张的例子以使其更直观:
让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 Buffer SPI_RX_BUFFER [0]在UART上,立即将所有其他元素转移到一个元素上。您只需要一个“饱满”计数器即可知道何时停止。例如,将其称为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是否有任何内容否则要发送。
Fundamentally, we need to handle two scenarios:
I think you're getting that part OK.
The problems start when you have continuous transmission and not individual bytes. Unless transmission timings are perfectly equal (which in real world is impossible), one peripheral will send/receive data faster than another peripheral. Consider exaggerated example to make it more intuitive:
Let SPI be 1Mbit/s.
Let UART be 9600b/s.
You can see how if you receive more than one byte of SPI data to be wired to UART, UART won't be able to handle it, it simply doesn't shift data out quickly enough. It's shifting out the first byte, but there are already many more coming in over SPI. If you receive via slow UART, but send out via faster SPI, you can see that when a full byte of UART data comes in, SPI can easily shift it out and take a coffee break while the second byte of UART data is still coming in. When speeds are closer, there will still be a mismatch, and input will be faster than output either from UART to SPI or from SPI to UART.
Let's consider for a moment, that SPI is faster than UART like in the example I made up above. Doesn't matter if it's the other way around in your case, it's about concepts.
When a byte over quick SPI comes in, there are two scenarios possible:
Therefore, I believe you need to step back a little, maybe take pen and paper and consider different scenarios that can occur in your application. You will have to choose which direction will be faster and therefore won't need any buffer, and the other one will have to use a FIFO buffer array of predetermined length. The MCU does process the incoming data almost immediately (comparing to physical communication speed), but the physical process of shifting the data out over another peripheral takes time, there is no way around it.
Given your MCU is very quick with moving numbers around (probably at least an order of magnitude quicker than data being physically shifted out), and you can simply implement it in such a way, that you always send incoming SPI buffer SPI_RX_BUFFER[0] out over UART and immediately shift all other elements one element down. You only need a FIFO "fullness" counter to know when to stop. For example, call it SPI_RX_BUFFER_LAST_ELEMENT, and every time you send something via UART, you decrement it (so that it's -1 when you send out the last element in FIFO). Every time SPI data comes in, SPI_RX_BUFFER_LAST_ELEMENT just gets incremented by 1 and the new data is stored at that position.
Even your ST-Link with its USB-UART bridge has this limited FIFO. If you flood it with USB data, you will overflow it, and some kind of error event will happen. For example, STM32F103-based ST-Link has max UART speed of 4.5Mbps, while its USB interface supports up to 12Mbps.
Here, I took a little time to draw a little illustration, because talking about these things is easier with a picture.
Bottom line is, you need to take a step back and reconsider your algorithm, decide how deep your buffer has to be and implement it step by step. In one direction, your algorithm will be "I received data, just put it in TX of another interface", because there it's definitely already done with the previous data (although an "if" statement won't hurt). In another direction, it has to be "I put data into next free FIFO spot. If FIFO was empty, start transmission", and "I have sent out a byte and transmit data register is empty, I need to check if FIFO has anything else to be sent. If it does, load it into transmit register and shift all the data in the FIFO and pointer to the last element".