STM32
直播中

刘桂兰

8年用户 1047经验值
私信 关注
[问答]

STM32F405RGT6 ADC2+TIM4触发+DMA(DMA2_Stream2_CH1)+DMA中断会死机,怎么解决?

ADC1+tiM4触发+DMA(DMA2_Stream0_CH0)+DMA中断完全正常更改为ADC2+TIM4触发+DMA(DMA2_Stream2_CH1)+DMA中断会死机(取消中断后完全正常)更改为ADC3+TIM4触发+DMA(DMA2_Stream1_CH2)+DMA中断会死机(取消中断后完全正常)
void ADC2_EXIT_TIM4_CC4_Trig_DMAConfiguration(unsigned short F_Prescaler,unsigned int F_ARR )//ADC_TIM4_CC4外部触发转换{
GPIO_InitTypeDef  GPIO_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;ADC_InitTypeDef       ADC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); //使能ADC2时钟//RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOC时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
// Configure PA5 PA4  PC2(ADC Channel 5-0-1-13) as analog input -------------------------GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//GPIO模式为ADC模拟输入模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 ;//选择PA5 PA4 为输入通道GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//端口速度50MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉GPIO_Init(GPIOA, &GPIO_InitStructure);
// ADC2 configuration -----------------------------------------------------// ADCs DeInit RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC2,ENABLE);   //ADC2复位RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC2,DISABLE);    //复位结束RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); //使能ADC2时钟
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;;//连续转换模式 使用(连续模式)ADC_InitStructure.ADC_ScanConvMode = DISABLE;;//扫面模式 使用(扫描)ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling;//禁止触发检测,使用软件触发ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4;//外部触发源 外部引脚 (已经禁止触发检测了)ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐ADC_InitStructure.ADC_NbrOfConversion = 1;//指定规则组转换的通道 5个通道ADC_Init(ADC2, &ADC_InitStructure);//ADC初始化
ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 1,  ADC_SampleTime_3Cycles);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA使能模式ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36MhzADC_CommonInit(&ADC_CommonInitStructure);//初始化
ADC_DMARequestAfterLastTransferCmd(ADC2,ENABLE);    //单通道使用//ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);ADC_DMACmd(ADC2,ENABLE);//使能ADC的DMA数据传送功能
ADC_Cmd(ADC2, ENABLE);//使能ADC2//  DMA2_Stream2_CH0[i]ADC configuration ----------------------------------------------DMA2_Stream2_CH1_ADC2_Config((uint32_t *)OSC_ADC_ConvertedValue,232,DMA_Mode_Circular);// DMA2_Stream2_CH1_ADC2_Config ADC DMANVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断优先级分组方式,整个程序只配置一次,可以放置在程序最开始
NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;//DMA2_Stream2中断占用通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//配置中断抢占优先级值,分组2的值为0-3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置中断响应优先级的值  分组2的值为0-3NVIC_Init(&NVIC_InitStructure);
DMA_Cmd(DMA2_Stream2, ENABLE);//打开DMA2 Stream0(或者使能)/[i] Enable DMA Channelx complete transfer interrupt ///  DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TC); //清除中断标志//  DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);
// Start ADC2 Software Conversion
ADC_SoftwareStartConv(ADC2);        //使能指定的ADC2的软件转换启动功能
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置定时器计时参数TIM_OCInitTypeDef TIM_OCInitStructure;//设置结构体
//开启TIM4时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);        
//选择TIM4的时钟模式为内部模式,时钟源为内部时钟(42*2=84MHZ)TIM_InternalClockConfig(TIM4);                              
//初始化上述结构体TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure);
//配置预分频系数为8400TIM_TimeBaseInitStructure.TIM_Prescaler = F_Prescaler;
//配置自动重装值为10000TIM_TimeBaseInitStructure.TIM_Period = F_ARR;
//配置计数模式为向上计数TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//配置定时器时钟频率与数字滤波器所使用的采样时钟之间的分频比TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //配置重复计数器的值为0TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
//初始化时基单元TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);                                 
TIM_OCStructInit(&TIM_OCInitStructure);//给结构体设置默认初始值////配置TIM4 通道1占空比TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式 PWM1模式TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性,默认输出高电平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能输出比较TIM_OCInitStructure.TIM_Pulse = 10;     //设置CCR数值 输出比较直0-FFFF(占空比-CCR/ARR)TIM_OC4Init(TIM4, &TIM_OCInitStructure);//初始化TIM4输出通道OC4
//选择更新事件作为触发输出TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_OC4Ref);
//开启TIM4,此时计数器开始工作TIM_Cmd(TIM4, ENABLE);
}
void DMA2_Stream2_IRQHandler(void) //DMA2_Stream2_IRQn{if(DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_TCIF1))      //清除传输完成中断{DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF1); // 清除传输完成标志DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_TCIF1);OSC_ADC_FLAG=1;TIM_Cmd(TIM4, DISABLE);}
if( DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_HTIF1))       //清除半传输完成中断
{DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_HTIF1);
}
// Clear the Streamx direct mode error flag if( DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_DMEIF1))       //清除传输错误中断
{DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_DMEIF1);
}
if( DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_FEIF1))       //清除Streamx FIFO error flag
{DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_FEIF1);
}
}
以上换成ADC1+TIM4+DMA+DMA中断工作完全正常 不清楚是什么原因

回帖(1)

王萍

2025-8-6 17:48:18

根据您的描述,ADC1配置正常工作而ADC2/ADC3在启用中断时死机,问题可能出在DMA中断配置或资源冲突。以下是解决方案:


关键问题原因



  1. ADC2/ADC3 DMA中断向量未正确配置

  2. DMA中断标志未正确处理

  3. ADC/DMA时钟使能不完整

  4. 中断优先级冲突


修复步骤


1. 修正中断向量配置


// 在NVIC配置中添加以下代码(确保使用正确的中断通道)
void ADC2_DMA_IRQ_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    // ADC2使用DMA2 Stream2(通道1对应ADC2)
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn; // 正确的中断向量
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

2. 完善中断服务程序


// 添加DMA2 Stream2中断处理函数
void DMA2_Stream2_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2)) // 检查传输完成标志
    {
        // 你的数据处理代码

        // 必须清除中断标志!
        DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2 | DMA_IT_TEIF2 | DMA_IT_DMEIF2);
    }
}

3. 补充时钟使能


在初始化函数开头添加:


// 确保所有外设时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOx, ENABLE); // GPIOx替换为实际端口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);

4. 修正DMA初始化配置


在您的配置函数中添加:


// 启用DMA中断(在DMA初始化结构中)
DMA_InitStructure.DMA_ITConfig = DMA_IT_TC | DMA_IT_TE; // 使能传输完成和错误中断

完整配置代码修改


void ADC2_EXIT_TIM4_CC4_Trig_DMAConfiguration(unsigned short F_Prescaler, unsigned int F_ARR)
{
    // 1. 确保时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);

    // ... [保留现有GPIO/TIM/ADC配置] ...

    // 2. 完善DMA配置
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA2_Stream2);
    DMA_InitStructure.DMA_Channel = DMA_Channel_1;  // ADC2对应通道1
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC2->DR);
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)YourBufferAddress;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = YourBufferSize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_ITConfig = DMA_IT_TC | DMA_IT_TE;  // 关键!启用中断
    DMA_Init(DMA2_Stream2, &DMA_InitStructure);

    // 3. 配置DMA中断
    ADC2_DMA_IRQ_Configuration();  // 调用前面定义的NVIC配置

    // 4. 启动DMA和ADC
    DMA_Cmd(DMA2_Stream2, ENABLE);
    ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
    ADC_DMACmd(ADC2, ENABLE);

    // ... [TIM4配置保持不变] ...
}

调试建议



  1. 检查向量表:确认启动文件中包含DMA2_Stream2_IRQHandler

  2. 优先级管理:降低中断优先级测试(设置PreemptionPriority=15)

  3. 错误中断处理:在ISR中添加错误检测
    if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TEIF2)) {
      // 处理传输错误
      DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TEIF2);
    }

  4. 资源冲突检查:使用STM32CubeMX确认:

    • DMA2 Stream2是否仅用于ADC2

    • 相同中断通道无其他使用者



补充说明



  • ADC3配置:将以上代码中的ADC2改为ADC3,DMA通道改为2,使用DMA2_Stream1_IRQn

  • 死机本质:通常是未处理的中断导致持续进入中断服务程序(中断风暴)

  • 库版本差异:标准库和HAL库中断处理机制不同,确保全工程统一


通过以上修改应该能解决ADC2/ADC3的DMA中断死机问题。重点检查中断向量配置和标志清除操作,这是ADC1正常工作而ADC2/ADC3失败的关键差异点。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分