与非网的L先生 发表于 2018-1-5 17:14:35

STM32F303使用定时器触发双ADC常规同步采样模式

本帖最后由 与非网的L先生 于 2018-1-5 17:28 编辑

之前已经实现了使用软件触发的方式,实现基于DMA方式的双ADC常规同步采样,但是这种方式有个问题,基于DMA方式的双ADC常规同步采样在两次采样之间是不存在间隔的,如下图所示:
所以,当我需要调整采样率的时候,就只能去修改ADC时钟、采样周期数,每次调整后,都得重新初始化ADC,而且这样的采样率没法很自由调整。
所以我采样定时器去触发,每次只采样一次(所以不需要用到DMA?),那么通过设置定时器的时间间隔来设定采样率就很自由了,如下图所示:


我的代码如下:
void ADC_Config(void)
{
ADC_MultiModeTypeDef multimode;
ADC_ChannelConfTypeDef sConfig;
      
/*##-1- Configuration of ADCx peripheral (ADC master) ######################*/
AdcHandle_master.Instance = AdcMasterInstance;
      
AdcHandle_master.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
AdcHandle_master.Init.Resolution = ADC_RESOLUTION_12B;
AdcHandle_master.Init.DataAlign   = ADC_DATAALIGN_RIGHT;
AdcHandle_master.Init.ScanConvMode = ADC_SCAN_DISABLE;
AdcHandle_master.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
AdcHandle_master.Init.LowPowerAutoWait = DISABLE;
AdcHandle_master.Init.ContinuousConvMode = DISABLE;
      AdcHandle_master.Init.NbrOfConversion= 1;
AdcHandle_master.Init.DiscontinuousConvMode = DISABLE;
AdcHandle_master.Init.NbrOfDiscConversion = 1;
      AdcHandle_master.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;
AdcHandle_master.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
AdcHandle_master.Init.DMAContinuousRequests = DISABLE;
AdcHandle_master.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
      
if (HAL_ADC_Init(&AdcHandle_master) != HAL_OK)
{
    Error_Handler();
}
      
/*##-2- Configuration of ADCy peripheral (ADC slave) #######################*/
AdcHandle_slave.Instance = AdcSlaveInstance;
      
/* Configuration of ADCy init structure: ADC parameters and regular group */
/* Same configuration as ADCx */
AdcHandle_slave.Init = AdcHandle_master.Init;
      
if (HAL_ADC_Init(&AdcHandle_slave) != HAL_OK)
{
    Error_Handler();
}
      
/*##-3- Configuration of channel on ADCx regular group on rank 1 ###########*/
sConfig.Channel               = AdcMasterChannel;
sConfig.Rank                     = ADC_REGULAR_RANK_1;
sConfig.SingleDiff            = ADC_DIFFERENTIAL_ENDED;
sConfig.SamplingTime      = ADC_SAMPLETIME_7CYCLES_5;
sConfig.OffsetNumber      = ADC_OFFSET_NONE;
sConfig.Offset                   = 0;
if (HAL_ADC_ConfigChannel(&AdcHandle_master, &sConfig) != HAL_OK)
{
    Error_Handler();
}
      
/*##-4- Configuration of channel on ADCy regular group on rank 1 ###########*/
sConfig.Channel = AdcSlaveChannel;

if (HAL_ADC_ConfigChannel(&AdcHandle_slave, &sConfig) != HAL_OK)
{
    Error_Handler();
}
      
/*##-5- Configuration of multimode #########################################*/
/* Multimode parameters settings and set ADCy (slave) under control of*/
/* ADCx (master).*/
multimode.Mode                           = ADC_DUALMODE_REGSIMULT;
multimode.DMAAccessMode         = ADC_DMAACCESSMODE_12_10_BITS;
multimode.TwoSamplingDelay      = ADC_TWOSAMPLINGDELAY_5CYCLES;
if (HAL_ADCEx_MultiModeConfigChannel(&AdcHandle_master, &multimode) != HAL_OK)
{
    Error_Handler();
}
      
/* Run the ADC calibration in differential-ended mode */
if (HAL_ADCEx_Calibration_Start(&AdcHandle_master, ADC_DIFFERENTIAL_ENDED) != HAL_OK)
{
    Error_Handler();
}
if (HAL_ADCEx_Calibration_Start(&AdcHandle_slave, ADC_DIFFERENTIAL_ENDED) != HAL_OK)
{
    Error_Handler();
}

}void ADC_Timer_Init(uint32_t uPrescaler,uint32_t uPeriod)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;

hadc_Timer.Instance                            = ADC_TIMn;
hadc_Timer.Init.Prescaler                     = uPrescaler-1;
hadc_Timer.Init.CounterMode               = TIM_COUNTERMODE_UP;      //向上计数模式
hadc_Timer.Init.Period                         = uPeriod;
hadc_Timer.Init.ClockDivision               = TIM_CLOCKDIVISION_DIV1;      //系统时钟不分频72MHz
hadc_Timer.Init.RepetitionCounter      = 0x00;      //发生0+1次updata事件产生中断
hadc_Timer.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&hadc_Timer) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&hadc_Timer, &sClockSourceConfig) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}
      
      /* Timer TRGO selection */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;      //选择update事件更新为触发源
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&hadc_Timer, &sMasterConfig) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}
}ADC每次装换完成后做处理,判断是否采样了1024个点:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
      if(Sample_Finish == 0)
      {
                aADCDualConvertedValue = HAL_ADC_GetValue(hadc);
                Sample_Index++;
      }
      if(Sample_Index>=1024)      //判断完成1024次采样
      {
                Sample_Index = 0;
                HAL_TIM_Base_Stop_IT(&hadc_Timer);
                Sample_Finish = 1;
      }
}main函数中调用下面这个用户函数:
void DualRegularADCtest(uint8_t uRange)
{
      Sample_Index = 0;
      Sample_Finish = 0;
      switch(uRange)
      {
                case 0:
                        ADC_Timer_Init(2,36);
                        break;
                case 1:
                        ADC_Timer_Init(2,35);
                        break;
                case 2:
                        ADC_Timer_Init(3,73);
                        break;
                case 3:
                        ADC_Timer_Init(6,73);
                        break;
                default:
                        ADC_Timer_Init(2,36);
                        break;
      }
      
      // 使能ADC,开启定时器,触发双ADC采样
if (HAL_ADC_Start(&AdcHandle_master) != HAL_OK)//STM例程中给的是使用HAL_ADC_Start_IT函数,试了不行
{
    Error_Handler();
}我使用的是定时器3去触发,ADC3通道1和ADC4的通道8.
上面的代码在调试的时候,发现一直停在的了:
while(Sample_Finish!=1);能进入定时器3中断里面,而且确定是Update事件触发了,但是Watch窗口观测到Sample_Index 和 Sample_Finish 的值一直为零,这意味着ADC无法采样,之前软件触发基于DMA方式的双ADC采样还是可以,改成定时器触发就不行,也调试了很久,不知道有没有大神能帮我看看原因?
STM32给的例程是定时器触发基于DMA方式的单ADC多通道采样,我想实现定时器触发的双ADC同步采样(不需要用到DMA),有没有人实现过这种方式采样的?

与非网的L先生 发表于 2018-1-5 17:16:33

本帖最后由 与非网的L先生 于 2018-1-5 17:31 编辑

不知道为啥 这个代码拷贝进来会出现不对齐和缩进异常问题,刚刚手动调了半天,凑合着看吧...Orz

与非网的L先生 发表于 2018-1-8 09:11:15

没有人回么...:dizzy:
因为直接用定时器触发的方式不知道为何一直不进采样中断,所以换种方式,直接在定时器中断中启用采样,一步一步调试:
1、软件触发DMA方式的双ADC常规同步采样(一次1024个点)。    OK
2、软件触发DMA方式的双ADC常规同步采样(一次1个点,循环1024次)。   OK
3、定时器中启用采样(即在定时器中断中调用HAL_ADCEx_MultiModeStart_DMA函数去启用采样)。   NG
第三步遇到一个问题,在定时器中调用下面语句:
HAL_ADCEx_MultiModeStart_DMA(&AdcHandle_master, (uint32_t *)(aADCDualConvertedValue+Sample_Index), 1);
Sample_Index++;
传给DMA的目标地址按道理是每次自增的,但是实际结果却每次都填充到aADCDualConvertedValue,其余值一直为零,但是观测Sample_Index的确是自增了的。
而且这数组和变量的声明应该也没错:
__IO        uint16_t Sample_Index;
__IOuint32_t aADCDualConvertedValue;
而且这种方式在第二步调试的时候是成功的,目前还在调试中。。。

wenyangzeng 发表于 2018-2-6 10:02:07


Sample_Index不用判断2次试看看:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
      if(Sample_Index==1024)      //判断完成1024次采样
      {
                Sample_Index = 0;
                HAL_TIM_Base_Stop_IT(&hadc_Timer);
                Sample_Finish = 1;
      }
       else
      {
                aADCDualConvertedValue = HAL_ADC_GetValue(hadc);

      }

}

feixiang20 发表于 2018-2-6 10:14:27

开始设置没错的话,检查下传送设置是不是对呢,感觉你在循环语句上可能有点问题,先精简几句,看看循环是不是正确,当循环出现问题的时候,确实会有异常

七哥 发表于 2018-2-6 15:17:33

本帖最后由 toofree 于 2018-2-6 15:39 编辑

对一个疑问已验证,故回复删除


无薪税绵 发表于 2018-2-6 17:09:02

找了两个例子,希望对你有用:

http://blog.csdn.net/xuezhimeng2010/article/details/15157911

http://www.cnblogs.com/longbiao831/p/6688006.html

斜阳 发表于 2018-2-6 19:36:36

加volatile修饰语试试

dmspe 发表于 2021-1-14 14:15:51

楼主,使用软件触发的基于DMA方式的双ADC常规同步的配置代码能否发出来看看
页: [1]
查看完整版本: STM32F303使用定时器触发双ADC常规同步采样模式