I need to start an ADC reading with a fixed delay in different places in my code. It should be done with a timer and once an update event (overflow) is generated, the timer should be stopped and reset for next call.

Most suitable appears to be One Pulse Mode to generate TRGO and to trigger the ADC.

I use an STM32L4R5ZI. The ADC works with no issues with software enable, but somehow I can't trigger it with the timer. I guess it's some small detail I still miss after all the tests.

ADC is set to external trigger, TIM2 TRGO as in the reference manual and other examples I see:

hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_TRGO;

Reference manual, Table 129 01 Hardware Trigger with detection on the rising edge

Reference manual, Table 131 EXT11 TIM2_TRGO Internal signal from on-chip timers 1011

I see registers are set correctly during debug. I guess the main issue is the timer setting:

static void MX_TIM2_Init(void) {
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 99;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {

  TIM2->CCR2 =1;
  TIM2->CCMR1 |= (TIM_CCMR1_OC2M_0 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2FE); // PWM Mode2

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
    // TIM2->CR2   |= TIM_CR2_MMS_1; // master mode 010: update signal is used as trigger output (TRGO)
    TIM2->EGR |= TIM_EGR_UG; // Update Generation
  TIM2->DIER = 1U;
  TIM2->SR = 0; // clear update status caused by TIM_EGR_UG

  // enable TIM2 IRQ from NVIC

In the main I try to start the conversion and wait for it to complete as follows:

TIM2->CR1 = 9U;
while(!(ADC1->ISR & ADC_ISR_EOS));  

Magic number 9 to have one pulse mode and CEN set at the same time. I have an interrupt handler to reset CNT, SR and CEN.

Any help or idea is welcome!

  • 1
    \$\begingroup\$ I assume the executions stops at the while loop. From the manual "trigger selection is effective once software has set bit ADSTART=1". Do you have this bit set in ADC_CR? Have you checked that timer interrupt is triggered, i.e. timer was set up correctly? \$\endgroup\$
    – Flexz
    Commented Feb 8, 2023 at 6:00
  • \$\begingroup\$ You are correct! I was not sure whether I have to put ADSTART to 1. During debug I did it but probably still had software enable in the ADC settings so it was triggered before the timer and I dropped it. \$\endgroup\$
    – D. K.
    Commented Mar 7, 2023 at 12:27

1 Answer 1


To make TIM2 trigger a delayed ADC conversion, do the following:

  1. Calibrate and enable the ADC, select a channel and sampling time, enable necessary interrupts (I'll leave it to you).
  2. Configure the ADC in continuous mode with the proper external trigger enabled:
  1. Initialize TIM2 with the required TRGO trigger event (UEV in this example):
TIM2_PSC = 99; // Preload prescaler
TIM2_EGR = TIM_EGR_UG; // Apply prescaler
  1. Start the ADC:
  1. Start the timer in one pulse mode (repeat as often as needed):
TIM2_ARR = number_of_ticks - 1;

The key point here is that the ADC reacts on a trigger only when a conversion is started. By running the ADC in continuous mode, you won't have to restart it (unless you desire to do so by design).


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.