Skip to main content
Graduate
October 24, 2024
Question

Another Microsecond Delay

  • October 24, 2024
  • 5 replies
  • 1506 views

NUCLEO-64 STM32L476RG

STM32CubeIDE 1.10.1

 

Trying to get a microsecond delay to work based on this post.

APB1 Timer = 80 MHz from HSI->PLLCLK.

TIM6 = 1 MHz (Prescaler = 79, ARR = 0xFFFF)

My main (after MX stuff) looks like this and sets delay to 5000 us (5 ms).

 

LL_TIM_EnableCounter(TIM6);

 while (1)
 {
	 LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
	 DelayUs(5000);
 }

 

  My delay function looks like this.

 

static inline void DelayUs(uint16_t us)
{
	uint16_t start = TIM6->CNT;
	while((TIM6->CNT - start) < us);
}

 

  The scope on LD2 shows this.

IMG_1089.JPG

So I'm getting 5 ms pulses but occasionally it doesn't switch and essentially doubles up. I'm very much still learning all this and dug into the datasheets as much as I could, but at this point I need help from people far smarter than me :) Any help is greatly appreciated!

    This topic has been closed for replies.

    5 replies

    Graduate II
    October 24, 2024

    I'd use 32-bit TIM, will give you more run-way.

    Would also not divide down much, as that will give you much finer granularity. You could divide by 8 (PSC=7) and get 1/10 us resolution, 6.5536 ms like scope (at 16-bit)

    It randomly doubling on/off doesn't look to be consistent with a wrapping issue.

    Anything else going on in the system here? Interrupts, etc?

    Look at the generated code.

    Perhaps counter-point with another TIM with a physical pin in toggle mode and 5ms period.

    Super User
    October 24, 2024
    while((uint16_t)(TIM6->CNT - start) < us);
    Graduate II
    October 25, 2024

    Hi,

    Unfortunately, C is not good at overflow arithmetic. You need to change your strategy -

    Change the Timer mode to Single Pulse Mode, set the appropriate prescalers etc... 

    static inline void DelayUs(uint16_t us) {
    	TIMx->CR1 &= ~TIM_CR1_CEN;	//stop counter, if it happens to be going...
    	TIMx->ARR = us - 1;		//preset counter
    	TIMx->EGR |= TIM_EGR_UG;	//reset counter
    	TIMx->CR1 |= TIM_CR1_CEN;	//start counter
    	while (TIMx->CR1 & TIM_CR1_CEN) {}
    }

     I hope that helps.

    Kind regards
    Pedro

    Graduate II
    October 25, 2024

    PS: my notes say that there are bugs in HAL with setting up Single Pulse Mode - I do it manually. If there are problems, I can edit and post some code...

    Kind Regards
    Pedro

    gb2835Author
    Graduate
    October 25, 2024

    Thanks everyone!

     

    @Pavel A. I swear I tried this before and it had no effect. Now it is stable at 5 ms.

    @PGump.1 This also made it stable at 5 ms.

    @Tesla DeLorean I'll have to get up to speed on setting up a 32-bit timer (only really know about basic timers at the moment). Not dividing down so much didn't fix the issue, but with the above recommendations I was able to get closer to us values. Ya no interrupts or anything, its a new project with the only additions in the OP.

     

    So with @Pavel A. and @PGump.1 recommendations I was able to get good pulses at 5 ms. I can get to about 10 us before the pulses start to skew more significantly. At a demand of 1 us I get 2 us delay with @Pavel A. and a 2.5 us delay with @PGump.1 (I'm assuming due to the extra overhead in the function). If at all possible, I'd like to be within 10% of the demand, so 1.1 us would be great. I'll see if I can't get a 32-bit timer from @Tesla DeLorean up and running and see if that helps.

    Graduate II
    October 26, 2024

    Hi,

    You should study the timer and how the prescalers operate, this will help you make good choices. I use this strategy to create X 100nS timing. Plus, it can be easily modified for non-blocking...

    Kind regards
    Pedro