您的位置:首页 > 其它

针对stm32 DMA传输AD数据,在完成中断后如何复位的问题的思考

2014-12-04 18:52 351 查看
案发条件

ADC连续单通道模式AD采集,触发DMA获取数据。程序如下

void ADC_DMAInit(void)

{

ADC_InitTypeDef ADC_InitStructure;

RCC_HSICmd(ENABLE); // Enable HSI Clock

ADC_IO_Init();

while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);



RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

ADC_DeInit(ADC1);

//AD转换结果为8位

ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;

//AD工作在单通道模式

ADC_InitStructure.ADC_ScanConvMode = DISABLE;

//模数转换工作在连续模式

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

//转换由定时器触发启动ADC_ExternalTrigConv_T2_CC2

//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

//上升沿下降沿触发ADC_ExternalTrigConvEdge_RisingFalling

ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

//ADC数据右对齐

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

//顺序进行规则转换的ADC通道的数目

ADC_InitStructure.ADC_NbrOfConversion = 1;

ADC_Init(ADC1, &ADC_InitStructure);

//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间(取最大值)

ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_4Cycles);
// CH0

//ADC_InterruptInit();

ADC_ClearFlag(ADC1,ADC_FLAG_EOC);

//使能ADC1的DMA请求

ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */

ADC_Cmd(ADC1, ENABLE);

//等待ADC1准备好

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET)

{

}

//循环通道没有准备好

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_RCNR) != RESET);

/* Start ADC1 Software Conversion */

ADC_SoftwareStartConv(ADC1);

}

DMA工作在从AD到内存的单次工作模式,开启完成触发中断,程序如下

/* 针对ADC的应用来配置DMA */

void DMA_ADCInit(void)

{

DMA_InitTypeDef DMA_InitStructure;

//开启DMA的第一通道的时钟

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

//复位DMA1通道的设置

DMA_DeInit(DMA1_Channel1);

//DMA对应的外设基地址,AD采样的数据存放地址

DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)ADC1_DR_ADDRESS);

//DMA对应的内存基地址

DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)g_u16ADC_DataArr;

//DMA缓存大小

DMA_InitStructure.DMA_BufferSize = DMA_BUFF_SIZE;


DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

//DMA的转换模式是SRC模式,就是从外设向内存中搬运

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;


//接收一次数据后,设备地址是否后移

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

//接收一次数据后,目标内存地址是否后移

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

//转换结果的数据大小

DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;

//DMA搬运的数据尺寸,16位

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

//DMA优先级,高

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

//M2M模式禁止

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;


DMA_Init(DMA1_Channel1, &DMA_InitStructure);

//使能DMA传输完成中断中断

DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

/* Configure the SysTick Handler Priority: Preemption priority and subpriority */

IRQ_DMA1_Channel1_Config();



/* Enable DMA channel1 */

DMA_Cmd(DMA1_Channel1, ENABLE);

}

想要解决的问题:

在DMA触发完成中断后,如果想重新开启AD和DMA继续采集数据。如何做?请继续向下看。

DMA中断处理程序见下

void DMA1_Channel1_IRQHandler(void)

{

DMA_InitTypeDef DMA_InitStructure;

if(DMA_GetITStatus(DMA1_IT_TC1))

{

DMA_ClearITPendingBit(DMA1_IT_TC1);

DMA_ClearITPendingBit(DMA1_IT_HT1);

//复位DMA1通道的设置

/* Disable the selected DMAy Channelx */

DMA1_Channel1->CCR &= (uint16_t)(~DMA_CCR1_EN);



//DMA缓存大小

DMA_SetCurrDataCounter(DMA1_Channel1 , DMA_BUFF_SIZE);

DMA_Cmd(DMA1_Channel1, ENABLE);

ADC_ClearFlag(ADC1,ADC_SR_OVR);

ADC_ClearFlag(ADC1,ADC_SR_STRT);

ADC_SoftwareStartConv(ADC1);

}

上面的中断处理程序是重新开启AD和DMA的最少处理语句,缺一不可。

带Clear的语句是清除DMA全部完成中断标志,完成一半中断标志,AD的OVR异常标志和regular通道转换完成标志。这是必须的。

两个重新开启AD和DMA的命令也不多说。

由于DMA中的剩余个数在全部完成中断里面时已经为0,需要对它进行重新配置也可以理解。

其中让人不理解的就是 DMA1_Channel1->CCR &= (uint16_t)(~DMA_CCR1_EN);和没有重新设置DMA设置内存目的地址得语句。

芯片硬件又不是我们自己设计的,这么用,估且我们赞同这种现象。但通过这个现象我们能重新理解DMA的运行机制。

我总结如下:

DMA1_Channel1->CCR &= (uint16_t)(~DMA_CCR1_EN);表明:虽然,DMA进入中断以后,去除掉了中断标志,但这是DMA已经停止,但此时通过仿真可以查看到CCR寄存器的中最低位EN是1,虽然如此,但实际上DMA已经关闭,此时必须通过先复位EN位,就是上一行写的语句,再置位EN位,这种方式来重新开启DMA。

没有重新设置DMA设置内存目的地址得语句:表明:在DMA参考手册中有一句话在DMA运行时源地址和目的地址是不可以读取的,这个例子DMA在运行时是源地址不变,目的地址在不断加2个字节。但当DMA停止后目的地址又恢复到最初初始化给它的值,或者是在DMA运行时目的地址改变的是芯片内部一个我们看不到的地址。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: