单片机
返回首页

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

2024-05-08 来源:elecfans

有人使用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一样,包括空闲中断回调函数的处理。上面测试代码可供参考验证。


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 家用电源无载自动断电装置的设计与制作

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • RS-485基础知识:处理空闲总线条件的两种常见方法

  • 如何调制IC555振荡器

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章