昨天做了一个ADC的程序一直想学习一下DMA的配置,我一直也是不懂DMA到底有什么用处,还是感觉很**肋。稍微配置了一下,我是这样理解DMA的。在配置了dma之后我们adc的数据不会再由cpu搬运,我们直接读取我们DMA数据是节省adc时间。直接看配置
void MY_ADC_Init(void)
{
ADC_ChannelConfTypeDef ADC1_ChanConf;
ADC1_Handler.Instance=ADC1;
ADC1_Handler.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=90/4=22.5MHZ
ADC1_Handler.Init.Resolution=ADC_RESOLUTION_12B; //12位模式
ADC1_Handler.Init.DataAlign=ADC_DATAALIGN_RIGHT; //右对齐
ADC1_Handler.Init.ScanConvMode=ENABLE; //非扫描模式
ADC1_Handler.Init.EOCSelection=DISABLE; //关闭EOC中断
ADC1_Handler.Init.ContinuousConvMode=ENABLE; //开启连续转换
ADC1_Handler.Init.NbrOfConversion=2; //2个转换在规则序列中 也就是只转换规则序列2
ADC1_Handler.Init.DiscontinuousConvMode=DISABLE; //禁止不连续采样模式
ADC1_Handler.Init.NbrOfDiscConversion=0; //不连续采样通道数为0
ADC1_Handler.Init.ExternalTrigConv=ADC_SOFTWARE_START; //软件触发
ADC1_Handler.Init.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE;//使用软件触发
ADC1_Handler.Init.DMAContinuousRequests=ENABLE; //关闭DMA请求
HAL_ADC_Init(&ADC1_Handler); //初始化
ADC1_ChanConf.Channel= ADC_CHANNEL_5; //通道
ADC1_ChanConf.Rank=1; //第1个序列,序列1
ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
ADC1_ChanConf.Offset=0; /好像没用
HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
ADC1_ChanConf.Channel= ADC_CHANNEL_4; //通道
ADC1_ChanConf.Rank=2; //第1个序列,序列1
ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
ADC1_ChanConf.Offset=0;
HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);
MY_ADC_DMA_Init();
}
__HAL_RCC_DMA2_CLK_ENABLE();
DMA2_Handler.Instance =DMA2_Stream0; //数据流0
DMA2_Handler.Init.Channel =DMA_CHANNEL_0; //通道0
DMA2_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY; //数据传输方向:外设->内存
DMA2_Handler.Init.PeriphInc=DMA_PINC_DISABLE; //外设地址不变
DMA2_Handler.Init.MemInc=DMA_MINC_ENABLE; //内存地址递增
DMA2_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD;//数据半字16位
DMA2_Handler.Init.MemDataAlignment=DMA_PDATAALIGN_HALFWORD; //数据半字16位
DMA2_Handler.Init.Mode=DMA_CIRCULAR; //循环模式
DMA2_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;//DMA传输方式有关数据格式几次传输
DMA2_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
DMA2_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;
DMA2_Handler.Init.MemBurst=DMA_MBURST_SINGLE;
DMA2_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;
__HAL_LINKDMA(&ADC1_Handler,DMA_Handle,DMA2_Handler);
/* Configure DMA Stream source address */
DMA2_Handler.Instance->PAR = (u32)&ADC1->DR; //外设地址
DMA2_Handler.Instance->M0AR = (vu32)ADC_DMA_ConvertedValue;//内存缓冲地址
DMA2_Handler.Instance->NDTR =2;//数据长度
HAL_DMA_Init(&DMA2_Handler);
HAL_DMA_Start (&DMA2_Handler,(u32)&ADC1->DR,(unsigned int)&ADC_DMA_ConvertedValue,2);//开启DMA
}
基本配置就是这样我们在
void Get_Adc_Average(u16 *temp,u8 times)
{
u32 temp_val[2]={0};
u8 t;
for(t=0;t<times;t++)
{
HAL_ADC_Start_DMA(&ADC1_Handler,(uint32_t*)&ADC_DMA_ConvertedValue,2);
temp_val[0]+=ADC_DMA_ConvertedValue[0];
temp_val[1]+=ADC_DMA_ConvertedValue[1];
delay_ms(5);
}
temp[0]=temp_val[0]/times;
temp[1]=temp_val[1]/times;
}
void ADC_DMA_Open(void)
{
//DMA config
HAL_ADC_Start(&ADC1_Handler); //开启ADC
MY_ADC_DMA_Init();
//ADC
HAL_ADC_Start_DMA(&ADC1_Handler,(uint32_t*)&ADC_DMA_ConvertedValue,2);
}
我在采样时取了十次求均值滤波值处理一下好像每次采样都要
HAL_ADC_Start_DMA(&ADC1_Handler,(uint32_t*)&ADC_DMA_ConvertedValue,2);这和先开启否则不会传入DMA有兴趣可以深入理解一下这个函数的用处。我也是简单学习一下就不在深究。到这配置就结束了
|