这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【STM32H7S78-DK】TouchGFX之串口DMA不定长接收

共10条 1/1 1 跳转至

【STM32H7S78-DK】TouchGFX之串口DMA不定长接收

助工
2024-10-03 14:35:47     打赏

【前言】

STM32H7S78拥有3个USART4个UART以及一个LPUART共8个串口外设。

image.png

这8个外设均支持DMA收发。

在stm32H7中,相比stm32F1\F4他的串口外设有一些不同,不同点主要在于以下几个方面:

1、拥有USART_TDR以及USART_RDR,两个寄存器,将收发分另存放,不同以前的只有一个USART_DR这一个数据寄存器。

2、支持TX—RX翻转功能,在设计串口GPIO中,可以实时配置翻转IO,实现实时配置。

3、使用GPDMA来设置DMA功能,使得配置稍有复杂。

本篇主要展示使用串口的DMA接收,并实现不定长的数据接收。

【STM32CubeMX配置】

1、配置GPDMA通道,选择Channel 0,然后配置Request Configuration为UART4_RX,使能Destination Data Setting中的Destination Address Increment After Transfer,Channel Configuration for Linked List为Circular,即为循环接收。

image.png

2、打开UART的中断以及DMA中断:

image.png

【用户代码实现】

1、接收数组的创建,创建三个数据用于存放接收缓存,以及三个变量

uint8_t aRXBufferUser[UART_RX_BUFFER_SIZE] __attribute__((section("noncacheable_buffer")));

/**
  * @brief Data buffers used to manage received data in interrupt routine
  */
uint8_t aRXBufferA[UART_RX_BUFFER_SIZE] __attribute__((section("noncacheable_buffer")));
uint8_t aRXBufferB[UART_RX_BUFFER_SIZE] __attribute__((section("noncacheable_buffer")));
__IO uint32_t     uwNbReceivedChars;
uint8_t *pBufferReadyForUser;
uint8_t *pBufferReadyForReception;

2、基中由于GPDMA需要使用__attribute__((section("noncacheable_buffer"))) 来指定内存存放在的位置,在分段配置文件中添加指定的内存位置:

   RW_NONCACHEABLEBUFFER  0x24072000-0x400 0x400  {
   *(.noncacheable_buffer)
  }

3、同时也需要指定DMA Node缓存地址指向指定地址来分配内存。

因为STM32H7的GPDMA是不能直接访问ITCM、DTCM两个内存的,在用户手册表有上说明:

image.png

4、编写中断回调函数:

/**
  * @brief  User implementation of the Reception Event Callback
  *         (Rx event notification called after use of advanced reception service).
  * @param  huart UART handle
  * @param  Size  Number of data available in application reception buffer (indicates a position in
  *               reception buffer until which, data are available)
  * @retval None
  */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  static uint8_t old_pos = 0;
  uint8_t *ptemp;
  uint8_t i;

  /* Check if number of received data in recpetion buffer has changed */
  if (Size != old_pos)
  {
    /* Check if position of index in reception buffer has simply be increased
       of if end of buffer has been reached */
    if (Size > old_pos)
    {
      /* Current position is higher than previous one */
      uwNbReceivedChars = Size - old_pos;
      /* Copy received data in "User" buffer for evacuation */
      for (i = 0; i < uwNbReceivedChars; i++)
      {
        pBufferReadyForUser[i] = aRXBufferUser[old_pos + i];
      }
    }
    else
    {
      /* Current position is lower than previous one : end of buffer has been reached */
      /* First copy data from current position till end of buffer */
      uwNbReceivedChars = UART_RX_BUFFER_SIZE - old_pos;
      /* Copy received data in "User" buffer for evacuation */
      for (i = 0; i < uwNbReceivedChars; i++)
      {
        pBufferReadyForUser[i] = aRXBufferUser[old_pos + i];
      }
      /* Check and continue with beginning of buffer */
      if (Size > 0)
      {
        for (i = 0; i < Size; i++)
        {
          pBufferReadyForUser[uwNbReceivedChars + i] = aRXBufferUser[i];
        }
        uwNbReceivedChars += Size;
      }
    }
    /* Process received data that has been extracted from Rx User buffer */
    UserDataTreatment(huart, pBufferReadyForUser, uwNbReceivedChars);

    /* Swap buffers for next bytes to be processed */
    ptemp = pBufferReadyForUser;
    pBufferReadyForUser = pBufferReadyForReception;
    pBufferReadyForReception = ptemp;
  }
  /* Update old_pos as new reference of position in User Rx buffer that
     indicates position to which data have been processed */
  old_pos = Size;

}

中断回调函数中,接收到数据后,回首根据返回接收到的字符长度来进行数据分装,将接收到的buff放入另一个buff中。同时使用UserDataTreatment(huart, pBufferReadyForUser, uwNbReceivedChars);这个函数将接收到的数据从串口返回。

5、发送函数为:

void UserDataTreatment(UART_HandleTypeDef *huart, uint8_t* pData, uint16_t Size)
{
  /*
   * This function might be called in any of the following interrupt contexts :
   *  - DMA TC and HT events
   *  - UART IDLE line event
   *
   * pData and Size defines the buffer where received data have been copied, in order to be processed.
   * During this processing of already received data, reception is still ongoing.
   *
   */
  uint8_t* pBuff = pData;
  uint8_t  i;

  /* Implementation of loopback is on purpose implemented in direct register access,
     in order to be able to echo received characters as fast as they are received.
     Wait for TC flag to be raised at end of transmit is then removed, only TXE is checked */
  for (i = 0; i < Size; i++)
  {
    while (!(__HAL_UART_GET_FLAG(huart, UART_FLAG_TXE))) {}
    huart->Instance->TDR = *pBuff;
    pBuff++;
  }

}

【实验效果】

使用串口向开发板发送任意长度的数据能够正确的返回。

image.png

image.png

【总结】

此次串口不定长DMA接收,主要用到的是串口中断回调函数的编写,DMA的配置。在实际工程中可以高效的使用串口来进行数据交互。




关键词: STM32H7S78-DK     串口     不定长     DMA    

专家
2024-10-04 08:26:12     打赏
2楼

学习一下


高工
2024-10-04 09:13:10     打赏
3楼

这个好详细啊

学习了,连注意点都有说明 


专家
2024-10-04 09:42:31     打赏
4楼

学习一下


专家
2024-10-04 09:43:08     打赏
5楼

学习一下


专家
2024-10-04 09:44:40     打赏
6楼

学习一下


工程师
2024-10-04 15:36:44     打赏
7楼

666666


专家
2024-10-04 19:20:27     打赏
8楼

学习一下


院士
2024-10-05 09:04:18     打赏
9楼

我倒是一直觉得,像Usart这种功能单一的外设最好使用LL库,类似寄存器操作的实现。


院士
2024-10-06 09:04:29     打赏
10楼

这款芯片确实太强大了,以至于上手挺困难的


共10条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]