当前位置: 首页 > web >正文

STM32-DMA

DMA:用于实现外设与储存器之间或者存储器与存储器之间数据传输的高效性,无需CPU直接操作

特性:12个独立可配置的通道(请求):DMA1:7个通道;DMA2:5个通道

每个通道都直接连接专用的硬件DMA请求;每个通道都同样支持软件触发;多个请求间的优先权可通过编程设置(很高;高;中等和低)优先权的设置相等时,由硬件决定(请求0优先于请求1)

在一个通道中同一时间只能产生一个外设

软件设计流程:

  • 从哪里来那里出

要传多少;单位是什么。硬件阶段-通道编号。外设-存储器;存储器-外设;存储器-存储器

  • 初始化DMA通道
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1时钟使能 
typedef struct
{uint32_t DMA_PeripheralBaseAddr; /*!< 指定DMAy通道x的外设基地址 */uint32_t DMA_MemoryBaseAddr;     /*!< 指定DMAy通道x的内存基地址 */uint32_t DMA_DIR;                /*!< 指定外设是源还是目标此参数可以是@ref DMA_data_transfer_direction中的值 */uint32_t DMA_BufferSize;         /*!< 指定指定通道的缓冲区大小,以数据单元为单位。数据单元等于根据传输方向在DMA_PeripheralDataSize或DMA_MemoryDataSize成员中设置的配置。 */uint32_t DMA_PeripheralInc;      /*!< 指定外设地址寄存器是否递增。此参数可以是@ref DMA_peripheral_incremented_mode中的值 */uint32_t DMA_MemoryInc;          /*!< 指定内存地址寄存器是否递增。此参数可以是@ref DMA_memory_incremented_mode中的值 */uint32_t DMA_PeripheralDataSize; /*!< 指定外设数据宽度。此参数可以是@ref DMA_peripheral_data_size中的值 */uint32_t DMA_MemoryDataSize;     /*!< 指定内存数据宽度。此参数可以是@ref DMA_memory_data_size中的值 */uint32_t DMA_Mode;               /*!< 指定DMAy通道x的操作模式。此参数可以是@ref DMA_circular_normal_mode中的值。@note: 如果在所选通道上配置了内存到内存的数据传输,则不能使用循环缓冲区模式 */uint32_t DMA_Priority;           /*!< 指定DMAy通道x的软件优先级。此参数可以是@ref DMA_priority_level中的值 */uint32_t DMA_M2M;                /*!< 指定DMAy通道x是否用于内存到内存传输。此参数可以是@ref DMA_memory_to_memory中的值 */
} DMA_InitTypeDef;
  • 使能外设DMA功能(DMA请求映射图对应外设)
/*** @brief  启用或禁用指定的DMA通道* @param  DMAy_Channelx: 指向DMA通道结构体的指针*         例如: DMA1_Channel1, DMA1_Channel2, ...* @param  NewState: 新状态*         取值范围: ENABLE 或 DISABLE* @retval 无*/
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState)
/*** @brief  设置DMA通道的当前数据传输计数器值* @param  DMAy_Channelx: 指向DMA通道结构体的指针*         例如: DMA1_Channel1, DMA1_Channel2, ...* @param  DataNumber: 要传输的数据单元数量*         取值范围: 0x0001 ~ 0xFFFF* @note   此值会被加载到DMA_CNDTRx寄存器中*         当DMA传输时,此计数器会递减至0* @retval 无*/
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber)
  • 开启DMA的通道传输()
/*** @brief  启用或禁用USART的DMA请求* @param  USARTx: 指向USART外设结构体的指针*         例如: USART1, USART2, ...* @param  USART_DMAReq: 指定要配置的DMA请求*         取值范围: *           - USART_DMAReq_Tx: 发送缓冲区空中断触发DMA请求*           - USART_DMAReq_Rx: 接收缓冲区非空中断触发DMA请求* @param  NewState: 新状态*         取值范围: ENABLE 或 DISABLE* @note   此函数会设置或清除USART_CR3寄存器中的DMAT/DMAR位* @retval 无*/
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)
  • 查询DMA传输状态
/*** @brief  检查指定的DMA标志位状态* @param  DMAy_FLAG: 指定要检查的DMA标志位*         取值范围:*           - DMA1_FLAG_GL1:  DMA1通道1全局标志*           - DMA1_FLAG_TC1:  DMA1通道1传输完成标志*           - DMA1_FLAG_HT1:  DMA1通道1半传输完成标志*           - DMA1_FLAG_TE1:  DMA1通道1传输错误标志*           - ... 以此类推,支持DMA1所有通道和DMA2相关标志* @retval FlagStatus: 标志位状态*           - SET:   标志位被设置(事件发生)*           - RESET: 标志位未被设置(事件未发生)* @note   不同DMA通道的标志位位于不同的寄存器中*         例如: DMA1通道1-4的标志在DMA1_ISR寄存器中*/
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
/*** @brief  清除指定的DMA标志位* @param  DMAy_FLAG: 指定要清除的DMA标志位*         取值范围:*           - DMA1_FLAG_GL1:  DMA1通道1全局标志*           - DMA1_FLAG_TC1:  DMA1通道1传输完成标志*           - DMA1_FLAG_HT1:  DMA1通道1半传输完成标志*           - DMA1_FLAG_TE1:  DMA1通道1传输错误标志*           - ... 以此类推,支持DMA1所有通道和DMA2相关标志* @retval 无* @note   不同DMA通道的标志位清除需写入对应的DMA_IFCR寄存器*         例如: 清除DMA1通道1的标志需写入DMA1_IFCR寄存器*/
void DMA_ClearFlag(uint32_t DMAy_FLAG)

 实际代码(DMA-USART1外设发送数据)

#include "dma.h"/*******************************************************************************
* 函 数 名         : DMAx_Init
* 函数功能		   : DMA初始化函数
* 输    入         : DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7par:外设地址mar:存储器地址ndtr:数据传输量
* 输    出         : 无
*******************************************************************************/ 
void DMAx_Init(DMA_Channel_TypeDef* DMAy_Channelx,u32 par,u32 mar,u16 ndtr)
{DMA_InitTypeDef  DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1时钟使能 //DMA_DeInit(DMAy_Channelx);/* 配置 DMA */DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址DMA_InitStructure.DMA_MemoryBaseAddr = mar;//DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//存储器到外设模式DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输DMA_Init(DMAy_Channelx, &DMA_InitStructure);//初始化DMA }/*******************************************************************************
* 函 数 名         : DMAx_Enable
* 函数功能		   : 开启一次DMA传输
* 输    入         : DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7ndtr:数据传输量
* 输    出         : 无
*******************************************************************************/ 
void DMAx_Enable(DMA_Channel_TypeDef *DMAy_Channelx,u16 ndtr)
{DMA_Cmd(DMAy_Channelx, DISABLE);                      //关闭DMA传输 DMA_SetCurrDataCounter(DMAy_Channelx,ndtr);          //数据传输量  DMA_Cmd(DMAy_Channelx, ENABLE);                      //开启DMA传输 
}	  

主函数代码

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart1.h"
#include "key.h"
#include "dma.h"#define send_buf_len 5000
u8 send_buf[send_buf_len];
/*******************************************************************************
* 函 数 名         : Send_Data
* 函数功能		   : 要发送的数据
* 输    入         : p:指针变量			 
* 输    出         : 无
*******************************************************************************/
void Send_Data(u8 *p)
{u16 i;for(i=0;i<send_buf_len;i++){*p='5';p++;}
}/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
int main()
{u8 i=0;u8 key;SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组LED_Init();USART1_Init(115200);KEY_Init();DMAx_Init(DMA1_Channel4,(u32)&USART1->DR,(u32)send_buf,send_buf_len);//DMA1通道4,外设USART1-TX,数组首地址,数组长度Send_Data(send_buf);while(1){key=KEY_Scan(0);if(key==KEY_UP_PRESS){USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送     DMAx_Enable(DMA1_Channel4,send_buf_len);     //开始一次DMA传输!//等待DMA传输完成,此时我们来做另外一些事//实际应用中,传输数据期间,可以执行另外的任务while(1){if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=0)//判断通道4传输完成{DMA_ClearFlag(DMA1_FLAG_TC4);break;}LED2=!LED2;delay_ms(300);	}}i++;if(i%20==0){LED1=!LED1;}delay_ms(10);	}
}

http://www.xdnf.cn/news/15649.html

相关文章:

  • 数字魔方--玩转魔方的助手
  • oracle2kingbase的字段长度问题
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | AutoTextEffect(自动打字机)
  • 尚庭公寓-------图片上传接口
  • 【c++深入系列】:万字详解list(附模拟实现的list源码)
  • 【unitrix】 6.4 类型化数特征(t_number.rs)
  • JavaScript进阶篇——第六章 内置构造函数与内置方法
  • 21、鸿蒙Harmony Next开发:组件导航(Navigation)
  • 主机安全---开源wazuh安装
  • 【Unity】IL2CPP相关理论知识学习
  • Spring MVC中@PathVariable的用法详解
  • AR智能巡检:电力行业数字化转型的“加速器”
  • Java 8新特性 函数式编程实践
  • python基础②-数据结构
  • 第二十一 篇 PDF文档自动化:Python一键合并、分割、水印、提取与加密解密!你的PDF全能管家!
  • 《通信原理》学习笔记——第二章
  • 【前端】Vue3 前端项目实现动态显示当前系统时间
  • 【TVM 教程】FAQ
  • 筑牢网络安全防线:DDoS/CC 攻击全链路防护技术解析
  • Hadoop(三)
  • PyTorch 损失函数详解:从理论到实践
  • Qt小组件 - 7 SQL Thread Qt访问数据库ORM
  • Uniapp中双弹窗为什么无法显示?
  • 玩转Docker | 使用Docker部署bender个人导航页工具
  • 利用Java自定义格式,循环导出数据、图片到excel
  • 【论文阅读 | CVPR 2023 |CDDFuse:基于相关性驱动的双分支特征分解的多模态图像融合】
  • lua(xlua)基础知识点记录
  • 【前端】在Vue3中绘制多系列柱状图与曲线图
  • 量子比特耦合与系统集成:量子计算硬件的核心突破
  • 入门华为数通,HCIA/HCIP/HCIE该怎么选?