繁体   English   中英

STM32 UART转SPI变长数据传输

[英]STM32 UART to SPI variable length data transmission

嗨,我正在尝试与我在 STM32 IoT 开发套件中的 ES-WIFI 模块进行通信。 wifi 模块默认通过 SPI2 连接(要使用 UART,我必须使用 SPI 刷新模块固件)。 我想将 AT 命令从 UART 串​​行监视器传输到 wifi 模块,并将响应接收回 PC 的串行监视器。 所以,我想从 USART1(pc-uart)接收消息并将数据传输到 SPI2。 同样,应从 SPI2 读取响应并将其发送到 USART1。 另外关键是,数据传输应该是可变长度的。

当我运行 thr 程序时,调试器停止在 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 */

}

从根本上说,我们需要处理两种情况:

  1. 传入 UART 的数据。 通过 SPI 发送。
  2. 输入数据到 SPI。 通过UART发送。

我认为你的那部分没问题。

当您进行连续传输而不是单个字节时,问题就开始了。 除非传输时间完全相等(这在现实世界中是不可能的),否则一个外设将比另一个外设更快地发送/接收数据。 考虑夸张的例子,使其更直观:

设 SPI 为 1Mbit/s。
让 UART 为 9600b/s。

您可以看到,如果您接收到要连接到 UART 的多于一个字节的 SPI 数据,UART 将无法处理它,它只是无法足够快地将数据移出。 它正在移出第一个字节,但已经有更多的字节通过 SPI 进入。 如果您通过慢速 UART 接收,但通过更快的 SPI 发送,您可以看到当一个完整字节的 UART 数据进入时,SPI 可以轻松地将其移出并在 UART 数据的第二个字节仍在进入时休息一下. 当速度更接近时,仍然会出现不匹配,并且从 UART 到 SPI 或从 SPI 到 UART 的输入会比输出快。


让我们考虑一下,在我上面的例子中,SPI 比 UART 快。 如果您的情况相反,没关系,这与概念有关。

当通过快速 SPI 输入一个字节时,可能有两种情况:

  1. UART 空闲。 开始传输。 很容易。
  2. UART 已经在转移一些东西了。 现在我们有一个问题。 我相信这就是您要解决的问题,并且您的代码挂在哪里,您对这种情况的处理不当。

因此,我认为您需要退后一步,也许拿起笔和纸,考虑一下您的应用程序中可能出现的不同场景。 您必须选择哪个方向更快,因此不需要任何缓冲区,而另一个必须使用预定长度的 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,并且新数据存储在该位置。

即使是带有 USB-UART 桥接器的 ST-Link 也有这个有限的 FIFO。 如果你用 USB 数据淹没它,你会溢出它,并且会发生某种错误事件。 例如,基于 STM32F103 的 ST-Link 的最大 UART 速度为 4.5Mbps,而其 USB 接口最高支持 12Mbps。

在这里,我花了一点时间画了一个小插图,因为用一张图片来谈论这些事情更容易。

在此处输入图像描述


底线是,您需要退后一步,重新考虑您的算法,确定缓冲区的深度并逐步实施。 在一个方向上,您的算法将是“我收到数据,只需将其放在另一个接口的 TX 中”,因为它肯定已经用以前的数据完成了(尽管“if”语句不会受到伤害)。 换个方向,必须是“我把数据放到下一个空闲的FIFO点。如果FIFO是空的,开始传输”,“我已经发出了一个字节,传输数据寄存器是空的,我需要检查FIFO是否有任何东西否则要发送。如果是,则将其加载到发送寄存器中,并将 FIFO 中的所有数据和指针移到最后一个元素“。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM