基于STM32H7 UART空闲事件及DMA传输示例

发布者:Harmonious222最新更新时间:2024-05-08 来源: elecfans关键字:STM32H7  UART  DMA传输 手机看文章 扫描二维码
随时随地手机看文章

有人使用STM32H7芯片的UART,想利用DMA实现不定长的数据接收,实现过程似乎不太顺利。另外,刚好最近有人使用H7芯片做UART收发,当开启D-Cache未做MPU配置,使用指令对D-Cache做相应失效处理,发现通信结果异常。我这里简单演示下实现过程,分使用和不使用D-Cache两种做法,以供参考。


这里使用UART4做发送,UART5做接收,都使用DMA,均工作在Normal模式。

2597a196-9cb0-11ee-8b88-92fbcf53809c.png

25ab52ae-9cb0-11ee-8b88-92fbcf53809c.png

在主循环里每隔一定时间让UART4发送一串数据出去,一共3串依次发送。每次发送的数据长度不一样,但不会超过20个字符。

25bfea8e-9cb0-11ee-8b88-92fbcf53809c.png

让UART5基于DMA做不定长的数据接收,将接收长度定义在20。同时开启UART5的空闲中断。在UART5的空闲中断里再次开启下一轮的DMA接收准备。

25cc33a2-9cb0-11ee-8b88-92fbcf53809c.png

关键API函数,UART4的发送函数和UART5用到的接收函数如下所示:

25d71326-9cb0-11ee-8b88-92fbcf53809c.png

顺便提下,在H7系列的HAL库里定义了好几个UART接收类型,使用时适当注意下。这里用的是下图划红线的关注IDLE事件的接收类型。

25e62014-9cb0-11ee-8b88-92fbcf53809c.png

我在IDLE事件的中断回调函数里就做了一件事,为下次UART5的DMA接收做准备。至于接收到的数据的后续处理就没做进一步操作了。

25fc4dee-9cb0-11ee-8b88-92fbcf53809c.png

这里是对不定长数据进行接收,使用IDLE事件的中断比使用DMA接收完成中断更方便些。


不开启D-Cache时的主要测试代码如下:


#define BUFFER_SIZE    20

ALIGN_32BYTES(uint8_t RxData[BUFFER_SIZE];)



ALIGN_32BYTES(char TxData1[]='a5a5lfjaf888';)



ALIGN_32BYTES(char TxData2[]='1234$%^&555';)



ALIGN_32BYTES(char TxData3[]='aa8$%^&*33333';)



uint8_t Tempcnt;



int main(void)

{

/* USER CODE BEGIN 1 */



/* USER CODE END 1 */



/* Enable I-Cache---------------------------------------------------------*/

   SCB_EnableICache();



/* 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_UART4_Init();

  MX_UART5_Init();

/* USER CODE BEGIN 2 */



  HAL_Delay(5);



  __HAL_UART_CLEAR_FLAG(&huart5, UART_CLEAR_IDLEF);

         

 HAL_UARTEx_ReceiveToIdle_DMA(&huart5, RxData,  BUFFER_SIZE);



/* USER CODE END 2 */



/* Infinite loop */

/* USER CODE BEGIN WHILE */

while (1)

  {

/* USER CODE END WHILE */



    /* USER CODE BEGIN 3 */



    HAL_Delay (500);  //延时长点方便观察调试窗口的数据变化

    

for (uint8_t i=0;i


现在看看验证结果。下面是3次不同接收结果截图,3次发送的数据个数分别是12个、11个和13个。


b1e0a359f18d61ed5e77a0cc8ae2b2ea_wKgaomV-wh6AVNLLAAP3_voShPM846.png

83dca365da039077334677779b82c50b_wKgaomV-wh6AWSgZAAPcyAWuXzU570.png

5c4ab88ff091ebc805c848c451241d78_wKgaomV-wh6APxkwAAPqOAxphlY036.png

上面是没有启用D-Cache的代码,若启用D-Cache而又不想配置MPU,就得在适当地方添加对Cache的失效操作或清除操作。调整后的代码如下:



int main(void)

{

/* USER CODE BEGIN 1 */



/* USER CODE END 1 */



/* Enable I-Cache---------------------------------------------------------*/

  SCB_EnableICache();



/* Enable D-Cache---------------------------------------------------------*/

  SCB_EnableDCache();  //*****



/* 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_UART4_Init();

  MX_UART5_Init();

/* USER CODE BEGIN 2 */



  HAL_Delay(5);    



   __HAL_UART_CLEAR_FLAG(&huart5, UART_CLEAR_IDLEF);

       

  HAL_UARTEx_ReceiveToIdle_DMA(&huart5, RxData,  BUFFER_SIZE);



        /* USER CODE END 2 */



/* Infinite loop */

/* USER CODE BEGIN WHILE */

while (1)

  {

/* USER CODE END WHILE */



/* USER CODE BEGIN 3 */


SCB_InvalidateDCache_by_Addr(RxData,BUFFER_SIZE);//***


HAL_Delay (500);  //延时长点方便观察调试窗口的数据变化


for (uint8_t i=0;i


上面代码中除了新增使能D-Cache那句代码外,还添加了2处标有三颗*的代码。分别是SCB_InvalidateDCache_by_Addr()和SCB_CleanDCache_by_Addr(),前一句将基于RxData而开辟的D-Cache行失效,让CPU去内存读取数据。因为此时内存数据可能已经被DMA改写而更新了。后一句就是将前面CPU循环操作对RxData数组清零后的数据写回到内存,并清空相应Cache行。其它代码跟前面不使用D-Cache一样,包括空闲中断回调函数的处理。上面测试代码可供参考验证。


关键字:STM32H7  UART  DMA传输 引用地址:基于STM32H7 UART空闲事件及DMA传输示例

上一篇:浅谈C语言内存分区和STM32存储器分配
下一篇:STM32WB55开发(5)----调整射频功率

推荐阅读最新更新时间:2024-11-12 10:28

STM32CubeIDE 中 HAL库的串口中断接收函数 HAL_UART_Receive_IT
一、代码自动生成以后的项目及代码结构: main.c中,调用了串口初始化 串口初始化函数赋值了串口的参数 相当于底层的初始化,配置引脚、并开启中断。 至此串口1配置完毕 二、库文件stm32f1xx_hal_uart.c内的秘密 2.1 初始化 1.usart.c中,MX_USART1_UART_Init 调用了库的HAL_UART_Init,将结构体传递进该函数中 2.HAL_UART_Init干了些什么事? if (huart- gState == HAL_UART_STATE_RESET) { huart- Lock = HAL_UNLOCKED; HAL_UART_MspInit(huar
[单片机]
STM32CubeIDE 中 HAL库的串口中断接收函数 HAL_<font color='red'>UART</font>_Receive_IT
STM32 ADC多通道DMA传输
ADC多通道采集是在ADC单通道DMA传输的基础上写的,代码如下: volatile u16 adcconverdata ={0,0}; static void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;//添加PA2的GPIO初始化代码 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; GPIO_Init(
[单片机]
UART0串口编程(一):通信协议设计;RS232标准
嵌入式系统之间采用通信方式交换数据,串行通信是一种最基本的通信手段。现在由于各类CPU均集成了UART部件。本节对串口编程时如何设计串口通信协议,以及对RS232接口进行了说明。 1. 通信协议设计 在进行通信时,每次需要传送的信息一般超过1字节。为此,通信双方必须约定通信数据的排列格式,即通信协议。通常把一次通信过程的全部内容称为一个“通信帧”。通信协议设计就是帧结构设计。在一帧内容中,通常包括以下部分。 (1)起始码:由一个或若干个包含特定内容的字节,表示一个通信帧的开始。起始码的内容必须与通信数据内容有明显区别(不能在通信数据里出现与起始码相同的内容)。当通信帧的总长度比较短,信道质量比较高时,为了提高效率,可
[单片机]
<font color='red'>UART</font>0串口编程(一):通信协议设计;RS232标准
cube mx uart dma
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * h2 center Copyright (c) 2020 STMicroelec
[单片机]
cube mx <font color='red'>uart</font> <font color='red'>dma</font>
ARM裸机篇-串口UART实验
串口应该都很熟悉了,具体通信原理我就不提了,这个百度上都很多讲的,然后就直接看函数了。 void Uart_SendByte(int data)//这个函数是发送整型数据,参数为data { if(whichUart==0)//这个是选中串口0 { if(data=='')//然后判断数据不为空 {       /*寄存器的原始宏定义,       #define rUTRSTAT0 (*(volatile unsigned *)0x50000010) //UART 0 Tx/Rx status*/ while(!(rUTRSTAT0 & 0x2));/*这个就是查询串口0的
[单片机]
ARM裸机篇-串口<font color='red'>UART</font>实验
AVR USART(UART)发送中断程序 使用缓冲器
系统功能    使用AVR的USART进行自发自收(将发送引脚RXD短接到接收引脚TXD),发出数据:0,1,2。。。数据,能接收到自己发出的数据:0,1,2。。。使用LED作出简单指示! 硬件设计 AVR主控电路原理图(点击图片放大,不需要放大镜! ) LED控制电路原理图(点击图片放大,不需要放大镜! ) 软件设计 下面部分从TXT拷出,拷到网页,代码部分缺省了很多空格,比较凌乱,请谅解! //目标系统: 基于AVR单片机 //应用软
[单片机]
AVR USART(<font color='red'>UART</font>)发送中断程序 使用缓冲器
SAM4E单片机之旅——11、UART之PDC收发
使用PDC进行数据的收发能减少CPU的开销。这次就使用PDC进行UART数据的接收与发送,同时,也利用TC也实现了PDC的接收超时。 PDC是针对外设的DMA控制器。对比DMA控制器,它更为简便,与相应外设的结合也更为紧密。比如说,要配置PDC时,首先要启用相应的外设的时钟;同时PDC收发的状态是通过外设上的寄存器反映出来的;甚至中断也是通过相应外设产生的。 使用PDC时,只需设置好传输时内存的地址,以及传输长度,就可以在外设和内存之前进行数据传输了。而SAM4的PDC甚至还提供了一个类似FIFO的功能:可以在进行本次传输的同时指定下次传输时的地址和长度,然后在本次传输结束时开始下一次传输。 一、 实现思路 本次会使用两组
[单片机]
深入理解ARM体系架构(S3C6410)---UART实例
1、 概括OVERVIEW S3C6410提供了4个独立的异步串行口,每个独立的串行口可以工作在中断模式或DMA模式下。也就是说UART能够产生一个中断或DMA请求。UART可以提供最高3Mbps。每个UART包含2个64位的FIFO,分别用于接收,发送缓冲。 S3C6410 UART 包括可编程的波特率,红外发射接收,1或2个停止校验位,5,6,7,8数据位,和奇偶检验。每个UART包含一个波特率发生器,接收发送和控制单元。 波特率可以由PCLK,EXT_UCLK0或EX_UCLK1锁定。发送接收器分别包含了一个64位FIFO和一个数据移位器。通过向FIFO写入数据,再把FIFO中的数据拷贝到数据移位器中,从而通过TxD
[单片机]
深入理解ARM体系架构(S3C6410)---<font color='red'>UART</font>实例
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved