采样DMA的原理和配置方法
因为ADC规则组数据寄存器ADC_DR只有一个,如果使用多通道转换,那转换的数据就全部都挤在ADC_DR里面了,前一个时间点转换的通道数据,就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走,或者开启DMA模式,把数据传输到内存里面,不然就会造成数据的覆盖。多通道ADC采集一般使用DMA进行数据传输,该方法更加高效方便。
注:只有ADC1拥有DMA功能。由ADC2转化的数据可以通过双ADC模式,利用ADC1的 DMA功能传输。
DMA间接
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。ADC1使用的是DMA1的通道1。
DMA初始化结构体详解
DMA_InitTypeDef初始化结构体结构体用于设置DMA的工作参数,其具体的定义如下:
typedef struct
{
uint32_t DMA_PeripheralBaseAddr;
uint32_t DMA_MemoryBaseAddr;
uint32_t DMA_DIR;
uint32_t DMA_BufferSize;
uint32_t DMA_PeripheralInc;
uint32_t DMA_MemoryInc;
uint32_t DMA_PeripheralDataSize;
uint32_t DMA_MemoryDataSize;
uint32_t DMA_Mode;
uint32_t DMA_Priority;
uint32_t DMA_M2M;
}DMA_InitTypeDef;
1) DMA_PeripheralBaseAddr:外设地址,设定DMA_CPAR寄存器的值;一般设置为外设的数据寄存器地址,如果是存储器到存储器模式则设置为其中一个存储器地址。我么是把ADC采集到的数据通过DMA传输到存储器上,则外设地址为ADC的数据寄存器。
2) DMA_Memory0BaseAddr:存储器地址,设定DMA_CMAR寄存器值;一般设置为我们自定义的用来存放ADC数据的数组地址。
3) DMA_DIR:传输方向选择,可选外设到存储器、存储器到外设。它设定 DMA_CCR寄存器的DIR[1:0]位的值。这里并没有存储器到存储器的方向选择,当使用存储器到存储器时,只需要把其中一个存储器当作外设使用即可。本章选择为外设到存储器。
4) DMA_BufferSize:设定待传输数据数目,初始化设定DMA_CNDTR寄存器的值,其大小等于我们定义的存储ADC数据的数组大小。
5)DMA_PeripheralInc:如果配置为 DMA_PeripheralInc_Enable,使能外设地址自动递增功能,它设定DMA_CCR寄存器的PINC位的值;因为ADC转换的数据都存放在一个数据寄存器中,则外设地址不变。
6) DMA_MemoryInc:如果配置为 DMA_MemoryInc_Enable,使能存储器地址自动递增功能,它设定DMA_CCR寄存器的MINC位的值;因为我们自定义的数组用来存放两个数据,所以要使能存储器地址自动递增功能。
7) DMA_PeripheralDataSize:外设数据宽度,可选字节(8位)、半字(16位) 和字(32位),它设定DMA_CCR寄存器的PSIZE[1:0]位的值。
8) DMA_MemoryDataSize:存储器数据宽度,可选字节(8位)、半字(16位) 和字(32位),它设定DMA_CCR寄存器的MSIZE[1:0]位的值。外设和存储器单位均为两个字节。
9) DMA_Mode:DMA传输模式选择,可选一次传输或者循环传输,它设定 DMA_CCR寄存器的CIRC位的值。例程我们的ADC采集是持续循环进行的,所以使用循环传输模式。当启动了循环模式,数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA操作将会继续进行。
ADC的工作参数配置
// 只使用一个ADC,属于单模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 扫描模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE ;
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 转换通道个数
ADC_InitStructure.ADC_NbrOfChannel = 2;
// 初始化ADC
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC时钟N狿CLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置ADC 通道的转换顺序和采样时间
ADC_RegularChannelConfig(ADC1, ADC_CHANNEL1, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_CHANNEL2, 2, ADC_SampleTime_55Cycles5);
// 使能ADC DMA 请求
ADC_DMACmd(ADC1, ENABLE);
// 开启ADC ,并开始转换
ADC_Cmd(ADC1, ENABLE);
// 初始化ADC 校准寄存器
ADC_ResetCalibration(ADC1);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADC1));
// ADC开始校准
ADC_StartCalibration(ADC1);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADC1));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
因为只是使用一个 ADC,所以模式配置为独立模式;例程中使用了ADC1的两个通道进行采集,因此需要开启扫描模式,当一个通道转换结束时,同一组的下一个通道将被自动转换;例程实现不间断的对外部模拟数据进行采集,因此使能连续转换模式。ADC的转换采用软件触发的方式,因此不使用外部触发转换信号。转换结果右对齐;转换通道数为2;因为是两个通道进行采集,所以调用ADC_RegularChannelConfig()函数设置每个通道的转换顺序和采样时间。
-
寄存器
+关注
关注
31文章
5308浏览量
119975 -
存储器
+关注
关注
38文章
7447浏览量
163579 -
adc
+关注
关注
98文章
6429浏览量
544033 -
dma
+关注
关注
3文章
559浏览量
100411
原文标题:MCU微课堂|CKS32F107xx系列 ADC(二)
文章出处:【微信号:中科芯MCU,微信公众号:中科芯MCU】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论