1 |
/* Copyright (c) 2002, Marek Michalkiewicz |
/* Copyright (c) 2005 Joerg Wunsch |
|
Copyright (c) 2004,2005 Joerg Wunsch |
|
2 |
All rights reserved. |
All rights reserved. |
3 |
|
|
4 |
Redistribution and use in source and binary forms, with or without |
Redistribution and use in source and binary forms, with or without |
30 |
|
|
31 |
/* $Id$ */ |
/* $Id$ */ |
32 |
|
|
|
/* |
|
|
avr/delay.h - loops for small accurate delays |
|
|
*/ |
|
|
|
|
33 |
#ifndef _AVR_DELAY_H_ |
#ifndef _AVR_DELAY_H_ |
34 |
#define _AVR_DELAY_H_ 1 |
#define _AVR_DELAY_H_ |
|
|
|
|
#include <inttypes.h> |
|
35 |
|
|
36 |
/** \defgroup avr_delay <avr/delay.h>: Busy-wait delay loops |
#warning "This file has been moved to <util/delay.h>." |
37 |
\code |
#include <util/delay.h> |
|
#define F_CPU 1000000UL // 1 MHz |
|
|
//#define F_CPU 14.7456E6 |
|
|
#include <avr/delay.h> |
|
|
\endcode |
|
|
|
|
|
\note As an alternative method, it is possible to pass the |
|
|
F_CPU macro down to the compiler from the Makefile. |
|
|
Obviously, in that case, no \c \#define statement should be |
|
|
used. |
|
|
|
|
|
The functions in this header file implement simple delay loops |
|
|
that perform a busy-waiting. They are typically used to |
|
|
facilitate short delays in the program execution. They are |
|
|
implemented as count-down loops with a well-known CPU cycle |
|
|
count per loop iteration. As such, no other processing can |
|
|
occur simultaneously. It should be kept in mind that the |
|
|
functions described here do not disable interrupts. |
|
|
|
|
|
In general, for long delays, the use of hardware timers is |
|
|
much preferrable, as they free the CPU, and allow for |
|
|
concurrent processing of other events while the timer is |
|
|
running. However, in particular for very short delays, the |
|
|
overhead of setting up a hardware timer is too much compared |
|
|
to the overall delay time. |
|
|
|
|
|
Two inline functions are provided for the actual delay algorithms. |
|
|
|
|
|
Two wrapper functions allow the specification of microsecond, and |
|
|
millisecond delays directly, using the application-supplied macro |
|
|
F_CPU as the CPU clock frequency (in Hertz). These functions |
|
|
operate on double typed arguments, however when optimization is |
|
|
turned on, the entire floating-point calculation will be done at |
|
|
compile-time. |
|
|
|
|
|
\note When using _delay_us() and _delay_ms(), the expressions |
|
|
passed as arguments to these functions shall be compile-time |
|
|
constants, otherwise the floating-point calculations to setup the |
|
|
loops will be done at run-time, thereby drastically increasing |
|
|
both the resulting code size, as well as the time required to |
|
|
setup the loops. |
|
|
*/ |
|
|
|
|
|
#if !defined(__DOXYGEN__) |
|
|
static void _delay_loop_1(uint8_t __count) __attribute__((always_inline)); |
|
|
static void _delay_loop_2(uint16_t __count) __attribute__((always_inline)); |
|
|
static void _delay_us(double __us) __attribute__((always_inline)); |
|
|
static void _delay_ms(double __ms) __attribute__((always_inline)); |
|
|
#endif |
|
|
|
|
|
/** \ingroup avr_delay |
|
|
|
|
|
Delay loop using an 8-bit counter \c __count, so up to 256 |
|
|
iterations are possible. (The value 256 would have to be passed |
|
|
as 0.) The loop executes three CPU cycles per iteration, not |
|
|
including the overhead the compiler needs to setup the counter |
|
|
register. |
|
|
|
|
|
Thus, at a CPU speed of 1 MHz, delays of up to 768 microseconds |
|
|
can be achieved. |
|
|
*/ |
|
|
void |
|
|
_delay_loop_1(uint8_t __count) |
|
|
{ |
|
|
__asm__ volatile ( |
|
|
"1: dec %0" "\n\t" |
|
|
"brne 1b" |
|
|
: "=r" (__count) |
|
|
: "0" (__count) |
|
|
); |
|
|
} |
|
|
|
|
|
/** \ingroup avr_delay |
|
|
|
|
|
Delay loop using a 16-bit counter \c __count, so up to 65536 |
|
|
iterations are possible. (The value 65536 would have to be |
|
|
passed as 0.) The loop executes four CPU cycles per iteration, |
|
|
not including the overhead the compiler requires to setup the |
|
|
counter register pair. |
|
|
|
|
|
Thus, at a CPU speed of 1 MHz, delays of up to about 262.1 |
|
|
milliseconds can be achieved. |
|
|
*/ |
|
|
void |
|
|
_delay_loop_2(uint16_t __count) |
|
|
{ |
|
|
__asm__ volatile ( |
|
|
"1: sbiw %0,1" "\n\t" |
|
|
"brne 1b" |
|
|
: "=w" (__count) |
|
|
: "0" (__count) |
|
|
); |
|
|
} |
|
|
|
|
|
#ifndef F_CPU |
|
|
/* prevent compiler error by supplying a default */ |
|
|
# warning "F_CPU not defined for <avr/delay.h>" |
|
|
# define F_CPU 1000000UL |
|
|
#endif |
|
|
|
|
|
/** |
|
|
\ingroup avr_delay |
|
|
|
|
|
Perform a delay of \c __us microseconds, using _delay_loop_1(). |
|
|
|
|
|
The macro F_CPU is supposed to be defined to a |
|
|
constant defining the CPU clock frequency (in Hertz). |
|
|
|
|
|
The maximal possible delay is 768 us / F_CPU in MHz. |
|
|
*/ |
|
|
void |
|
|
_delay_us(double __us) |
|
|
{ |
|
|
uint8_t __ticks; |
|
|
double __tmp = ((F_CPU) / 3e6) * __us; |
|
|
if (__tmp < 1.0) |
|
|
__ticks = 1; |
|
|
else if (__tmp > 255) |
|
|
__ticks = 0; /* i.e. 256 */ |
|
|
else |
|
|
__ticks = (uint8_t)__tmp; |
|
|
_delay_loop_1(__ticks); |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
\ingroup avr_delay |
|
|
|
|
|
Perform a delay of \c __ms milliseconds, using _delay_loop_2(). |
|
|
|
|
|
The macro F_CPU is supposed to be defined to a |
|
|
constant defining the CPU clock frequency (in Hertz). |
|
|
|
|
|
The maximal possible delay is 262.14 ms / F_CPU in MHz. |
|
|
*/ |
|
|
void |
|
|
_delay_ms(double __ms) |
|
|
{ |
|
|
uint16_t __ticks; |
|
|
double __tmp = ((F_CPU) / 4e3) * __ms; |
|
|
if (__tmp < 1.0) |
|
|
__ticks = 1; |
|
|
else if (__tmp > 65535) |
|
|
__ticks = 0; /* i.e. 65536 */ |
|
|
else |
|
|
__ticks = (uint16_t)__tmp; |
|
|
_delay_loop_2(__ticks); |
|
|
} |
|
38 |
|
|
39 |
#endif /* _AVR_DELAY_H_ */ |
#endif /* _AVR_DELAY_H_ */ |