i don't understand : _delay_us

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

Hi, I am a newbie to AVR. Just wondering, people told me that the built-in internal frequency of AVR (AVR162) is 10Mhz but when I am using prescaler =1, it shows 1Mhz. Why?

Also, I don't understand how util/delay.h works

	while (1)
	{
		PORTB |=0X02;
		_delay_us (0.3125);
		PORTB &=~0x02;
		_delay_us (0.3125);
	}

I wanted to have a 5us delay, so I type _delay_us (5); but it turns out to be 80us! So I tried changing it by using a ratio concept, wrting _delay_us (0.3125) and it works! I got 5us output now. I DON'T UNDERSTAND WHY. Can someone please explain it to me? Thanks in advanced. Sorry if my question sounds stupid. Cheers!

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

Quote:

but it turns out to be 80us!

Did you read (and observe) the points made in the manual. Key amongst these are:

1) F_CPU must reflect the actual clock speed of the CPU (this is the most commonly wrong thing)

2) util/delay.h programs MUST be built with optimisation enabled (usually it'd tend to be -Os, but you'd want to verify that)

3) the parameter to _delay_us() must be a constant that is known at compile time - it cannot be a run-time variable (to do that you must wrap a constant call in a variable loop).

As this is about GCC specifically I'll move this thread.

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

Try reading your error / warning messages.
Then read the _delay_us() documentation.

Either your AVR is running at 1MHz with optimisation -Os
Or your AVR is running at 16MHz with optimisation -O0 ( and by chance this has a magic overhead to give your delay )

David.

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

Hi Clawson thanks for your fast reply. I don't understand most of the things that you said. Sorry. Can you clarify please?

Quote:
F_CPU must reflect the actual clock speed

what is the difference of F_CPU and actual clock speed of CPU? Why are they different?

Quote:
util/delay.h programs MUST be built with optimisation enabled

How do you do that? I am using winAVR 20080610.

Quote:
a constant that is known at compile time - it cannot be a run-time variable (to do that you must wrap a constant call in a variable loop).

I don't understand what do you mean by 'wrap a constant call in a loop'.

Sorry I am seriously lost. Thanks.

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

Quote:

what is the difference of F_CPU and actual clock speed of CPU? Why are they different?

The clock speed of the CPU is the rate at which a piece of quartz or an RC timing generator in the electronics happen to be oscillating. F_CPU is a number you build into your program that is you guess at what that oscillation frequency is. Often your guess and reality are not the same. For example people often add a crystal to an AVR circuit but never change the fuses so the crystal is ignore completely. Or they do succeed in changing that fuse but fail to spot that the CPU also had a fuse called CKDIV8 which results in the internal clocking of the CPU happening at 1/8th of the rate that the crystal/RC is oscillating at. So you need to set F_CPU to the number that represents the speed the CPU is actually running at, not what you *think* it it running at. Ironically the way you'd often test this is to put your assumption into the F_CPU value then build a program using _delay_us() or _delay_ms() that flashes and LED or toggles an oscilloscope visible pin and then the difference between the actual observed rate and the expected rate identifies how far out your F_CPU assumption was. Often the error will be x8 (because of CKDIV8) or as muh as +/-10% because the user hasn't realised how inaccurate the internal RC is. Or it could be the ratio of an internal 1MHz RC oscillator (the default) to the attached crystal frequency (because it hasn't actually been enabled).

To enable optimisation make sure the command line to the compiler includes "-Os" and you should be hot to trot.

As for the constant thing. You can use:

_delay_us(5);

or

#define DELAY 5
_delay_us(DELAY);

or even:

{
  int a=3, b=7;
  _delay_us(a*b);

(because the compiler can "see" that this could never be anything but equivalent to:

  _delay_us(21);

But what you can't do is:

void my_delay(int us_value) {
  _delay_us(us_value);
}

because 'us_value' could take on any value at run-time. Instead it would be necessary to use:

void my_delay(int us_value) {
  int i;
  for(i=0; i

In which case the call to _delay_us() is "safe" because it's still a constant value (1) and meets the usage requirements of _delay_us().

This all comes about because delay_us() is defined as a floating point function which relies on the fact that the values will be pre-calculated at compile time (like the a,b example above). If the values being used are not constant then the function will be compiled to include the full floating point library of the C compiler and to do the floating point calculation at run-time with a HUGE speed and size penalty that will not only bloat your program but also completely throw out the otherwise fairly accurate timing the functions are supposed to provide.

Cliff

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

F_CPU is a #defined constant (usually set up in your Makfile) that tells various routines (delay, uart baud rate setting, etc) what clock rate your processor is running at. It does *not* actually set or change the clock rate.
The clock speed is determined by the clock source (crystal, oscillator, internal RC oscillator) and
fuses (CLKDIV if the processor has it, CLKOPT to make sure the processor is correctly using any external oscillator).
To avoid headaches, these two should match. An easy way to check if you got things right is to write code that should blink an LED once per second and see if it really does so.

By 'wrap a constant call in a loop', we mean have a constant delay (ie, 1000us) in a loop.

void delay_ms(uint16_t ms)
{
    for (; ms > 0; ms--) _delay_us(1000);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mien_noodles wrote:
what is the difference of F_CPU and actual clock speed of CPU? Why are they different?

I think the point is they must _NOT_ be different. F_CPU is a constant defined inside your program or in the Makefile, which tells the compiler the clock speed of your CPU, so it can for example use the correct delay routines.

For example in your main C source file, in the beginning (or wherever (C source file) you need the delay functions):

#define F_CPU 1000000UL  // 1 MHz
#include 

mien_noodles wrote:

Quote:
util/delay.h programs MUST be built with optimisation enabled

How do you do that? I am using winAVR 20080610.

You have to define the compiler flags in your Makefile.
It would read for example:

CFLAGS=-g -mmcu=$(MCU) -std=c99 -pedantic -Wall -Wextra -Wstrict-prototypes -Os -mcall-prologues

mien_noodles wrote:

Quote:
a constant that is known at compile time - it cannot be a run-time variable (to do that you must wrap a constant call in a variable loop).

I don't understand what do you mean by 'wrap a constant call in a loop'.

It means if you want a variable delay, you must call the constant delay function a variable amount of times inside a loop. (bad english?)

Edit: darn, too late :P
-masa

n00b

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

Hi guys, thanks for the detailed explaination! Now I have understood F_CPU and how to select -Os on Makefile. Am still struggling a bit with the delay though. Can I ask another question?

I am using an external ADC (ADS1252 -TI)and it says on the datasheet that to set ~5kHz data output rate, I have to set the CLK to 1.843200 Mhz. How do I achieve this CLK frequency? Do I use a prescaler or what? I don't understand how AVR clock works. Thanks in advanced :)

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

For that clock rate you would need to use an external crystal of that value. The internal RC oscillator is not capable of that frequency.

Quote:
people told me that the built-in internal frequency of AVR (AVR162) is 10Mhz

Those people were wrong. The chip may have a maximum capability of 10MHz, but the internal clock is 8MHz (with a default pre-scaler of 8, making the default frequency 1MHz).

Regards,
Steve A.

The Board helps those that help themselves.

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

Oh right. So how do I get an external crystal oscillator? Does it looks like a oval metal with 2 legs? How do I select one with the frequency that I want?

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

You need to read up some in the data sheet. Apart from the crystal you need two capacitors. Search this site for "load capacitors" for a lot of traffic.

Quote:

How do I select one with the frequency that I want?

Huh? The important question before that is "What frequency do I want?". You should saty under the max rating for the AVR model you are using (see the data sheet). If you plan to do UART communications you should select one of those odd looking frequencies that give little or no error in transmission rate. There are several pages of tables in the data sheet to help you choose clock frequency based on the transmission rate.

Now when you have decided on a frequency the selection in a supplier catalog or on-line store should be pretty straight forward. The remaining parameters are the accuracy of the crystal (often given in PPMs), maybe a specification of the load capacitance, the package (yes most often that oval metallic case, but it can be full height (10 millimetres?) or low height (4 millimetres?).

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I just looked at the ADS1252 datasheet. It needs an external clock, not a crystal. I would run the Atmega162 at 14.7456, 11.0592, or 7.3728 depending on supply voltage, and use one of the timers (or an external divider) to get 1.8432 MHz out. Or just get a 1.8432 MHz oscillator.

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

Quote:

I would run the Atmega162

Except that the 162 has the luxury of a CKOUT fuse so no code and no timer is required at all and the entire system can hang off the 1.8432MHz crystal

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

Thanks for the clues...
Is that possible to get an output squarewave of 1 MHz and 100kHz from the AVR162. I was trying to use timer to get the 1MHz but it don't work...

#include 
#include 
#include 

#define F_CPU 1000000UL



ISR(TIM1_OVF_vect)
{
    PORTB ^= (1<<0);
    TCNT1 = 1;
}

int main (void)
{
   DDRB |= (1 << 0); // Set LED as output

   TIMSK |= (1 << TOIE1); // Enable overflow interrupt
   sei(); // Enable global interrupts

   TCNT1 = 1;

    TCCR1B |= (1 << CS11); // Start timer at Fcpu/8


   for (;;)
   {

   }
}

Can someone please point me out ? Many thanks

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

Well if F_CPU is 1MHz there's no way in code or even a h/w timer to get the same frequency. HOWEVER the 162 has a CKOUT fuse.

(the 100kHz should be quite possible having a timer toggle a pin using CTC)