volatile qualifier & microsecond delay problem

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

I have recently received my SAMD21 xplained pro board.I was writing microsecond delay subroutine for the MCU.I found a link here but that is not working for me so I modified the code a little bit.

So,now my delay.h file looks like this below.

 

#ifndef DELAY_H_
#define DELAY_H_

#include "sam.h"
#include <stdio.h>

#define MstrClkFrq 8000000ul

#if MstrClkFrq == 8000000ul

static __inline__ void delay_us ( uint32_t usDelay )
{
	asm volatile(
	"mydelay:			\n"
	" sub  %0, #1	\n"	// 1 cycle
	" nop				\n" // 1 cycle
	" nop				\n" // 1 cycle
	" nop				\n" // 1 cycle
	" nop				\n" // 1 cycle
	" nop				\n" // 1 cycle
	" bne  mydelay		\n" // 2 if taken, 1 otherwise
	:"+r" (usDelay)
	);
}

#else
#error Clok Frequency Error...
#endif

void delay_ms(uint32_t msDelay);

#endif /* DELAY_H_ */

I am simply toggling a pin & measuring the actual delay in scope.So my test result is as follows:

 

1us delay at program - 2.38uS at scope

100uS delay at program - 101uS at scope

 

But

 

when I am omitting the volatile qualifier in the above delay_us subroutine,the result of 1uS delay is getting a lot more better.But,the 100us delay is returning same value as 1us.

 

with volatile qualifier removed:

 

1uS delay at program - 1.38uS at scope

100uS delay at program - 1.38uS at scope!!!!!!

 

why this is happening ??

Last Edited: Thu. Jul 4, 2019 - 06:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Without the volatile flag the compiler/assembler is optimizing out your nop loop since it doesn't do anything from the compiler's point of view.

 

https://gcc.gnu.org/onlinedocs/g...

 

It is not unusual for a Delay_Us(1) to last longer than 1us because of CPU overhead.

Josh @ CIHOLAS Inc - We fill the gaps from chips to apps

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SHARANYADAS wrote:

when I am omitting the volatile qualifier in the above delay_us subroutine,the result of 1uS delay is getting a lot more better.But,the 100us delay is returning same value as 1us.

 

Any function that loops has two components: the one-time function call and return overhead, and the actual looping component.  You will never get a simple delay function that works for 1us and for 100us, because of the fixed overhead.  You may get a delay function that works but it will involve subtracting some amount from the delay value to account for the overhead.

 

The part about 'volatile' has been explained.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So,the proper way here is to proceed using the volatile.... right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wrote some cycle-counting delay functions that use the sysTick timer (They assume that systick is running, and that the requested cycle count is less than any sysTick period that's been set, but aren't destructive and don't use interrupts.)   Obviously, these are loops that time "a bit more than the number of cycles asked for", since most instructions take at least one cycle (all of them on a CM0, I think.)  And it doesn't have the "function overhead is N cycles" tuning.  But it will time accurately even in the face of things like slow flash memory and/or caching.

 

https://github.com/WestfW/Duino-hacks/blob/master/systick_delay/systick_delay.ino

 

I put "similar" code into Adafruits SAMD51 delayMicroseconds() in their Arduino core, but it uses the DWT module (which has another 32bit cycle counter) and isn't appropriate for an 8MHz CM0 chip.

https://github.com/adafruit/ArduinoCore-samd/pull/77