Help with understanding delay precision?

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

I am trying to use the included delay.h and the _delay_ms function for timings.

As a basic test, I am trying to switch an led on and off at precisely 1x/sec. Something like this...

while (1) {
		
//1000 ms total for 1 second

//LED Toggle
PORTD = 0b00000001;
_delay_ms (200);

//LED Toggle
PORTD = 0b00000000;
_delay_ms (800);

}

When I do this while watching the second hand on a watch, the timing is not accurate. I'm thinking this has to do with cpu settings, but I thought that the purpose of this function was to automatically make the calculation for you.

I am using AVR Studio 4 / WinAVR, and have the cpu settings configured in the menus. Testing on STK500.

What am I doing wrong? Thanks.

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

I'm guessing you arent using a xtal but the internal osc?

Also; your "PORTD = 0b00000000;" and "PORTD = 0b00000001;" take some time too, nothing noticable, but they do add onto the 1000mS

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

How inaccurate is it?

If it is a few percent out, then my guess is you're using the internal oscillator, which is no good for accurate timing (as supplied it is only +/-10% of noiminal I think, and even when calibrated the variation with temperature is a few percent). Note that just connecting a crystal is inadequate; you have to set the programming fuses appropriately to make the AVR use the crystal.

If it is out by a factor of 8 out then my guess is the CLKDIV fuse.

CH
==

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

I think optimization must be turned on
(See documentation !). Is your fuse-setting and
F_CPU ok ?

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

Using Internal Osc. CKDIV8 checked. Mega88 by the way. Never had a need for accurate timing to this point so I haven't tried a crystal yet, but I am at least trying to get it close internally first.

I've noticed that if I go to configuration options and change the frequency (ie. from 1000000hz to 8000000hz) the rate of the flashing changes accordingly.

My understanding was that this frequency value is automatically read in and calculated in the _delay_ms function. Apparently I am misunderstanding that.

Checking docs for optimization and other fuse settings...

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

The AVR does not know the speed of your crystal.
You tell Studio or your makefile by defining F_CPU.

So the macros work out how many F_CPU cycles are needed for the required delay. The faster your F_CPU, the more cycles that need to be wasted.

And then as a special totally unnecessary "feature" of avr-gcc it deliberately screws up the process if you have a -O0 optimisation setting.

1. be honest about F_CPU. e.g. for 12MHz crystal with CKDIV8 fuse, #define F_CPU 1500000
2. always use -O1 or -Os optimisation.

David.

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

Thanks.

Didn't understand the CKDIV8 setting before. I tried dividing my delays by 8 @ 8Mhz and got the expected result. Then unchecked the CKDIV8 and got the expected result with the proper 1000ms total delay time.

Time to learn crystals.

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

Quote:
When I do this while watching the second hand on a watch, the timing is not accurate. I'm thinking this has to do with cpu settings, but I thought that the purpose of this function was to automatically make the calculation for you.

I never cease to be amazed by young people's reaction times.

Personally, I set a loop that counts for 60 or 100 seconds before lighting an LED or displaying a UART message. I can manage this by comparing to my wristwatch. I can detect a 2% inaccuracy this way. Anything fussier needs a long time.

However you can use AVR053 to calibrate your RC oscillator to 2% if you have a jtagice or stk500.

Simple answer is: use a crystal for accurate times.

David.