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

stm32 DMA

1、原理

软件触发适用于从存储器到存储器的数据转运(通道可以任意选择)。如把Flash里的数据,转运到SRAM里

硬件触发适用于从外设到存储器的数据转运,外设的数据需要处理完再转运。如转运ADC的数据,等到ADC每个通道AD转换完成后硬件触发一次DMA,之后DMA再转运

特定的硬件触发是指每个DMA通道的硬件触发源是不同的,想要使用特定的硬件触发源就要使用其对应的通道

内部结构分析

总线矩阵的左端为主动单元,拥有存储器的访问权,如DCode(专门访问Flash)、系统总线、   DMA总线;右端为被动单元,它们的存储器只能被左边的主动单元读写     

DMA模块内部存在多个通道,可以分别设置它们转运数据的源地址和目的地址                                仲裁器用于多个通道产生冲突时,根据通道的优先级决定顺序。多个通道虽然可以独立转运数据,但是所有通道只能分时复用一条DMA总线

在总线矩阵内部也存在一个仲裁器,如果DMA和CPU同时访问同一个目标,CPU的访问会被暂停(CPU仍能得到一半的总线带宽)

AHB从设备,也是DMA自身的寄存器,用于DMA配置,DMA既是总线矩阵上的主动单元,也是AHB总线上的被动单元,CPU通过AHB总线就可以对DMA进行配置了    

DMA请求,DMA硬件触发源,如ADC转换完成、串口接收到数据,就会通过这条线路来向DMA发送硬件触发信号

基本结构

要进行存储器到存储器的数据转运,将其中一个存储器的地址放在外设站点。

传输计数器用于指定总共需要转运几次(DMA关闭时),自减计数器,每次转运1次计数器的数就会减1。

自动重装器,设置循环模式,传输计数器减到0之后可以选择恢复到最初的值,进行下一轮工作

M2M,存储器到存储器,M2M位为1时,DMA选择软件触发。与ADC软件触发不同,以最快的速度,连续不断地触发DMA,将传输计数器清零,完成这一轮转换。软件触发适合从存储器到存储器的转运,软件启动,不需要特定的时机。M2M位为0时,DMA选择硬件触发,一般与外设有关,如ADC转换完成、串口接收数据、定时器时间到,同时还要在对应外设调用XXX_DMA_Cmd

DMA进行转运条件:

1、开关控制,DMA_Cmd使能                                                                                     

2、传输计数器大于0

3、有触发信号

M2M软件触发和自动重装器循环模式不能一起使用,不然传输计数器会不断地清零再恢复,DMA停不下来。 

2、代码

        不重装,软件触发

uint16_t MyDmasize=0;/*
@para Addr1:外设地址
@para Addr2:存储器地址
@para size:转运数据的个数
*/
void MyDMA_Init(uint32_t Addr1, uint32_t Addr2, uint16_t size)
{MyDmasize=size;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);DMA_InitTypeDef DMA_InitStruct;//外设站点配置//起始地址DMA_InitStruct.DMA_PeripheralBaseAddr=Addr1;//数据宽度DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//是否自增DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Enable;//存储器站点配置DMA_InitStruct.DMA_MemoryBaseAddr=Addr2;DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//传输方向DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;//传输计数器DMA_InitStruct.DMA_BufferSize=size;//配置传输计数器是否要重装DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;DMA_InitStruct.DMA_M2M=DMA_M2M_Enable;DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;DMA_Init(DMA1_Channel1, &DMA_InitStruct);DMA_Cmd(DMA1_Channel1, ENABLE);
}
//每次转换时调用一次
void DMA_Transfer()
{//给传输计数器赋值时,DMA需要处于失能状态DMA_Cmd(DMA1_Channel1, DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1, MyDmasize);DMA_Cmd(DMA1_Channel1, ENABLE);//等待数据转运完成while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);DMA_ClearFlag(DMA1_FLAG_TC1);
}

 DMA+AD多通道,自动重装

#include "stm32f10x.h"                  // Device headeruint16_t AD_Value[4];void Ad_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//配置ADCCLK时钟分频,ADC的输入时钟不得超过14MHzRCC_ADCCLKConfig(RCC_PCLK2_Div6);GPIO_InitTypeDef GPIO_InitStructure;//初始化为模拟输入引脚GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3|GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_1Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_1Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 4, ADC_SampleTime_1Cycles5);ADC_InitTypeDef ADC_InitStruct;//独立模式 ADC1 和 ADC2 单独转换ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//选择数据对齐 左对齐、右对齐ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//外部触发源选择, 这里使用软件触发,所以选择NoneADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//连续转换模式, 选择单次转换还是连续转换ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;//扫描转换模式, 选择扫描模式还是非扫描模式ADC_InitStruct.ADC_ScanConvMode=ENABLE;//通道数目, 只有在扫描模式下才能使用多个通道ADC_InitStruct.ADC_NbrOfChannel=4;ADC_Init(ADC1, &ADC_InitStruct);DMA_InitTypeDef DMA_InitStruct;//外设站点配置//起始地址//设置地址为ADC1数据寄存器,别忘了取地址符&DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//数据宽度//DR寄存器里低16位是ADC1数据存储的地方,所以DMA转运的数据宽度为16位DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//是否自增//始终转运ADC1->DR上的数据DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//存储器站点配置DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)AD_Value;DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//传输方向DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;//传输计数器DMA_InitStruct.DMA_BufferSize=4;//配置传输计数器是否要重装DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;//软件触发还是硬件触发DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;DMA_Init(DMA1_Channel1, &DMA_InitStruct);DMA_Cmd(DMA1_Channel1, ENABLE);//开启ADC的DMA输出ADC_DMACmd(ADC1, ENABLE);ADC_Cmd(ADC1, ENABLE);//手册中建议在每次上电后执行一次校准//复位校准ADC_ResetCalibration(ADC1);//等待复位校准完成, 复位校准完成后为 RESETwhile(ADC_GetResetCalibrationStatus(ADC1)==SET);//开始校准ADC_StartCalibration(ADC1);//等待校准完成while(ADC_GetCalibrationStatus(ADC1)==SET);//连续转换仅需要在最开始触发一次就可以,//软件触发转换函数可以挪到初始化最后,不需要每次取值都使用ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

相关文章:

  • Slidev集成Chart.js:专业数据可视化演示文稿优化指南
  • CAPL Class: TcpSocket (此类用于实现 TCP 网络通信 )
  • 电机试验平台:创新科技推动电动机研究发展
  • Windows/MacOS WebStorm/IDEA 中开发 Uni-App 配置
  • C 语言学习笔记(数组)
  • 使用UniApi调用百度地图API的需要注意的地方
  • asp.net core api RESTful 风格控制器
  • STM32之蜂鸣器和按键
  • 支持同步观看的媒体服务器GhostHub
  • SpringCloud微服务开发与实战
  • 初识计算机网络。计算机网络基本概念,分类,性能指标
  • 代码随想录60期day38
  • “分布形态“
  • Java 常用的Arrays函数
  • 初识仓颉编程语言:高效、简洁与创新的编程选择
  • C++:字符串操作函数
  • uniapp-商城-60-后台 新增商品(属性的选中和页面显示,数组join 的使用)
  • NexBot AI 1.9.3 | 专业AI写作助手,高自由度定制内容,支持中文设置
  • foxmail - foxmail 启用超大附件提示密码与帐号不匹配
  • ESP32 PWM开发对比:底层驱动 VS Arduino封装,谁更适合你?
  • 美国失去最后一个AAA评级,资产价格怎么走?美股或将触及天花板
  • 解锁儿时愿望!潘展乐战胜孙杨,全国冠军赛男子400自夺冠
  • 美国贸易政策|特朗普模式:你想做交易吗?
  • 中国情怀:时代记录与家国镜相|澎湃·镜相第三届非虚构写作大赛征稿启事
  • 马上评|文玩字画竞拍轻松赚差价?严防这类新型传销
  • 外企聊营商|武田制药:知识产权保护助创新药研发