0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

串口DMA其实一点儿都不难

朱老师物联网大讲堂 ? 2024-04-29 08:10 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

DMA一种在嵌入式实时任务处理中常用的功能。而UART发送数据包,使用DMA方式能大量减轻CPU处理的时间,使其CPU资源不被大量浪费,尤其在UART收发大量数据包(如高频率收发指令)时具有明显优势。

一、简述DMA

ecb153ba-05bc-11ef-9118-92fbcf53809c.pngDMA:Direct Memory Access,直接内存存取/访问。简单来说就是内存RAM直接和其他设备(外设)进行数据交互,而不需要CPU参与的一种控制器。DMA它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的数据复制到缓存器,然后把它们再次写回到新的地方。在这个过程中,CPU不能做其他的工作。

二、DMA的优点

ecb153ba-05bc-11ef-9118-92fbcf53809c.pngDMA在系统中的角色好比一个公司的员工,CPU好比是公司的老板。回到UART发送数据,同样的道理,CPU只需要简单的操作(“安排任务”),就可把一串数据包丢给DMA直接发送,最后发送完成,收到一个发送完成中断,通知CPU发送完成即可。说到这里相信大部分人都明白了,老板可以亲自开车或者坐飞机送快递,完成这件事情,但会耽搁老板很多时间。同样,如果我们使用UART自己发送,CPU就会不停仲裁发送结果,占据CPU大量资源。在RTOS中,特别是有大量任务需要处理的时候,UART使用DMA发送就会带来很大方便。使用裸机运行的相同,尤为突出。

三、实例代码:DMA发送配置

ecb153ba-05bc-11ef-9118-92fbcf53809c.png本文使用STM32F4 MCU、标准外设库为例给大家简单讲述一下配置。

01

USART配置

USART(COM)宏定义:

/* COMM通信 */#define COMM_COM USART2#define COMM_COM_CLK RCC_APB1Periph_USART2#define COMM_COM_TX_GPIO_CLK RCC_AHB1Periph_GPIOD //UART TX#define COMM_COM_TX_PIN GPIO_Pin_5#define COMM_COM_TX_GPIO_PORT GPIOD#define COMM_COM_TX_SOURCE GPIO_PinSource5#define COMM_COM_TX_AF GPIO_AF_USART2#define COMM_COM_RX_GPIO_CLK RCC_AHB1Periph_GPIOD //UART RX#define COMM_COM_RX_PIN GPIO_Pin_6#define COMM_COM_RX_GPIO_PORT GPIOD#define COMM_COM_RX_SOURCE GPIO_PinSource6#define COMM_COM_RX_AF GPIO_AF_USART2#define COMM_COM_IRQn USART2_IRQn#define COMM_COM_Priority 9 //优先级#define COMM_COM_BaudRate 115200 //波特率#define COMM_COM_IRQHandler USART2_IRQHandler //中断函数接口(见stm32f4xx_it.c)

USART配置:

/************************************************函数名称 :USART_COMM_Configuration功 能 :通信串口配置参 数 :无返 回 值 :无作 者 :strongerHuang*************************************************/void USART_COMM_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
/* 时钟配置 */ RCC_AHB1PeriphClockCmd(COMM_COM_TX_GPIO_CLK | COMM_COM_RX_GPIO_CLK, ENABLE); if((USART1 == COMM_COM) || (USART6 == COMM_COM)) RCC_APB2PeriphClockCmd(COMM_COM_CLK, ENABLE); else RCC_APB1PeriphClockCmd(COMM_COM_CLK, ENABLE);
/* 复用配置 */ GPIO_PinAFConfig(COMM_COM_TX_GPIO_PORT, COMM_COM_TX_SOURCE, COMM_COM_TX_AF); GPIO_PinAFConfig(COMM_COM_RX_GPIO_PORT, COMM_COM_RX_SOURCE, COMM_COM_RX_AF);
/* 引脚配置 */ GPIO_InitStructure.GPIO_Pin = COMM_COM_TX_PIN; //USART Tx GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(COMM_COM_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = COMM_COM_RX_PIN; //USART Rx GPIO_Init(COMM_COM_RX_GPIO_PORT, &GPIO_InitStructure);
/* NVIC配置 */ NVIC_InitStructure.NVIC_IRQChannel = COMM_COM_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = COMM_COM_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
/* USART配置 */ USART_InitStructure.USART_BaudRate = COMM_COM_BaudRate; //波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //传输位数 USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位 USART_InitStructure.USART_Parity = USART_Parity_No ; //校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发功能 USART_Init(COMM_COM, &USART_InitStructure);
USART_ClearFlag(COMM_COM, USART_FLAG_RXNE | USART_FLAG_TC); USART_ITConfig(COMM_COM, USART_IT_RXNE, ENABLE); //接收中断
USART_DMACmd(COMM_COM, USART_DMAReq_Tx, ENABLE); //使能DMA
USART_Cmd(COMM_COM, ENABLE); //使能USART}


02

DMA配置

DMA宏定义:

/* COMM_DMA */#define COMM_DR_ADDRESS ((uint32_t)USART2 + 0x04)#define COMM_DMA DMA1#define COMM_DMA_CLK RCC_AHB1Periph_DMA1#define COMM_TX_DMA_CHANNEL DMA_Channel_4#define COMM_TX_DMA_STREAM DMA1_Stream6#define COMM_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF6#define COMM_TX_DMA_IRQn DMA1_Stream6_IRQn#define COMM_TX_DMA_Priority 8 //优先级#define COMM_TX_DMA_IRQHandler DMA1_Stream6_IRQHandler //中断函数接口(见stm32f4xx_it.c)#define COMM_TX_DMA_IT_TCIF DMA_IT_TCIF6

DMA配置:

/************************************************函数名称 :USART_COMM_DMA_Configuration功 能 :通信串口的DMA配置参 数 :无返 回 值 :无作 者 :strongerHuang*************************************************/void USART_COMM_DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
/* 使能时钟 */ RCC_AHB1PeriphClockCmd(COMM_DMA_CLK, ENABLE);
/* NVIC配置 */ NVIC_InitStructure.NVIC_IRQChannel = COMM_TX_DMA_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = COMM_TX_DMA_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
/* DMA配置 */ DMA_DeInit(COMM_TX_DMA_STREAM); DMA_InitStructure.DMA_Channel = COMM_TX_DMA_CHANNEL; //DMA通道 DMA_InitStructure.DMA_PeripheralBaseAddr = COMM_DR_ADDRESS; //外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0; //内存地址(待传入参数) DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //传输方向 DMA_InitStructure.DMA_BufferSize = 0; //传输长度(待传入参数) DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设递增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(COMM_TX_DMA_STREAM, &DMA_InitStructure);
DMA_ClearFlag(COMM_TX_DMA_STREAM, COMM_TX_DMA_FLAG_TCIF); DMA_ITConfig(COMM_TX_DMA_STREAM, DMA_IT_TC, ENABLE); //使能DMA传输完成中断
DMA_Cmd(COMM_TX_DMA_STREAM, DISABLE); //初始化禁止}

03

DMA发送UART数据包

DMA发送函数:

/************************************************函数名称 :COMM_SendBufByDMA功 能 :通信串口通过DMA发送数据参 数 :Buf ------ 数据(地址) Length --- 数据长度(字节)返 回 值 :无作 者 :strongerHuang*************************************************/void COMM_SendBufByDMA(uint8_t *Buf, uint16_t Length){ DMA_Cmd(COMM_TX_DMA_STREAM, DISABLE); //关闭DMA //内存地址 DMA_MemoryTargetConfig(COMM_TX_DMA_STREAM, (uint32_t)Buf, DMA_Memory_0); DMA_SetCurrDataCounter(COMM_TX_DMA_STREAM, Length); //设置DMA传输长度 DMA_Cmd(COMM_TX_DMA_STREAM, ENABLE); //使能DMA}

细心的朋友会发现,这个发送函数其实很简单,当然,这里是使用STM32F4芯片,其他芯片也差不多,原理类似。HAL库同样可以完成。
关于DMA发送完成中断,可根据实际情况,如果使用RTOS,一般发送数据是一个任务,这个任务会OS等待(检测)发送完成信号(即DMA发送完成中断)。

本文转载自公众号|strongerHuang

如有侵权 |联系删除

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 串口
    +关注

    关注

    15

    文章

    1591

    浏览量

    80222
  • dma
    dma
    +关注

    关注

    3

    文章

    576

    浏览量

    103463
  • 数据包
    +关注

    关注

    0

    文章

    269

    浏览量

    25033
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    由反激电源引起的一点儿分析

    由反激电源引起的一点儿分析 开关电源分为,隔离与非隔离两种形式,在这里主要谈谈隔离式开关电源的拓扑形式,隔离电源按照结构形式不同,可分 为两大类:正激式和反激式。反激式指在变压器原边导通时副边截止
    发表于 05-27 16:52

    高铁跑得快,不靠车头带

    这句话也是一点儿毛病都没有。但是如果你想用这句话描述当今高铁列车的动力系统,那毛病大了。今天就来和大家聊聊,高铁跑得那么快,既不是车头带的,又不是你领导带的,那到底
    的头像 发表于 02-08 11:25 ?635次阅读
    高铁跑得快,不靠车头带

    12位串行AD好用一点的有哪些介绍的?

    12位串行AD好用一点的有哪些介绍的
    发表于 02-06 07:05

    用LMP91200采集PH信号,LMP91200输出的电压会一点一点下降,是什么原因导致的?

    我用LMP91200采集PH信号。在前段信号无变化的情况下,LMP91200输出的电压会一点一点下降。电路连接我是参考LMP91200开发板的。 请问可能是什么原因?需要采取什么措施解决?
    发表于 02-05 06:12

    ZYNQ基础---AXI DMA使用

    前言 在ZYNQ中进行PL-PS数据交互的时候,经常会使用到DMA其实在前面的ZYNQ学习当中,也有学习过DMA的使用,那就是通过使用自定义的IP,完成HP接口向内存写入和读取数据的方式。同样
    的头像 发表于 01-06 11:13 ?2508次阅读
    ZYNQ基础---AXI <b class='flag-5'>DMA</b>使用

    救助,定义个大一点的数组导致编译不通过问题。

    本例使用 CSU-IDE V6.0.6 ,单片机为CSU38F20,发现在改大数组的时候编译不通过,请各位大神指教。具体问题描述如下: 正常情况: 串口收发缓冲区定义小一点没有问题,如下
    发表于 01-01 15:43

    串口设计些关键注意!千万别踩雷!

    本文将以Air700ECQ/EAQ/EMQ为例,带你从硬件设计的角度,起来了解串口设计中的些关键注意;软件开发或者AT设置方面不做深入探讨。 ?
    的头像 发表于 12-25 17:01 ?756次阅读
    <b class='flag-5'>串口</b>设计<b class='flag-5'>一</b>些关键注意<b class='flag-5'>点</b>!千万别踩雷!

    光纤外面的皮破了一点有关系吗

    光纤外面的皮破了一点,在般情况下,只要光纤的纤芯没有受到损伤,对通信通常是没有影响的。光纤的外皮主要起保护作用,能够防止光纤受到机械损伤、腐蚀、潮湿等外部环境的损害。如果外皮破损,但纤芯仍然保持
    的头像 发表于 11-25 10:04 ?2398次阅读

    TPA3255音量稍微大一点就会保护,需要重新启动,怎么解决?

    经过反复测3255 双声道模式2欧喇叭单元,音量稍微大一点就会保护,需要重新启动,4欧以上就没有任何问题,这个情况供电超过36V 才明显,尤其高压50V左右,只要音量有一点就保护了。单声道模式可以55V供电不保护。寻求解决办法,调整电阻,电容,或者加粗铜箔走线,并没有得
    发表于 09-30 08:32

    求推荐带宽高的单电源仪表放大器?

    有没有带宽高一点儿的单电源仪表放大器
    发表于 09-23 06:56

    大功率贴片电感的电感值偏大一点可以用吗

    电子发烧友网站提供《大功率贴片电感的电感值偏大一点可以用吗.docx》资料免费下载
    发表于 09-20 11:33 ?0次下载

    VCA810可变增益放大器按PDF的原理图来设计,怎么效果一点都不好呢?

    VCA810可变增益放大器,按着PDF的原理图来设计,怎么效果一点都不好呢,跟理论值差好远啊,增益变化根本不成线性,调了好久了,实在没有办法!
    发表于 09-14 06:18

    电感碎了一点点能正常用吗

    电子发烧友网站提供《电感碎了一点点能正常用吗.docx》资料免费下载
    发表于 09-04 11:32 ?0次下载

    HMC470控制电平改变,但是HMC470的衰减倍数还是一点都不变,为什么?

    HMC470控制电平改变,但是芯片的衰减倍数还是一点都不变 芯片是根据芯片的几个引脚的输入改变衰减倍数的 HMC470芯片是LCC封装的,就是那种四周有16个引脚的,引脚在芯片的正下方,芯片大小
    发表于 09-03 06:47

    发电机转子一点接地如何处理

    故障原因分析 发电机转子一点接地故障的原因主要有以下几种: 1.1 机械损伤 发电机转子在运行过程中,由于振动、摩擦等原因,可能导致转子绕组的绝缘层受到损伤,从而引发接地故障。 1.2 绝缘老化
    的头像 发表于 08-20 17:05 ?3645次阅读