Skip to main content
Associate
November 25, 2025
Solved

Generate a single pulse of 12ns with stm32u5

  • November 25, 2025
  • 11 replies
  • 1095 views

Hi there.

I’m trying to generate a 12 ns pulse for a time-of-flight (ToF) application.

I’m using an STM32U5 microcontroller, and I’d like to know whether one of the general-purpose timers (TIM2/TIM3/TIM4/TIM5) can produce a pulse that narrow. With a 160 MHz timer clock, the time resolution is about 6 ns, so in principle it seems feasible, but I may be overlooking something.

Thanks!

Best answer by lucascalam

In the end, I realized I hadn’t been interpreting my results correctly. The pulse shown earlier in IMG_0794 was actually inverted, the relevant pulse was the low portion, not the high one. This means the pulse width was around 200 ticks.

This behavior occurs because, in the selected PWM mode combined with one-pulse mode, the output goes low when the counter transitions from TIMx_CCR to TIMx_ARR. Therefore, for example, if we want a 2-tick low pulse, setting CCR = 198 and ARR = 200 should produce the expected result.

Sorry for the confusion, and thanks to everyone for the support.

Cheers!

11 replies

T_Hamdi
ST Employee
November 25, 2025

hello @lucascalam 

To generate a pulse of about 12 ns using an STM32U5 timer running at 160 MHz, you can:

  • Set the timer prescaler to 1 (no division) for a timer tick of 6.25 ns.
  • Use PWM mode or Output Compare mode.
  • Set the pulse width to 2 timer ticks (12.5 ns), which is the closest achievable width to 12 ns.

This will produce a pulse very close to 12 ns directly from the timer hardware without CPU intervention.

 

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Hamdi Teyeb"
Associate
November 25, 2025

Hi @T_Hamdi , thanks a lot for your answer. Do you know if there is any example I can use as a guide?

Associate
November 25, 2025

I am using something like this:


void WHGPIO_PinOutSendPulse1(void) {
 LL_TIM_EnableCounter(TIM2);
}

void WHGPIO_InitPinOutSendPulse(void) {
 
 LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);

 LL_GPIO_InitTypeDef gpio_init = {0};
 gpio_init.Pin = LL_GPIO_PIN_1;
 gpio_init.Mode = LL_GPIO_MODE_ALTERNATE;
 gpio_init.Alternate = LL_GPIO_AF_1; // TIM2_CH2 → AF1 on PA1
 gpio_init.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
 gpio_init.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
 gpio_init.Pull = LL_GPIO_PULL_NO;

 LL_GPIO_Init(GPIOA, &gpio_init);

 LL_TIM_DisableCounter(TIM2);
 LL_TIM_OC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_OCPOLARITY_HIGH);

 LL_TIM_SetPrescaler(TIM2, 0);
 LL_TIM_SetAutoReload(TIM2, 200);
 LL_TIM_OC_SetCompareCH2(TIM2, 1);

 LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_PWM1);

 LL_TIM_OC_EnablePreload(TIM2, LL_TIM_CHANNEL_CH2);
 LL_TIM_EnableARRPreload(TIM2);

 LL_TIM_SetOnePulseMode(TIM2, LL_TIM_ONEPULSEMODE_SINGLE);

 LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);

 LL_TIM_GenerateEvent_UPDATE(TIM2);
}


void main() {
 WHGPIO_InitPinOutSendPulse();
 while(1) {
 WHGPIO_PinOutSendPulse1();
 }
}

I obtained the results shown in the attached images. From the first graph, we can see that the pulse width is significantly larger than 12 ns. The second graph shows the interval between pulses, which is about 1.25 µs. This is expected, since the auto-reload value is set to 200 ticks, and 200 × 6.25 ns = 1.25 µs. So, while the frequency appears to be configured correctly, the pulse width does not.

T_Hamdi
ST Employee
November 25, 2025

hello @lucascalam 

To achieve a pulse width of approximately 12 ns, you need to increase the compare value in your code from:

LL_TIM_OC_SetCompareCH2(TIM2, 2);

 each timer tick corresponds to about 6.25 ns at 160 MHz, setting the compare register to 2 will produce a pulse width close to 12.5 ns, effectively doubling the pulse duration from 6.25 ns to approximately 12 ns.

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Hamdi Teyeb"
Associate
November 25, 2025

hello @T_Hamdi .

Thanks for your answer. The problem is that even when the compare value is set to 1, the pulse width that I get is more than 50ns, as the image that I attached on the previous reply. Do you have any idea why the pulse is always longer than the expected 6ns (or 12ns in case the compare value is set to 2 ticks) ?

Ozone
Principal
November 25, 2025

I think you will need to get deeper into the reference manual of your MCU.
Most STM32 devices have a dozen or more timers, usually on different peripheral busses, while not all those busses support the same clock frequencies.
In most devices I worked with, the peripheral busses support only a maximum of core-clock/2.
I have no specific knowledge of STM32U5 devices, though.

T_Hamdi
ST Employee
November 25, 2025

hello @lucascalam 

To understand why your pulse width is longer than expected, you should first check the actual timer clock frequency. If the timer runs at a lower frequency than 160 MHz, each timer tick will be longer, which increases the pulse width.

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Hamdi Teyeb"
Associate
November 25, 2025

hello @T_Hamdi , the frequency of the clock is set to 160MHz. 

I checked also the value with  LL_RCC_GetSystemClocksFreq().

Additonally, in the measurement I got the following: (see IMG_0794.jpeg).

 

which shows that the period between pulse is 1.25us. In the code, I set the period to 200 ticks:

LL_TIM_SetAutoReload(TIM2, 200);

therefore, we can confirm that the frequency is properly set (otherwise, the period would be different not  1.25us).

 

I have no clue what might be causing this issue.

MM..1
Chief III
November 25, 2025

Preloading with one pulse mode is absurd, and too place in while 

LL_TIM_EnableCounter(TIM2);
waclawek.jan
Super User
November 25, 2025

Yes, they all are mistakes, but neither of them should result in cca 10x longer pulse.

JW

LCE
Principal II
November 25, 2025

Looks at least that you're quite close with 62.5 ns (?).

Check the timer registers, compare to ref manual. Is the "compare" register really set to 2 (or does this have the typical +1, wouldn't make sense in this case...) ?

The basic timer functions like this are not to hard to do with direct register settings.

waclawek.jan
Super User
November 25, 2025

What's your hardware, a "known-good" board like Nucleo or Disco, or your own?

Do you measure directly at the PA1 pin? What is connected to that pin?

JW

LCE
Principal II
November 26, 2025

I was curious, can't remember to have used the timer for an output pulse.
Just working with a L073 at 32 MHz, so I programmed TIM3 to work at 32 MHz, with a 1 tick high output every 10 timer ticks - and I see the same on the scope.

/* 32 MHz timer,
 *	pulse output
 *	TEST only
 *	TIM3, output compare ch1
 *	-> PC6
 */
void TimPulseInit(void)
{
	/* peripheral clock enable */
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

	TIM3->CR1	= 0;
	TIM3->CR2	= 0;
	TIM3->SMCR	= 0;
	TIM3->CCER	= 0;
	TIM3->DIER	= 0;
	TIM3->SR	= 0;
	TIM3->EGR	= 0;
	TIM3->OR	= 0;
	TIM3->CNT 	= 0;

	TIM3->PSC	= 0;	/* max input clock */
	TIM3->ARR	= 9;	/* rep clock * 10 */

	/* 1 tick pulse length */
	TIM3->CCR1	= 1;
	/* 110 = PWM mode 1 */
	TIM3->CCMR1	= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // | TIM_CCMR1_OC1PE | TIM_CCMR1_OC1FE;
	/* enable output */
	TIM3->CCER 	= TIM_CCER_CC1E;

	/* TIM3 enable */
	TIM3->CR1 |= TIM_CR1_CEN;
}

 

Here's the UART output showing TIM registers in hex:

TIM3->
CR1 0001
CR2 0000
SMCR 0000
DIER 0000
SR 001F

PSC 0000
ARR 0009
CCR1 0001
CCMR1 0060
CCER 0001
lucascalamAuthorBest answer
Associate
November 26, 2025

In the end, I realized I hadn’t been interpreting my results correctly. The pulse shown earlier in IMG_0794 was actually inverted, the relevant pulse was the low portion, not the high one. This means the pulse width was around 200 ticks.

This behavior occurs because, in the selected PWM mode combined with one-pulse mode, the output goes low when the counter transitions from TIMx_CCR to TIMx_ARR. Therefore, for example, if we want a 2-tick low pulse, setting CCR = 198 and ARR = 200 should produce the expected result.

Sorry for the confusion, and thanks to everyone for the support.

Cheers!

waclawek.jan
Super User
November 26, 2025

Oh, so the positive pulse was just a coincidental value between timer overflow/stop until code executing the function call and that call to execute. It must have been quite jittery, wasn't it?

JW

Associate
November 26, 2025

 

I’m not completely sure, but since the call to enable the counter was placed inside an infinite loop, what you describe is likely part of the cause. It definitely wasn’t the best approach, but I only needed a quick check to see whether a 1-tick or 2-tick pulse was achievable (this was my first time generating pulses). Now I’ll implement it properly in my application.