HAL_UART_Receive_DMA 只能工作一次。我该如何解决它?

问题描述 投票:0回答:3

我正在使用 STM32F103RB 板,我想简单地将通过串行端口从计算机接收到的所有内容回显到该端口。我必须使用 UART 和 DMA 来完成此操作。我已在正常模式下使用 CubeMX 在 USART2_RX 上设置 DMA。我的问题是

HAL_UART_RxCpltCallback
只被调用一次。有趣的是,我在 PC 端得到了响应,但带有额外的
0xFC
字节。之后,控制器停止对通过串行端口发送的新数据做出反应,并且直到我用 USB 拔出并重新插入控制器时才会这样做。这是回调和主函数的代码:

#define BUF_SIZE 16

uint8_t RX_BUF[BUF_SIZE] = {0};
uint8_t TX_BUF[BUF_SIZE] = {0};

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_UART_Transmit(&huart2, RX_BUF, BUF_SIZE, 1000);
  HAL_UART_Receive_DMA(&huart2, RX_BUF, BUF_SIZE);
}

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_DMA(&huart2, RX_BUF, sizeof (RX_BUF));
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

编辑:我正在尝试通过 USB-C 适配器在 Mac 上执行此操作。这会是问题吗?

stm32 uart dma stm32f1 stm32cubemx
3个回答
1
投票

在 ISR 中调用复杂函数是一个坏主意。许多 HAL 函数使用系统滴答来测量超时,并且根据您的中断优先级,滴答可能会在 ISR 运行时被阻止。

最好将任何复杂的处理从 ISR 中移出到主函数中。只需在 ISR 中设置一个标志来指示接收何时完成。比如:

static volatile bool uart_rx_done = false;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    uart_rx_done = true;
}

int main()
{
    // Initialisation stuff

    for (;;)
    {
        uart_rx_done = false;
        HAL_UART_Receive_DMA(&huart2, RX_BUF, BUF_SIZE);
        while (!uart_rx_done)
            ;

        HAL_UART_Transmit(&huart2, RX_BUF, BUF_SIZE, 1000);
    }
}

1
投票

首先,检查您是否正确配置了

uart
dma
中断。 在
stm21f1xx_it.c
文件中你应该看到这些函数

void DMA1_Channel6_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */

  /* USER CODE END DMA1_Channel6_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_usart2_rx);
  /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */

  /* USER CODE END DMA1_Channel6_IRQn 1 */
}


void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

以及

uart2
文件中
MX_NVIC_Init()
函数中的
main.c
配置。

但您的主要错误是您根本没有激活

uart
接收中断。我建议暂时不要使用
dma
,尝试一下看看
uart
中断是否被激活:

#define BUF_SIZE 16
bool uart_received = false;

uint8_t RX_BUF[BUF_SIZE] = {0};
uint8_t TX_BUF[BUF_SIZE] = {0};

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  // HAL_UART_Transmit(&huart2, RX_BUF, BUF_SIZE, 1000);
  uart_received = true;
  HAL_UART_Receive_IT(&huart2, RX_BUF, BUF_SIZE);
}

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  //HAL_UART_Receive_DMA(&huart2, RX_BUF, sizeof (RX_BUF));
  HAL_UART_Receive_IT(&huart2, RX_BUF, BUF_SIZE);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      if (uart_received) {
          HAL_UART_Transmit(&huart2, RX_BUF, BUF_SIZE, 1000);
          uart_received = false;
      }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

如果有效,那么您可以使用

HAL_UARTEx_ReceiveToIdle_DMA
来激活
uart-dma
中断,使用
HAL_UARTEx_RxEventCallback
来激活回调函数(假设已配置
dam
中断)。


0
投票

我以一种罕见的方式解决了这个问题: 我正在开发的板子是使用 NUCLEO-L152RE 的 IOC;我在外设端的 DMA RX 配置中将数据宽度从字节更改为字: 数据宽度

© www.soinside.com 2019 - 2024. All rights reserved.