当前位置: 首页 > 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);
}

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

相关文章:

  • 【八股战神篇】Java集合高频面试题
  • Redis Sentinel如何实现高可用?
  • 类加载 与 Spring容器加载
  • STM32 | 软件定时器
  • 【发票提取表格】批量PDF电子发票提取明细保存到Excel表格,批量提取ODF电子发票明细,行程单明细,单据明细保存到表格,使用步骤、详细操作方法和注意事项
  • Java—异常体系
  • 【Linux笔记】——Linux线程封装
  • Ulyssess Ring Attention
  • Python文件与JSON操作全解:从基础到企业级实践
  • A级、B级弱电机房数据中心建设运营汇报方案
  • Ankr:Web3基础设施的革新者
  • Zephyr OS 中的 FIFO 接口应用介绍
  • SECERN AI提出3D生成方法SVAD!单张图像合成超逼真3D Avatar!
  • Windows系统部署MongoDB数据库图文教程
  • 机器学习-人与机器生数据的区分模型测试-数据处理 - 续
  • 【漫话机器学习系列】263.线性插值(Interpolation)
  • img.dims() <= 2 in function ‘cv::matchTemplate报错
  • Mysql 刷题 day05
  • 数学复习笔记 19
  • 1.2.1电商平台
  • 探索C++对象模型:(拷贝构造、运算符重载)成员函数的深度解读(中篇)
  • 力扣HOT100之二叉树:98. 验证二叉搜索树
  • 【网络入侵检测】基于Suricata源码分析运行模式(Runmode)
  • STM32烧录程序正常,但是运行异常
  • 实战2:利用Python与AI模型实现文本分类
  • STM32F103定时器1每毫秒中断一次
  • 机器学习中的过拟合及示例
  • 咖啡叶子病害检测数据集VOC+YOLO格式1468张4类别均为单叶子
  • mac-M系列芯片安装软件报错:***已损坏,无法打开。推出磁盘问题
  • PySide6 GUI 学习笔记——常用类及控件使用方法(常用类颜色常量QColorConstants)