OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4791|回复: 7

请问为什么开启DMA中断就死机?

[复制链接]

9

主题

55

帖子

0

精华

初级会员

Rank: 2

积分
182
金钱
182
注册时间
2018-3-28
在线时间
30 小时
发表于 2018-9-12 21:24:47 | 显示全部楼层 |阅读模式
1金钱
问题如题,一打开中断就死机,程序不知道跑到那里去了。我看了一下,并没有nvic的冲突,中断函数中就设置了一个标志位。
还有一点是本来我是打算采用T2 CC2启动ADC采样的,因为T2的PWM复用口被占用了,所以映射到PB3上了,后来没有试成功,这个也不明原因。后来不得已改为定时器中断采样了。

上述真是不明所以。请大神指点!感谢!


代码如下:

__IO u8 GET_DMA_FLAG=0;

__IO uint16_t ADC_ConvertedValue[ADC_BUFF_LEN];   //ADC的缓冲数组
// __IO uint8_t stat_u8ADBufferPointer = 0;                  //采样指针
//uint16_t WriteBuff[ADC_BUFF_LEN];            //ADC的写入缓冲数组


void ADC_Configuration(void)    //初始化ADC 外部定时器2触发启动转换  DMA传输
{
      ADC1_GPIO_Config();
      ADC1_DMA1_Init();
      ADC1_Mode_Config();
    //ADC1_ExternalTrig_T2_CC2_Init(1999,719);
}

void ADC1_GPIO_Config(void)   //ADC1 GPIO配置 PB1
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);  //使能ADC1 GPIOB引脚以及TIM2 PWM引脚时钟 这里复用映射到PB3上
       
                GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
    /* Configure TIM1_CH1 (PB3) as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* Configure PB.01 (ADC Channel9 ) as analog input */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}


void ADC1_Mode_Config(void)    //ADC1初始参数配置
{
    ADC_InitTypeDef ADC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);   //使能ADC1时钟
                RCC_ADCCLKConfig(RCC_PCLK2_Div6);  //配置ADC时钟,为PCLK2的6分频,即12MHz
    /* ADC1 configuration ------------------------------------------------------*/
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  //ADC工作在独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;     //关闭扫描模式 因为只有一个通道
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //关闭连续转换模式 因为只要触发一次
          ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //选择软件触发
    //ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //选择定时器 2 的捕获比较 2 作为转换外部触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC 数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);  //初始化配置
               
          
    ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_239Cycles5); //(239.5+12.5)*1/12=21us


               
    ADC_DMACmd(ADC1, ENABLE);//使能ADC DMA1
       
                ADC_Cmd(ADC1, ENABLE); //使能ADC1
               


    ADC_ResetCalibration(ADC1);//校准ADC1
    while(ADC_GetResetCalibrationStatus(ADC1));//等待准备完成

    ADC_StartCalibration(ADC1);//开始校准
    while(ADC_GetCalibrationStatus(ADC1));  //等待校准完成
               
               
          //ADC_ExternalTrigConvCmd(ADC1, ENABLE);//使能外部T1触发ADC1启动转换功能       
   //ADC_SoftwareStartConvCmd(ADC1, ENABLE); //连续转换开始,ADC通过DMA方式不断的更新RAM区。
       
       
}

void ADC1_DMA1_Init(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA1时钟

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;  //设置DMA1的中断优先级为最高,0 1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* DMA1 Channel1 Configuration ----------------------------------------------*/
       
    DMA_DeInit(DMA1_Channel1);  //将 DMA 的通道 1 寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //DMA 外设 ADC 基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue; //设置DMA1的传送地址 *ADC_ConvertedValue 数组首地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向外设到内存
    DMA_InitStructure.DMA_BufferSize = ADC_BUFF_LEN;  //DMA 通道的 DMA 缓存的大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度为 16 位,第16-31位是ADC2的规则转换数据 这里不需要
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为 16 位,对应于外设宽度
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在循环缓存模式,缓存满了之后再重新覆盖
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级  这里只设置了一路DMA
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//DMA 通道1没有设置为内存到内存传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化DMA1配置

    //DMA_ITConfig(DMA1_Channel1, DMA_IT_TC , ENABLE);//设置通道1传输完成中断屏蔽

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

void ADC1_ExternalTrig_T2_CC2_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
    TIM_OCInitTypeDef         TIM_OCInitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能通用定时器TIM2时钟

    /* Time Base configuration */
    //TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); //普通定时器缺省值
    TIM_TimeBaseStructure.TIM_Period = arr;       // 重载周期  
    TIM_TimeBaseStructure.TIM_Prescaler = psc;       //(1/72M)*72*1000=1ms
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;    //不分频
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    /* TIM2 channel2 configuration in PWM mode */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //TIM1 脉冲宽度调制模式 1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    //使能输出比较状态            
    TIM_OCInitStructure.TIM_Pulse = 1000; //它的取值必须在 0x0000 和 arr 之间。
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;      //TIM2 输出比较极性低   
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);

                //TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
    //TIM_CtrlPWMOutputs(TIM1, ENABLE);//使能PWM输出
   // TIM_Cmd(TIM2, DISABLE);//关闭定时器2
}

void ADC1_DMA1_IT_Hander(void)
{
    if(DMA_GetFlagStatus(DMA1_FLAG_TC1))
    {
        DMA_ClearITPendingBit(DMA1_FLAG_TC1);
                                GET_DMA_FLAG=1;
    }

}



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-12 22:21:37 | 显示全部楼层
死哪儿去都不知道这么奇怪? 看不到PC的值?
回复

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-9-13 10:43:29 | 显示全部楼层
你是用定时器触发ADC吧!之前弄过
你参考这帖子http://www.openedv.com/forum.php ... =277863&extra=:)
业精于勤荒于嬉;行成于思毁于随!
回复

使用道具 举报

9

主题

55

帖子

0

精华

初级会员

Rank: 2

积分
182
金钱
182
注册时间
2018-3-28
在线时间
30 小时
 楼主| 发表于 2018-9-20 16:14:45 | 显示全部楼层
1208 发表于 2018-9-13 10:43
你是用定时器触发ADC吧!之前弄过
你参考这帖子http://www.openedv.com/forum.php?mod=viewthread&tid=277 ...

是的  试了很长时间不行。 关键的是我不打算用定时器触发了,但是DMA不能开启接收中断,一开启就不知道死哪里去了。
回复

使用道具 举报

9

主题

55

帖子

0

精华

初级会员

Rank: 2

积分
182
金钱
182
注册时间
2018-3-28
在线时间
30 小时
 楼主| 发表于 2018-9-20 16:16:01 | 显示全部楼层
1208 发表于 2018-9-13 10:43
你是用定时器触发ADC吧!之前弄过
你参考这帖子http://www.openedv.com/forum.php?mod=viewthread&tid=277 ...

刚才忘了感谢您了!我回去试试,有问题再请教您。
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-20 18:52:43 | 显示全部楼层
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue;
把&删除
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-20 18:55:59 | 显示全部楼层
ADC_ConvertedValue是个数组, 它本身就是个指针, 你在指针前加个&, 那就不是指针指向数组的地址, 而是指针本身的地址
回复

使用道具 举报

9

主题

55

帖子

0

精华

初级会员

Rank: 2

积分
182
金钱
182
注册时间
2018-3-28
在线时间
30 小时
 楼主| 发表于 2018-9-23 11:22:04 | 显示全部楼层
edmund1234 发表于 2018-9-20 18:55
ADC_ConvertedValue是个数组, 它本身就是个指针, 你在指针前加个&, 那就不是指针指向数组的地址, 而是指 ...

删除了 还是不行。
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-19 22:28

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表