Skip to main content
Associate II
August 15, 2025
Question

ADC conversion triggered by timer output compare

  • August 15, 2025
  • 2 replies
  • 1540 views

I am trying to make the ADC channels sample the current through some motor channels synchronised to the center of the center aligned PWM waveform to avoid switching noise.

The microcontroller I am using is the STM32F411 series, and I am using the first 3 channels of Timer 2 for PWM. The 4th channel is set to "Output compare no output", and I also set the timer trigger output event selection to Output compare (OC4REF). I set the pulse of channel 4 to the TOP value of the timer so it triggers when the counter counts to the TOP (midpoint of PWM).

eggsacc_0-1755228333971.pngeggsacc_1-1755228352332.png

 

For the ADC, i am trying to sample 4 inputs (2 phases for 2 motors) and shift the data into a buffer using DMA. I enabled scan conversion mode as well as DMA continuous requests, and set the trigger source to Timer 2 capture compare 4 event, triggered on the rising edge. The ADC global interrupt is also enabled.

eggsacc_2-1755228390909.png

In code, I started timer 2 using:

HAL_TIM_Base_Start(&htim2);
HAL_TIM_OC_Start(&htim2, TIM_CHANNEL_4);

Then, I start the ADC using:

HAL_ADC_Start_DMA(&hadc1, ADC_buff, 4);

 In the ADC conversion complete callback function, I shift the buffer values into the motor struct for processing:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
 motor.phase_current[0] = ADC_buff[0];
 motor.phase_current[1] = ADC_buff[1];
}

 However, the values in the buffer just remained at 0 without updating. I tried debugging it by adding a breakpoint at the HAL_ADC_ConvCpltCallback() function to see if it was doing anything, but the breakpoint was never triggered. I also tried to trigger the ADC manually using "regular conversion launched by software" instead of the timer, and the values updated fine. So I'm pretty sure the issue is with the triggering the ADC with Timer 2 compare match. I have already tried many different configurations of timer 2, but all of them did not work (conversion callback function was never called).

Any suggestions would be appreciated!

2 replies

waclawek.jan
Super User
August 15, 2025

Read out and check/post content of TIM and ADC registers.

This would probably work, if you set TIM2_TRGO as ADC trigger, rather than TIM2_CH4. 

TIM2_CH4 selection in ADC should also work, but ST is sloppy in explaining the details, and you probably need to enable the TIM2_CH4 output by setting TIM2_CCER.CC4E (I dont' Cube/HAL/MX, probably something like setting it other than "no output"), although you don't need to assign any pin to it - see this and the linked discussion there.

JW

Explorer
June 29, 2026

Unfortunately, the developers don't clearly describe the internal interconnection system of the blocks. Moreover, they force users to rely on this HELL, called HAL.

As a result, we have a situation where the developers aren't meticulous in their hardware documentation, and users have a poor understanding of what the firmware does.

In fact, you can easily, using a bare CMSIS or, at worst, a LL library, pinpoint all these issues with ADC startup by examining the "gray box."

In fact, I solved a similar issue on the STM32G473. After some effort, I discovered that the startup of the conversion of the injected channel group ADC2 from TIM1, triggered by the TIM1 CC4 Event, is definitely triggered by the internal signal OC4, taking into account its polarity! Thus, with a centrosymmetric PWM signal, this allows for ADC triggering both with an increasing and decreasing counter direction.

However, I can no longer say with certainty whether this is happening directly from OC4 or from its "copy," i.e., whether dead time affects ADC triggering. This needs further verification.