基于DMA的ADC多通道采集_亲测

基于DMA的ADC多通道采集_亲测

其实像其他博主一样讲些原理的,大部分我们都懂些少许。

学习外设首先要在明白外设的作用之后,好了,不用在深究了,开始查看数据手册学习常用的外设寄存器都有什么作用。要想记住辣么多的外设都有什么作用,就先查看英文数据手册。之前我也是网上直接Copy代码,代码终究是在人家环境下写的,只能借鉴不能照搬。之后明白啦,就开始查看数据手册 ,理解还是很深刻的毕竟是自己动脑子想出来啦。

DMA interrupt status register (DMA_ISR)中断状态寄存器

  • ARM32位,顾名思义判断中断的状态
  • HTIFx: Channel x half transfer flag 半传输标志位
  • TCIFx: Channel x transfer complete flag 传输完成标志位

DMA interrupt flag clear register (DMA_IFCR)中断标志清楚寄存器

DMA channel x configuration register (DMA_CCRx)DMA通道配置寄存器

  • 该寄存器配置了大多数的DMA功能调节,具体内容可参考数据手册13.4.3(英文版)配合着代码查看即可。具体功能不再拗述。
  • 其中一个位4是配置外设是源地址还是目的地址,DIR: Data transfer direction

DMA channel x number of data register (DMA_CNDTRx)DMA通道x传输数量寄存器

  • 这个寄存器配置的是buffersize也就是DMA缓存的大小。举个例子:三个通道,每个通道采集10组那一共需要3*10个数据缓存位。其实他就是一个用来计数的,在当下时间开始DMA传输这个事件之后一共需要30次,每传输成功一次就减1,宽度都设为16位的,都需要通过一个32个寄存器来作为中转站,右对齐左对齐可自由配置。
  • 通过配置目的地址,也就是定义的二维数组名的地址,即可把源数据通过DMA传送到二维数组当中。

DMA channel x peripheral address register (DMA_CPARx)DMA通道x外设地址寄存器

  • 配置外设数据源的寄存器地址。

DMA channel x memory address register (DMA_CMARx)

  • 配置存储器地址,也就是你定义的二维数组的地址(地址即为数组名字)
以上的配置,基本上在基于DMA的ADC任务当中就够用啦。
以下是过程的理解:

首先简单啰嗦几句这个DMA的功能和条件

  1. 直接存储器存取(DMA)用来提供在外设(例如ADC、Timer等)和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
    这说明DMA的作用范围为外设产生的数据到存储器之间,和存储器和存储器之间可以调动DMA总线。
  2. 闪存、SRAM、外设的SRAM、以及搭载在APB1、APB2和AHB总线上的外设均可作为访问的源和目标。
  3. DMA通道和外设之间有固定的地址,不同的通道和外设不能建立链接。具体如下:
    在这里插入图片描述
  4. DMA和外设之间大致的工作流程,就拿ADC来说,当启动了ADC_DMACmd()(这个是ADC的配置寄存器可以自己查看数据手册)这个函数后,DMA和ADC之间就建立啦链接。在发生一个事件后,外设向DMA控制器发送一个请求信号。DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问发出请求的外设时,DMA控制器立即发送给它一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。如果有更多的请求时,外设可以启动下一个周期。
  5. 当传输一半的数据后,半传输标志(HTIF)被置1,当设置了允许半传输中断位(HTIE)时,将产生一个中断请求。在数据传输结束后,传输完成标志(TCIF)被置1,当设置了允许传输完成中断位(TCIE)时,将产生一个中断请求。
  6. 这个的意思就是,假设你定义了一个二维数组,那么当A*B个数据传送一半完成或者传送完成之后,设置了中断允许则可产生中断请求。
  7. 假设ADC的ADC->DR(为ADC的数据暂存寄存器)为源地址,配置CPAR位即可,每当传输完成一个12为的AD值之后地址就会按照你配置的数据位进行相应的地址递增进行传输。看图:
    在这里插入图片描述
    配置的存储器的地址递增,因为你的二维数组链表要一次的存储数据啊,而源地址ADC的DR寄存器根本不需要进行地址的递增,因为是固定的。
  8. 循环模式用于处理循环缓冲区和连续的数据传输(如ADC的扫描模式)。在DMA_CCRx寄存器中的CIRC位用于开启这一功能。当启动了循环模式,数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA操作将会继续进行。说一下这个循环缓冲区,DMA占用的也是内核的系统数据总线,而这个总线想必大家都知道那可不是在总线上待着玩呢,都是瞬时完成的。每当ADC转化一次数据完成之后(也就是CPU处理了数据你可以理解为你的电压值),DMA说,大哥你只管计算数据就啦,剩下的交给我吧,即DMA占用一下数据总线(查的手册为占用一半的资源),把数据发送到你定义的二维数组地址下的存储空间。假设你定义了10组两个通道大小的AD值,那么ADC会一直转换直到20组,那么在这个过程当中,CPU只管计算(比如采样、编码、量化等,这些可查看ADC)之后DMA尽快的去把数据送到二维数组当中。在这个DMA送数据的连续过程当中就为循环缓冲区。
  9. 为什么数据传输当中的源和目的都是半字16位呢,因为首先我的ADC是12位的也就是分辨率为1/4096,因为DMA固定的位数不是随意定的,所以只能选择16位了,而且数据对齐方式为右对齐,这个是看个人喜好的。对于32位的ARM来说,数据从右到左存放感觉还是挺顺心的。
到这里DMA的具体内容就这么多啦。其实看看数据手册基本上没有多大的问题。
下面贴一段代码:
  DMA_DeInit(DMA1_Channel1);    //将通道一寄存器设为默认值
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);//该参数用以定义DMA外设基地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue;//该参数用以定义DMA内存基地址(转换结果保存的地址)
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//该参数规定了外设是作为数据传输的目的地还是来源,此处是作为来源
  DMA_InitStructure.DMA_BufferSize = 2*10;//定义指定DMA通道的DMA缓存的大小,单位为数据单位。这里也就是ADCConvertedValue的大小
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设定外设地址寄存器递增与否,此处设为不变 Disable
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//用来设定内存地址寄存器递增与否,此处设为递增,Enable
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度为16位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为16位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA通道拥有高优先级 分别4个等级 低、中、高、非常高
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//使能DMA通道的内存到内存传输
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);//根据DMA_InitStruct中指定的参数初始化DMA的通道
	DMA_ClearITPendingBit(DMA1_IT_TC1);  

	DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, ENABLE); 
	  //中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	DMA_Cmd(DMA1_Channel1,ENABLE);

里面的2*10即为,两个通道每个通道采样十次;其他的配置已经在上面啰嗦啦一大堆不再拗述啦。

  ADC_InitStructure.ADC_ScanConvMode = ENABLE;     
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  //配置DMA允许连续转换模式

这个是ADC的配置,两点,一是循环浏览模式开启多通道扫描传输。二是需要连续转化才行,不言而喻。

最后你只需要去处理的目的地址也就是二维数组的值就可以啦。

这里特别重要的一点就是,数组要开辟为10行2列的十维数组,
在这里插入图片描述

  • 10
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值