野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1416|回复: 2

STM32H743 PWM+ADC+DMA,同时对中断函数有点疑问

[复制链接]
发表于 2019-5-29 11:56:32 | 显示全部楼层 |阅读模式
代码部分如下:采用了双重ADC模式。
ADC_HandleTypeDef ADC1_Handle,ADC2_Handle;
DMA_HandleTypeDef hdma_adc;
ADC_MultiModeTypeDef ADC_multimode;
__attribute__ ((at(0x30000000))) __IO uint32_t ADC_ConvertedValue=0;
__IO uint16_t ADC_ConvertedValueLocal[2];

一、//ADC引脚配置
static void ADC_GPIO_Mode_Config(void)
{
  
    GPIO_InitTypeDef  GPIO_InitStruct;
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;  

   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;

    /* 配置为模拟输入,不需要上拉电阻 */
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}


二、//时钟+DMA配置
static void ADC_Mode_Config(void)
{
    ADC_ChannelConfTypeDef ADC_Config;

    RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;  
    /*            配置ADC3时钟源             */
    /*    HSE Frequency(Hz)    = 25000000   */                                             

    RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    RCC_PeriphClkInit.PLL2.PLL2FRACN = 0;
    RCC_PeriphClkInit.PLL2.PLL2M = 5;
    RCC_PeriphClkInit.PLL2.PLL2N = 160;
    RCC_PeriphClkInit.PLL2.PLL2P = 25;
    RCC_PeriphClkInit.PLL2.PLL2Q = 2;
    RCC_PeriphClkInit.PLL2.PLL2R = 2;
    RCC_PeriphClkInit.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_2;
    RCC_PeriphClkInit.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
    RCC_PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
   HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);  

    /* 使能ADC1、2时钟 */
    __HAL_RCC_ADC12_CLK_ENABLE();
               
   //使能DMA时钟
   __HAL_RCC_DMA1_CLK_ENABLE();
         
         //指向DMA数据流基地址的指针,指定用数据流1
    hdma_adc.Instance = DMA1_Stream1;

     //DMA请求选择
    hdma_adc.Init.Request = DMA_REQUEST_ADC1;

   //传输方向,外设至存储器
    hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;

   //如果配置为PeriphInc_Enable,使能外设地址自动递增。ADC1数据寄存器地址固定,无需递增使能
    hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;

   //如果配置为MemInc_Enable,使能存储器地址自动递增功能
    hdma_adc.Init.MemInc = DMA_MINC_DISABLE;

     //外设数据宽度,可选字节(8位)、半字(16位)、字(32位)
   //双重模式时,ADC 的通用规则数据寄存器是32 位有效
    hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;

   //存储器字节宽度,可选字节(8位)、半字(16位)、字(32位)
    hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

   //DMA传输模式选择,可选一次传输或者循环传输
    hdma_adc.Init.Mode = DMA_CIRCULAR;

        //软件设置数据流的优先级
    hdma_adc.Init.Priority = DMA_PRIORITY_LOW;

        //FIFO 模式使能
    hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
               
    HAL_DMA_Init(&hdma_adc);
               
    HAL_DMA_Init(&hdma_adc);
                        
   //hdma_adc和ADC_Handle.DMA_Handle链接
    __HAL_LINKDMA(&ADC1_Handle,DMA_Handle,hdma_adc);
               
               
    ADC1_Handle.Instance = ADC1;
    HAL_ADC_DeInit(&ADC1_Handle);
        
    //使能Boost模式
    ADC1_Handle.Init.BoostMode = ENABLE;

    //ADC时钟1分频
    ADC1_Handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
               
    //关闭连续转换模式
    ADC1_Handle.Init.ContinuousConvMode = DISABLE;
               
   //扫描1个通道        
   ADC1_Handle.Init.NbrOfConversion = 1;

    //数据存放在数据寄存器中
    ADC1_Handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;

    //关闭不连续转换模式
    ADC1_Handle.Init.DiscontinuousConvMode = DISABLE;
    ADC1_Handle.Init.NbrOfDiscConversion = 0;

   //使能EOC标志位
    ADC1_Handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
        
    //T4定时器TRGO事件触发
   ADC1_Handle.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T4_TRGO;
   ADC1_Handle.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_RISING;
               
    //关闭低功耗自动等待
    ADC1_Handle.Init.LowPowerAutoWait = DISABLE;

    //数据溢出时,覆盖写入
    ADC1_Handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

    //不使能过采样模式
    ADC1_Handle.Init.OversamplingMode = DISABLE;

    //分辨率为:16bit
    ADC1_Handle.Init.Resolution = ADC_RESOLUTION_12B;

    //不使能多通道扫描
    ADC1_Handle.Init.ScanConvMode = DISABLE;
               
   //扫描0个通道
    ADC1_Handle.Init.NbrOfConversion = 0;

    //初始化 主ADC1
    HAL_ADC_Init(&ADC1_Handle) ;
               
               
    HAL_ADCEx_Calibration_Start(&ADC1_Handle,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);
               
  //初始化 从ADC2
   ADC2_Handle.Instance = ADC2;
   HAL_ADC_DeInit(&ADC2_Handle);
               
   ADC2_Handle.Init = ADC1_Handle.Init;
               
    HAL_ADC_Init(&ADC2_Handle);
        
    iHAL_ADCEx_Calibration_Start(&ADC2_Handle,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);
               
    //使用通道7
    ADC_Config.Channel = ADC_CHANNEL_7;

    //转换顺序为1
    ADC_Config.Rank = ADC_REGULAR_RANK_1 ;

    //采样周期
    ADC_Config.SamplingTime = ADC_SAMPLETIME_16CYCLES_5;

    //不使用差分输入的功能
    ADC_Config.SingleDiff = ADC_SINGLE_ENDED ;
    ADC_Config.OffsetNumber = ADC_OFFSET_NONE;            
    ADC_Config.Offset = 0;  

    //配置ADC1通道
    HAL_ADC_ConfigChannel(&ADC1_Handle, &ADC_Config);

    // 使用通道3
    ADC_Config.Channel = ADC_CHANNEL_3;

   // 转换顺序为2
    ADC_Config.Rank = ADC_REGULAR_RANK_1;

    //配置ADC2通道
    HAL_ADC_ConfigChannel(&ADC2_Handle, &ADC_Config);

   //使能ADC1、2
    ADC_Enable(&ADC1_Handle);

   ADC_Enable(&ADC2_Handle);
               
    //数据格式
    ADC_multimode.DualModeData = ADC_DUALMODEDATAFORMAT_32_10_BITS;

    //双重ADC交替模式
               
    ADC_multimode.Mode = ADC_DUALMODE_INTERL;
               
   //主ADC和从ADC采样间隔3个ADC时钟
    ADC_multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_3CYCLES;
               
   //ADC双重模式配置初始化
   //控制是否使能ADC的DMA请求
    HAL_ADCEx_MultiModeConfigChannel(&ADC1_Handle, &ADC_multimode);
               
    //使能DMA
   HAL_ADCEx_MultiModeStart_DMA(&ADC1_Handle, (uint32_t*)&ADC_ConvertedValue, 1);
}



三、//DMA中断配置
static void DMA_NVIC_Config(void)
{
    HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}

四、//DMA中断服务函数
void DMA1_Stream1_IRQHandler(void)
{
    HAL_DMA_IRQHandler(ADC1_Handle.DMA_Handle);
}



五、//PWM触发源配置
void TIM4_PWM_Init(void)
{
  TIM_MasterConfigTypeDef master_timer_config;


  TIM4_Handler.Instance = TIM4;//定时器4
  TIM4_Handler.Init.Period            = 50-1;//自动重装载值
  TIM4_Handler.Init.Prescaler         = 4-1;//定时器分频
  TIM4_Handler.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
  TIM4_Handler.Init.CounterMode       = TIM_COUNTERMODE_UP;
  TIM4_Handler.Init.RepetitionCounter = 0x0;

  HAL_TIM_Base_Init(&TIM4_Handler);

  /* Timer TRGO selection */
  master_timer_config.MasterOutputTrigger = TIM_TRGO_UPDATE;
  master_timer_config.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  master_timer_config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

  HAL_TIMEx_MasterConfigSynchronization(&TIM4_Handler, &master_timer_config);


  HAL_TIM_Base_Start(&TIM4_Handler); //使能定时器4和定时器4更新中断:TIM_IT_UPDATE   
}



六、//最终初始化
void ADC_Init(void)
{

    ADC_GPIO_Mode_Config();

    ADC_Mode_Config();
    DMA_NVIC_Config();

    HAL_ADC_Start(&ADC1_Handle);
    HAL_ADC_Start(&ADC2_Handle);
}


七、//ADC回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
       /* 获取结果 */

        ADC_ConvertedValue=HAL_ADCEx_MultiModeGetValue(AdcHandle);

        
        ADC_ConvertedValueLocal[0] = (uint16_t)ADC_ConvertedValue;
        ADC_ConvertedValueLocal[1] = (uint16_t)((ADC_ConvertedValue&0xFFFF0000)>>16);
        TEST_PIN_Toggle;
        //需要增加的中断处理函数
}


现在的问题是,在第七段中,我不添加那段需要中断处理的函数,用示波器观察TSET_PIN的翻转,是500KHz;
但是我添加了中断处理函数(测量过这段函数执行大约820ns),TSET_PIN的翻转频率就变成了300KHz多一点。
即使我把这段中断处理函数缩减到400ns,TEST_PIN的翻转频率也只提高到425KHz。
想知道问题出在哪里?怎么解决?

回复

使用道具 举报

发表于 2019-5-29 17:28:56 | 显示全部楼层
有沒有可能是中斷優先順序的關係, 把DAC的中斷優先拉高試試.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-5-29 20:16:37 | 显示全部楼层
twqqq168 发表于 2019-5-29 17:28
有沒有可能是中斷優先順序的關係, 把DAC的中斷優先拉高試試.

ADC+DMA只需开启DMA中断就行了吧?DMA中断已经是优先级最高的了,看波形也没有被别的中断打断的现象,周期很稳定。猜测会不会是中断进出栈需要几百ns,不太清楚这方面的东西。1uS进一次中断可能太极端了吧,降低要求改成了2uS,一切正常
回复 支持 反对

使用道具 举报

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

本版积分规则

联系站长|手机版|站点地图|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号-2 ) 大学生ARM嵌入式2群

GMT+8, 2020-9-21 19:49 , Processed in 0.248668 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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