cancel
Showing results for 
Search instead for 
Did you mean: 

Another Microsecond Delay

gb2835
Associate II

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!

6 REPLIES 6

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Pavel A.
Evangelist III
while((uint16_t)(TIM6->CNT - start) < us);
PGump.1
Senior III

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

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.

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

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.
gb2835
Associate II

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.

PGump.1
Senior III

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

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.