cancel
Showing results for 
Search instead for 
Did you mean: 

The ADC1 & ADC2 is configured in multimode with DMA and trigged by TIM1, but I only get half sample rate 20 kHz. What I have done wrong? Q2 I can only use TIM1 Trigger 2 Out Event to trig the ADCs. Why can I not use any other timers or events?

AJack
Associate II
static void MX_ADC1_Init(void)
{
 
  ADC_MultiModeTypeDef multimode;
  ADC_ChannelConfTypeDef sConfig;
 
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
    */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_TRGO2;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 2;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure the ADC multi-mode 
    */
  multimode.Mode = ADC_DUALMODE_REGSIMULT;
  multimode.DMAAccessMode = ADC_DMAACCESSMODE_2;
  multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
    */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
    */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}
/* TIM1 init function */
static void MX_TIM1_Init(void)
{
 
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
 
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 1;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}
/* TIM4 init function */
static void MX_TIM4_Init(void)
{
 
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
 
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 0;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 2499;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}
static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
 
}
int main(void)
{
  // Enable I-Cache &  D-Cache
  SCB_EnableICache();
  SCB_EnableDCache();
 
 
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_TIM4_Init();
  MX_TIM1_Init();
  MX_ADC2_Init();
 
  if(HAL_TIM_Base_Start_IT(&htim4) != HAL_OK)
  {
      // Error
      while(1);
  }
 
  while (1)
  {
     HAL_Delay(1);
  }
 }
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
        HAL_ADCEx_MultiModeStop_DMA(&hadc1);
        HAL_ADC_Stop(&hadc2);
      
       HAL_GPIO_TogglePin(PK2_LED_GPIO_Port, PK2_LED_Pin);
 
    if(m_res_cnt < 1000)
    {
        //m_res_adc_buf[m_res_cnt++] = HAL_ADC_GetValue(hadc);
        m_res1_adc_buf[m_res_cnt] = m_adc_buf[0];
        m_res2_adc_buf[m_res_cnt] = m_adc_buf[1];
        m_res3_adc_buf[m_res_cnt] = m_adc_buf[2];
        m_res4_adc_buf[m_res_cnt++] = m_adc_buf[3];
    }
    else
    {
        m_res_cnt = 0;
    }
}
void TIM4_IRQHandler(void)
{
 
  HAL_TIM_IRQHandler(&htim4);
 
 
      HAL_ADC_Start(&hadc2);
      HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&m_adc_buf, 4);
      HAL_GPIO_TogglePin(PK0_LED_GPIO_Port, PK0_LED_Pin);
 
      HAL_TIM_Base_Start_IT(&htim1);
 
}
void TIM1_UP_TIM10_IRQHandler(void)
{
  HAL_GPIO_TogglePin(PK1_LED_GPIO_Port, PK1_LED_Pin);
  HAL_TIM_Base_Stop_IT(&htim1);
 
  HAL_TIM_IRQHandler(&htim1);
}
I start TIM1 in 
void TIM4_IRQHandler(void)
{
   ...
    HAL_TIM_Base_Start_IT(&htim1);
   ...
}
 
and stop TIM1 in 
void TIM1_UP_TIM10_IRQHandler(void)
{
  ...
   HAL_TIM_Base_Stop_IT(&htim1);
  ...
}
 
I start the ADC DMA in 
void TIM4_IRQHandler(void)
{
   ...
     HAL_ADC_Start(&hadc2);
     HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&m_adc_buf, 4);
   ...
}
 
and stop ADC DMA in
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  ...      
  HAL_ADCEx_MultiModeStop_DMA(&hadc1);
  HAL_ADC_Stop(&hadc2); 
   …
}

I'm using STM32F746, and the configuring is done with the HAL-library.

In the code below there is a 40 kHz TIM4 interrupt.

The ADC1 & ADC2 is configured in multimode which is triggered by TIM1.

I also use DMA for the ADC data transfer

Each ADC samples 2 channels (ADC1: IN3, IN4), (ADC2: IN5, IN6). 

TIM1 is invoked in TIM4 interrupt handler and stopped in TIM1 interrupt handler.

The 4 data from ADC1 & ADC2 are accessible in HAL_ADC_ConvCpltCallback()

The problem is that the ADCs only samples data with 20 kHz instead of 40 kHz.

I have try several different setting but I cannot increase the ADC sampling rate.

Can someone point out what I have done wrong?

As you can see I have enabled Scan Conversion Mode but disabled Continuous Conversion Mode

As I understand it, (when I read the STM32F746 user manual), it should be enough with one TIM1 trigger to the ADC, since the ADCs should the be responsible to sample all channels automatically and the invoke HAL_ADC_ConvCpltCallback() (when End of Conversion Selection = ECO flag at the end of all conversations).

I saw somewhere that someone suggested to activate the Continuous Conversion Mode to get all channels sampled when a timer is triggs the ADCs but I cannot find anything which confirms this in the STM32F746 user manual.

I have another problem too and that is that the only trigger event that is possible to use to trig the ADCs is timer 1 Trigger 2 Out Event. Why can I not use any other timer or events?

I have tried to trig the ADCs with timer 4. The settings I have tried are:

 TIM4                                        ADC1

  - TRGO update event              -> Timer 2 Trigger Out Event

  - Output Compare (OC1REF) -> Capture Compare 1 event

  - Output Compare (OC2REF) -> Capture Compare 2 event

  - Output Compare (OC3REF) -> Capture Compare 3 event

  - Output Compare (OC4REF) -> Capture Compare 4 event

Nothing above are working.

8 REPLIES 8
AJack
Associate II
void SystemClock_Config(void)
{
 
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
 
    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();
 
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 12;
  RCC_OscInitStruct.PLL.PLLN = 192;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Activate the Over-Drive mode 
    */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
 
    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* ADC2 init function */
static void MX_ADC2_Init(void)
{
 
  ADC_ChannelConfTypeDef sConfig;
 
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
    */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 2;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
    */
  sConfig.Channel = ADC_CHANNEL_5;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
    */
  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}
/* TIM4 init function */
static void MX_TIM4_Init(void)
{
 
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
 
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 0;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 2499;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}

Here is some missing code that I was not able to add in the first message

AJack
Associate II

Here is some more information:

I start TIM1 in 
void TIM4_IRQHandler(void)
{
   ...
    HAL_TIM_Base_Start_IT(&htim1);
   ...
}
 
and stop TIM1 in 
void TIM1_UP_TIM10_IRQHandler(void)
{
  ...
   HAL_TIM_Base_Stop_IT(&htim1);
  ...
}
I start the ADC DMA in 
void TIM4_IRQHandler(void)
{
   ...
     HAL_ADC_Start(&hadc2);
     HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&m_adc_buf, 4);
   ...
}
 
and stop ADC DMA in
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  ...      
  HAL_ADCEx_MultiModeStop_DMA(&hadc1);
  HAL_ADC_Stop(&hadc2); 
   …
}

AJack
Associate II

One More thing TIM4 interrupt handler is invoked with 40 KHz, but when I plot ADC data I only get 20 samples when sampling a 1 kHz signal from the pulse generator connected to the ADC inputs.

What's the ADC sampling time? Is it short enough so that both conversions finish within 1/40kHz?

I don't use Cube nor CubeMX.

JW

AJack
Associate II

The ADC conversions finish time is 2,56 us

While the ADCs are triggered every 25 us so it should be plenty of time. (For each channel I use 15 cycles, but I have tried with 3 cycles and that does not help)

ADCCLK = PCLK2 / ADC CLK Prescaler

ADCCLK = 100 MHz / 4

ADCCLK = 25 MHz

....

Delay between 2 sample phases 5 cycles

ADC1&2 Rank 1 sampling time 15 cycles

ADC1&2 Rank 2 sampling time 15 cycles

Channel-wise sampling time

Tconv = Sampling time + 12 cycles

TConv = channel1 + channel 2

TConv = 15 + 12 + 5 + 15 +12 + 5

TConv = 64 cykles

ADC conversions finish time = 64 * 1/25000000

ADC conversions finish time = 2,56 us

Timer 4 interrupt handler is invoked every: 1/40 kHz = 25 us

AJack
Associate II

The first image below shows that ADC samples only 20 samples during each period even when input signal i 1 kHz. The second image shows the input signal connected to the ADCs input channels.

0690X00000ARVafQAH.png

0690X00000ARVaVQAX.png

AJack
Associate II

Do anyone have any idea what the problem might be?

AJack
Associate II

OK the main problem is now solved.

Instead of invoke "start of timer 1" and "start ADC" in TIM4 IRQ. I let TIM4 be the master of TIM1 (so TIM1 is triggerd by TIM4)

by setting TIM1 to:

Slave Mode: External Clock Mode 1

Triger source to: ITR3

Then I set TIM1 to:

Slave mode controller to ERT mode 1

When I start ADC I set length of data to 2 instead of 4, since length should be calculated as 32 bits data and not 16 bits data.

HAL_ADC_Start(&hadc2);

HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&m_adc_buf, 2/*4*/);

I Still have a problem that ADC divide the TIM1 sample rate with 2, but that is easy to fix since there is no problen to sample TIM1 faster now.

To start and stop ADC seems to take quit some times and should probably not be done in a timer IRQ. Thanks waclawek.jan for your help