1
\$\begingroup\$

I am currently trying to achieve delay of 1 uS using timer in stm32 for my application purpose.

SYSCLk is set to 16MHZ LSI and define same for timer clock.
Timer used is a 16 bit timer.
The logic I am using is this.

void delay_us (unsigned int cnt_val)
{    
unsigned long x =0;
unsigned int cnt=0,  psc_cnt = 0;
RCC->APB1ENR |= (RCC_APB1ENR_TIM6EN );

x = (unsigned int)((cnt_val * 1000) / 62);
if(x < 65536)
  {
    cnt = x;
    psc_cnt = 0;
  }
else
  {
    cnt = 0xFFFF;
    psc_cnt = x / 65536;
  }
TIM6->SR = 0x00;
TIM6->ARR = cnt;
TIM6->PSC = psc_cnt;
TIM6->CR1 |= (TIM_CR1_CEN | TIM_CR1_OPM);
while(!(TIM6->SR & TIM_SR_UIF));
RCC->APB1ENR &= ~(RCC_APB1ENR_TIM6EN); 
}

Issue is when i tried to achieve the delay of 1 us i am getting 2.5 us. I checked it by toggling the gpio.

while(1)
{
GPIOA->ODR ^= GPIO_PIN_5;
delay_us(1);
}

can't understand the reason and looking for the solution.

\$\endgroup\$
  • \$\begingroup\$ How about longer times? I guess 1us is comparable with your processor clock and very affected by the overhead of the instruction executed around. \$\endgroup\$ – Eugene Sh. Mar 25 at 17:24
  • \$\begingroup\$ Achieving accurate delays on the order of a microsecond will be difficult using microcontroller software. Why don't you tell us what you plan to do with this delay function? \$\endgroup\$ – Elliot Alderson Mar 25 at 17:48
  • \$\begingroup\$ @EugeneSh. in case of longer times as the error is in microseconds, output is acceptable I tried with 1 sec delay and it works good. \$\endgroup\$ – Vaibhav Mar 26 at 7:24
  • \$\begingroup\$ @ElliotAlderson curiosity as how far can i go. \$\endgroup\$ – Vaibhav Mar 26 at 7:25
  • 1
    \$\begingroup\$ If you need this kind of microsecond accuracy you are using the wrong tool. You'd need some beast like a fast-clocked DSP. It can be achieved with a MCU however, by simply executing a bunch of NOP. Not in a loop, but literally just NOP NOP NOP... \$\endgroup\$ – Lundin Mar 27 at 16:09
5
\$\begingroup\$

Look at your delay_us() function.
How many assembler instructions do you think that will compile to?
Don't forget the stack push/pop and return at the end.
Now, at 16MHz, how long do you think that function will take to execute, assuming the while() at the end just falls straight through.

I threw your function into my GCC-based ARM compiler and, without much optimization enabled, it produced 33 instructions.
Considering that your measured 2.5uSec corresponds to about 40 instructions at 16MHz, and adding a few extra instructions for the while(1) loop , the GPIO toggle and the call to the function in your main(), it looks to me as though it's pretty spot-on.

\$\endgroup\$
  • \$\begingroup\$ is there any better logic for achieving same result?. If yes a hint will be helpful. \$\endgroup\$ – Vaibhav Mar 26 at 7:26
  • \$\begingroup\$ It depends largely on what your desired use-case is. For toggling a GPIO, as in your example, you should be directly driving the pin using a hardware module in your micro and not try to control it in the firmware. So - what are you actually trying to do? \$\endgroup\$ – brhans Mar 26 at 11:18
  • \$\begingroup\$ i am trying to create a delay in microseconds, toggling gpio is just for testing that delay created working expected or not. I was confirming that reason of issue is same as i am thinking and get any better solution if any \$\endgroup\$ – Vaibhav Mar 26 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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