16327|8

23

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

有关STM32使用ADC的DMA中断问题 [复制链接]

本人需要调试一个AD功能,就是用单通道连续采样4次AD口(PA0)的数据存入DMA中后,产生一次DMA中断。设计思路是:
1)需要采样时利用软件触发AD的方式,将单通道连续采样的数据通过DMA存到对应数组;
2)在DMA中断里关闭AD,直到下一次需要采样时再打开AD。


但实际调试的时后发现,如果 DMA_InitStructure.DMA_Mode 设置成DMA_Mode_Circular,中断会不停产生。但是如果DMA_MODE设置成DMA_Mode_Normal以后,产生一次中断以后就不再产生中断了。请大家帮我看看是什么原因,代码是在stm32自带ADC1_DMA中的例程基础上增加中断控制处理。


ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;   
       
__IO uint16_t ADCConvertedValue[4];

// 配置PA0口为AD口
void ADC1_GPIO_Config(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;  /* Enable ADC1 and GPIOA clock */
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA,ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;  
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}


void ADC1_Mode_Config(void)
{
  /* DMA1 channel1 configuration ----------------------------------------------*/
  DMA_DeInit(DMA1_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;        // (uint32_t)&ADCConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 4;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;        //DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;        // DMA_Mode_Normal
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);

  /* Enable DMA1 channel1 */
  DMA_Cmd(DMA1_Channel1, ENABLE);

  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel14 configuration */
  //ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));

  /* Start ADC1 Software Conversion */
  //ADC_SoftwareStartConvCmd(ADC1, ENABLE);
       
       
                        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
                        NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel1_IRQn;
                        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
                        NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
                        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
                        NVIC_Init(&NVIC_InitStructure);

                        DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //??DMA??????
}



stm32f10x_it.c里的DMA中断处理:

void DMA1_Channel1_IRQHandler(void)
{
        if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
        {
                //filter();//ADC????
                ADC_SoftwareStartConvCmd(ADC1, DISABLE);
                DMA_ClearITPendingBit(DMA1_IT_TC1);
        }
}


程序里启动ADC和DMA时同时调用了以下函数:
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);








此帖出自stm32/stm8论坛

最新回复

基本要对所有的外设,都有相似或者相同的写法。所以一眼就能看出你的问题啦。  详情 回复 发表于 2016-7-5 09:05
点赞 关注(1)
 

回复
举报

31

帖子

0

TA的资源

一粒金砂(中级)

沙发
 
用单次,然后用一个全局计数器,4次后再清零试试看
此帖出自stm32/stm8论坛

点评

这种方法也可以,但是我要弄明白是哪里设置错了,并不要避开这个问题。  详情 回复 发表于 2016-7-1 10:31
 
 

回复

31

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
还有种办法,设立一个长的缓冲区,比如1024,然后4次一下分别读取值

nettlhx 2016/7/1 10:27:04
这种方法可以用CIRCULAR
此帖出自stm32/stm8论坛
 
 

回复

23

帖子

0

TA的资源

一粒金砂(中级)

4
 
netlhx 发表于 2016-7-1 10:23
用单次,然后用一个全局计数器,4次后再清零试试看

这种方法也可以,但是我要弄明白是哪里设置错了,并不要避开这个问题。
此帖出自stm32/stm8论坛
 
 
 

回复

23

帖子

0

TA的资源

一粒金砂(中级)

5
 
找到问题了,在DMA传输完4次数据以后,如果需要重新采样到DMA,需要对DMA_CNDTRx重新赋值。查了一下手册对于这个寄存器的相关操作: “这个寄存器只能在通道不工作(DMA_CCRx的EN=0)时写入。”,于是翻查了一下函数库里的相关函数,在重新启动AD前调用下面的函数就可以了。
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1, 4);
DMA_Cmd(DMA1_Channel1, ENABLE);


测试了一下,DMA设置成DMA_Mode_Normal模式工作正常,可以防止数据覆盖。

此帖出自stm32/stm8论坛
 
 
 

回复

4008

帖子

0

TA的资源

版主

6
 
连续AD转换,连续dma,当dam传输完一半时处理数据。
此帖出自stm32/stm8论坛
 
 
 

回复

4177

帖子

9

TA的资源

五彩晶圆(高级)

7
 
好像没有看到使能DMA的时钟总线哦,要看看DMA挂在哪个总线下面哦。。。。。
此帖出自stm32/stm8论坛

点评

看得真仔细!是的,上面代码忘记写了,后面软件调试时也查到了这个问题,已纠正  详情 回复 发表于 2016-7-5 08:22
 
 
 

回复

23

帖子

0

TA的资源

一粒金砂(中级)

8
 
huaiqiao 发表于 2016-7-1 23:27
好像没有看到使能DMA的时钟总线哦,要看看DMA挂在哪个总线下面哦。。。。。

看得真仔细!是的,上面代码忘记写了,后面软件调试时也查到了这个问题,已纠正
此帖出自stm32/stm8论坛

点评

基本要对所有的外设,都有相似或者相同的写法。所以一眼就能看出你的问题啦。  详情 回复 发表于 2016-7-5 09:05
 
 
 

回复

4177

帖子

9

TA的资源

五彩晶圆(高级)

9
 
SoftwareX 发表于 2016-7-5 08:22
看得真仔细!是的,上面代码忘记写了,后面软件调试时也查到了这个问题,已纠正

基本要对所有的外设,都有相似或者相同的写法。所以一眼就能看出你的问题啦。
此帖出自stm32/stm8论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表