853|1

7003

帖子

11

TA的资源

版主

楼主
 

【STM32H7S78-DK】测评+TouchGFX UART+DMA不定长接收 [复制链接]

本帖最后由 lugl4313820 于 2024-10-3 21:48 编辑

【前言】

STM32H7系列的串口+DMA接收,与F1、F4不大相同,此篇使用STM32H7的串口+DMA中断回环接收,接收到数据后,通过TouchGFX显示接收到的数据。此次的重点是如何配置GPDMA以及如何处理接收到的数。

这次试验的基础环境在上篇工程的基础之上添加:

【STM32H7S78-DK】测评+ToucGFX之Lwip移植 - stm32/stm8 - 电子工程世界-论坛 (eeworld.com.cn)

【图形化配置】

1、前面工程是已经开启好了UART4的基础之上添加,打开GPDMA来开启,如下图所示。

  在配置中,主要是开启回环接收模式,Request Configration中选择UART4_RX,然后开启Destination Data Setting下的After Transfer为Enabled,其余的保持默认就行。

2、然后在UART4中开启两个中断,即GPDMA1,以及UART4 global interrrupt。

 

配置好后,更新工程。

【代码编写】

1、接收数组的创建,创建三个数据用于存放接收缓存,以及1个数组用于给TouchGFX进行显示。

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

/**
  * [url=home.php?mod=space&uid=159083]@brief[/url]  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")));
uint8_t show_buff[100];

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

 

所以需要用__attribute__((section("noncacheable_buffer")))来指定存放到指定的内存中,同时在分段加载文件中指定内存段:

  

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

2、编写中断回调函数:

/**
  * @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];
				show_buff[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];
				show_buff[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];
					show_buff[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;
		usart_dma_rcv_state = Size;
		show_buff[Size] = 0;
  }
  /* Update old_pos as new reference of position in User Rx buffer that
     indicates position to which data have been processed */
  old_pos = Size;

}

此段代码中,使用HAL库的扩展HAL_UARTEx_RxEventCallback,来接收数据,并完成处理。在回调函数中返回Size即此次中断接收到的数据长度,使用old_pos与Size来找到此次接收到的数据位置,并把数据转存到其他的几个buff数组,接收完成后,更新一个usart_dama_state,给TouchGFX来处理接收到的数据。

同时在系统初始化好接,执行一次开启DMA的函数:

void StartReception(void)
{
  /* Initializes Buffer swap mechanism (used in User callback) :
     - 2 physical buffers aRXBufferA and aRXBufferB (RX_BUFFER_SIZE length)
  */
  pBufferReadyForReception = aRXBufferA;
  pBufferReadyForUser      = aRXBufferB;
  uwNbReceivedChars        = 0;

  /* Print user info on PC com port */
//  PrintInfo(&huart4, aTextInfoStart, COUNTOF(aTextInfoStart));

  /* Initializes Rx sequence using Reception To Idle event API.
     As DMA channel associated to UART Rx is configured as Circular,
     reception is endless.
     If reception has to be stopped, call to HAL_UART_AbortReceive() could be used.

     Use of HAL_UARTEx_ReceiveToIdle_DMA service, will generate calls to
     user defined HAL_UARTEx_RxEventCallback callback for each occurrence of
     following events :
     - DMA RX Half Transfer event (HT)
     - DMA RX Transfer Complete event (TC)
     - IDLE event on UART Rx line (indicating a pause is UART reception flow)
  */
  if (HAL_OK != HAL_UARTEx_ReceiveToIdle_DMA(&huart4, aRXBufferUser, UART_RX_BUFFER_SIZE))
  {
    Error_Handler();
  }
}

下载后工程后,使用串口组手发送不定长的数据,可以从串口接收到不定长的返回数据:

 

说明不定长是可以正确接收的。

【TouchGFX代码实现】

在ScreenView.cpp中添加HandleTickEvent函数,每10毫秒检查一下次是否接收到串口数据,发果发现有,将数据打印到屏幕上:

void Screen1View::handleTickEvent()
{
	static int tick=0;
	if(tick%10 == 0 && usart_dma_rcv_state > 0)
	{
		Unicode::fromUTF8(show_buff,textFileBuffer,40);
		textFile.invalidate();
		memset((void *)show_buff, 0U, sizeof(show_buff));	
		usart_dma_rcv_state = 0;
	}
	tick = (tick+1)%60;
}

【实现现象】

从串口助手发送到开发板,可以在屏上实时查看到发送的数据:

  

此帖出自stm32/stm8论坛

最新回复

串口空闲中断加DMA是不定长数据接收的最优解     详情 回复 发表于 2024-10-7 11:43
点赞 关注
 

回复
举报

6509

帖子

10

TA的资源

版主

沙发
 

串口空闲中断加DMA是不定长数据接收的最优解  

此帖出自stm32/stm8论坛
 
个人签名

在爱好的道路上不断前进,在生活的迷雾中播撒光引

 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表