打印
[STM32H5]

【NUCLEO- H563ZI 测评】串口空闲中断+DMA接收不定长数据

[复制链接]
1169|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创#  1、串口是设备与设备之间或者MCU和外设之间常用的通信模式,一个好用的串口接收程序对 协议解析,数据接收都非常方便。
很多人都应该用过串口空闲中断+DMA这个模式用于接收不定长的数据这,STM32H5的库函数对这个方式进行封装,直接调用库函数就可以使用空闲中断DMA接收数据了。
为了方便测试,下面的还是使用USART3进行演示,USART3可以和stlink的VCP进行通信。
2、首先是对串口的DMA进行初始化,设置GPDMA1_REQUEST_USART3_RX接收,初始化dma的通道,设置dma 工作在CircularMode模式。最后将DMA和USART3相关联。
/* USART3 DMA Init */
     /* GPDMA1_REQUEST_USART3_RX Init */
     NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
     NodeConfig.Init.Request = GPDMA1_REQUEST_USART3_RX;
     NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
     NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
     NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
     NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
     NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
     NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
     NodeConfig.Init.SrcBurstLength = 1;
     NodeConfig.Init.DestBurstLength = 1;
     NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
     NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
     NodeConfig.Init.Mode = DMA_NORMAL;
     NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
     NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
     NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
     if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0) != HAL_OK)
     {
       Error_Handler();
     }

     if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0) != HAL_OK)
     {
       Error_Handler();
     }

     if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0) != HAL_OK)
     {
       Error_Handler();
     }

     handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
     handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
     handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
     handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
     handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
     handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
     if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0) != HAL_OK)
     {
       Error_Handler();
     }

     if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0) != HAL_OK)
     {
       Error_Handler();
     }

     __HAL_LINKDMA(huart, hdmarx, handle_GPDMA1_Channel0);

     if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
     {
       Error_Handler();
     }
ST的库里面封装了下面这个函数用于启动dma接收  HAL_UARTEx_ReceiveToIdle_DMA(&huart3, aRXBufferUser, RX_BUFFER_SIZE))。这里面的数组是接收数据存储的地方,长度是一次最大的接收长度。在这个函数里面可以看到这个函数使能了串口空闲中断,并设置DMA接收的参数。这个函数非常方便,不需要我们去额外配置空闲中断,直接调用即可。
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  HAL_StatusTypeDef status;

  /* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    /* Set Reception type to reception till IDLE Event*/
    huart->ReceptionType = HAL_UART_RECEPTION_TOIDLE;
    huart->RxEventType = HAL_UART_RXEVENT_TC;

    status =  UART_Start_Receive_DMA(huart, pData, Size);

    /* Check Rx process has been successfully started */
    if (status == HAL_OK)
    {
      if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
      {
        __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLEF);
        ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
      }
      else
      {
     
        status = HAL_ERROR;
      }
    }

    return status;
  }


为了验证功能,将接收的数据再次发送到stlink vcp 上
void UserDataTreatment(UART_HandleTypeDef *huart, uint8_t* pData, uint16_t Size)
{
  
  uint8_t* pBuff = pData;
  uint8_t  i;

    for (i = 0; i < Size; i++)
  {
    while (!(__HAL_UART_GET_FLAG(huart, UART_FLAG_TXE))) {}
    huart->Instance->TDR = *pBuff;
    pBuff++;
  }

}
还有就是USART3的中断函数了,里面直接对空闲中断做了判断,如果使能了DMA就调用对应的回调函数,读取接收到的数据。
3、测试结果:


测试代码如下,需要注意要把代码解压到STM32Cube_FW_H5_V1.1.0\Projects\NUCLEO-H563ZI\Examples\UART路径下面
UART_ReceptionToIdle_CircularDMA.rar (637.55 KB)


使用特权

评论回复
沙发
uiint| | 2023-9-5 10:07 | 只看该作者
如何通过DMA实现不定长USART接收

使用特权

评论回复
板凳
maqianqu| | 2023-9-5 10:45 | 只看该作者
串口空闲中断是指在串口通信过程中,当检测到线路处于空闲状态时,由硬件自动产生一个中断信号,通知CPU可以进行数据发送或接收操作。这种中断信号可以帮助CPU更好地控制串口通信的流程。

使用特权

评论回复
地板
mickit| | 2023-9-5 11:06 | 只看该作者
串口空闲中断+DMA接收不定长数据的开发需要使用HAL库提供的DMA驱动程序和API,同时需要注意串口空闲中断的配置和DMA接收的配置。

使用特权

评论回复
5
51xlf| | 2023-9-5 13:37 | 只看该作者
串口空闲中断+DMA接收不定长数据是一种常用的数据接收方式,可以在不影响主程序的情况下实现数据的接收和处理。

使用特权

评论回复
6
pl202| | 2023-9-5 18:13 | 只看该作者
串口接收不固定数据长度包,可以怎么处

使用特权

评论回复
7
mnynt121| | 2023-9-5 18:42 | 只看该作者
stm32 串口发送数组 cpu可以工作吗

使用特权

评论回复
8
Bowclad| | 2023-9-5 21:38 | 只看该作者
uiint 发表于 2023-9-5 10:07
如何通过DMA实现不定长USART接收

用空闲中断

使用特权

评论回复
9
maudlu| | 2023-9-5 22:09 | 只看该作者
通常采用DMA做USART接收固定长度的数据,或通过DMA完成固定数量的不间断数据流。

使用特权

评论回复
10
zwll| | 2023-9-5 22:10 | 只看该作者
硬件自动产生一个中断信号

使用特权

评论回复
11
modesty3jonah| | 2023-9-7 12:14 | 只看该作者
如何做到让串口接受不同长度的数据

使用特权

评论回复
12
everyrobin| | 2023-9-7 13:01 | 只看该作者
如何实现从串口接收一串不定长度的数据

使用特权

评论回复
13
yorkbarney| | 2023-9-7 16:06 | 只看该作者
需要在DMA接收完成后通过中断或其他方式通知CPU进行处理。这种方式可以避免CPU在接收数据时被频繁打断,提高系统的效率。

使用特权

评论回复
14
Undshing| | 2023-9-7 22:26 | 只看该作者
everyrobin 发表于 2023-9-7 13:01
如何实现从串口接收一串不定长度的数据

利用空闲中断就可以

使用特权

评论回复
15
c1486361959| | 2023-9-16 14:54 | 只看该作者
串口空闲中断

使用特权

评论回复
16
Jacquetry| | 2023-9-16 21:59 | 只看该作者
pl202 发表于 2023-9-5 18:13
串口接收不固定数据长度包,可以怎么处

可以用空闲中断

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

44

帖子

3

粉丝