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

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路径下面。
---------------------
作者:OldestTrick
链接:https://bbs.21ic.com/icview-3323048-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。
 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值