patchAVR C Runtime Library - Patches: patch #6418, Yet another delay routines


You are not allowed to post comments on this tracker with your current authentication level.

patch #6418: Yet another delay routines

Submitter:  Carlos Lamas <carloslamas>
Submitted:  Wed 13 Feb 2008 10:26:51 PM UTC
Category:  None Priority:  5 - Normal
Status:  None Privacy:  Public
Assigned to:  None Open/Closed:  Open

Sun 11 Oct 2009 02:31:31 PM UTC, comment #3: 

Rather than generating an error when an integer non-constant is passed the non-exact macros could form a loop around a constant delay.

#define _delay_ms(__ms)                                                      \
do {                                                                         \
    if (!__builtin_constant_p(F_CPU)) {                                      \
        _DELAY_EMIT_ERROR(__STRINGIFY(F_CPU)                                 \
                          " is not a constant for _delay_ms");               \
    } else if (__builtin_constant_p(__ms)) {                                 \
        _delay_f_ms(F_CPU, __ms);                                            \
    } else if ((__typeof__((_ms) + 0))0.25 == 0)  {                          \
        __typeof__((__ms) + 0) __ms2 = __ms;                                 \
        while (__ms2--) _delay_f_ms(F_CPU, 1);                               \
    } else {                                                                 \
        _DELAY_EMIT_ERROR(__STRINGIFY(__ms)                                  \
                          " is not a constant or integer for _delay_ms");    \
    }                                                                        \
} while (0)

Timothy Baldwin <timothyebaldwin>
Mon 01 Dec 2008 09:40:31 PM UTC, comment #2: 

I have pursued alternative methods to improve the accuracy of the delay functions.  Your work here is impressive, and my testing indicates that it functions as advertised.  I will be using your patch personally, and look forward to it being integrated.

Clarence Risher <sparr>
Mon 17 Mar 2008 02:29:25 PM UTC, comment #1: 

Following David Brown's suggestion of using __builtin_constant_p() GCC function to test the macro arguments I have uploaded a new version of the headers. The main changes are:

- Errors emitted are controlled and now error messages are clear. Extra lines of printed messages also help the IDEs to locate the source line of error in the C code.

- Argument range checking is performed on the delay time intervals.

- Comments were updated with the changes and some modifications were introduced for Doxygen compatibility.

- Some internal use macros called only once from __SHORT_DELAY() in the headers have been eliminated (moving the code to the caller) to reduce the number of macro definitions.

Everything else remains the same.

(file #15289)

Carlos Lamas <carloslamas>
Wed 13 Feb 2008 10:26:51 PM UTC, original submission:  

This code is proposed to replace actual avr-libc delay routines. Current delay routines in <util/basic_delay.h> and <util/delay.h> present several problems:

1) They require the optimization enabled to avoid floating point libraries code bloating the executable.

2) The arguments passed must be constant but the compiler does not warn the user when a variable is passed. This can also bloat the code with floating point libraries and delay's accuracy loss.

3) There is a lot of asymmetry between the functions used for microseconds and for milliseconds: the time is not continuous, the 1/10 millisecond precision is arbitrary (F_CPU value is not considered) and inaccurate, and delays are short for high frequency processors...


Problem 1. Can be solved eliminating temporary intermediate variables and letting the compiler to do all the arithmetics. If the variables are not defined the intermediate integer and floating point constant values do not need to be stored, even when optimization level is -O0. To accomplish this it's mandatory a conversion from inline function (the argument is an automatic storage class variable) to macro.

Problem 2. The proposed solution is to check the constant parameter passed against an inline assembler constraint in an empty dummy asm() instruction. This also requires to transform the inline function in a macro. Passing a variable as the argument to the macro generates an error a bit obfuscated.

Problem 3. The compiler can choose the delay with the minimum penalty in size. Frequency and time should be taken as a whole, i.e. the number of CPU cycles that must elapse to obtain the delay. And big sized delay loops can produce accurate delays by increasing the counter word size from 16 bit maximum to 24 bit and 32 bit.

Attached files

The new files <util/delay_basic.h> and <util/delay.h> are downwards compatible with currently existing routines.

Another two delay loop functions have been defined: _delay_loop3() and _delay_loop4() to get 24 bit and 32 bit counter values. The code size of this loops is somewhat big including compiler overhead but they allow really, really long delays.

Additionaly, constant argument versions delay loop macros were defined to reduce the code generated and minimize errors when optimization is disabled.

The core of these header files are two delay macros named _delay_cycles() and _delay_exact_cycles(). They do not depend on F_CPU and as such they are placed in delay_basic.h. They wrap to the shortest loop  suitable to obtain a delay in CPU cycles (_delay_cycles() accuracy is +/- 0.5 loop step size and _delay_exact_cycles() is +/- 0.5 CPU cycles). Single instruction sequences without loops are used for very short delays (less than 7 CPU cycles). _delay_cycles_exact() inserts padding instructions after the loops at the expense of increasing code size to obtain the best delay accuracy.

Padding instructions used in the code are NOP (1 word, 1 CPU cycle) and RJMP (1 word, 2 CPU cycles). LPM (1 word, 3 cycles) was discarded due to lack of documentation about the behaviour accessing inexistent Flash addresses and other possible fuses and lock bits issues. Also, LPM is not available in all the AVR devices.

The constraint 'd' was preferred to 'w' in 32 bit data sizes to facilitate to the compiler the allocation of the loop variable, at the expense of increasing the code in one instruction (sbiw could be used instead of subi + sbci). Internal constant loop version macros for optimization enabled use a different approach splitting the big data counters (24 bit and 32 bit) in two parts, with 'w' constraint applied only to the less significant 16 bit of the data. For the remaining data part (8 bit or 16 bit) is up to the compiler (constraint 'r') to decide the registers to be used. Optimization disabled counterparts avoid the compiler overhead previous to the loop (not fixed time) moving the counter precharge to the first loop instructions and the compiler overhead after the loop storing data in the temporary and zero registers (complete for loops 1 and 2, partial for loop 3, nothing for loop 4)

The code philosophy remains the same: despite of the increased code complexity in the header files the compiler performs all the arithmetics and the resulting delay code remains short. The only incompatibility can arise with the imposition of using constant values.

Interface summary <util/delay_basic.h>

static inline void _delay_loop_1(uint8_t __count);
static inline void _delay_loop_2(uint16_t __count);
static inline void _delay_loop_3(uint32_t __count);
static inline void _delay_loop_4(uint32_t __count);

#define _delay_cycles(__cycles)
#define _delay_exact_cycles(__cycles)

#define _delay_f_us(__freq, __us)
#define _delay_f_ms(__freq, __ms)
#define _delay_f_s(__freq, __s)

#define _delay_exact_f_us(__freq, __us)
#define _delay_exact_f_ms(__freq, __ms)
#define _delay_exact_f_s(__freq, __s)

Interface summary <util/delay.h>

#define _delay_us(__us)
#define _delay_ms(__ms)
#define _delay_s(__s)

#define _delay_exact_us(__us)
#define _delay_exact_ms(__ms)
#define _delay_exact_s(__s)

Note. Doxygen comments haven't been compiled/tested.

Carlos Lamas <carloslamas>


(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attached Files
file #15289:  delay2.tgz added by carloslamas (7KiB - application/x-gzip - Delay modified routines with __builtin_constant_p() checking)
file #15033:  delay.tgz added by carloslamas (6KiB - application/x-gzip - new header files <util/delay.h> and <util/delay_basic.h>)


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -email is unavailable- added by timothyebaldwin (Posted a comment)
  • -email is unavailable- added by sparr (Posted a comment)
  • -email is unavailable- added by carloslamas (Submitted the item)

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.


    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2008-03-17 carloslamas Attached File- Added delay2.tgz, #15289
    2008-02-13 carloslamas Attached File- Added delay.tgz, #15033

    Back to the top

    Powered by Savane 3.13.
    Corresponding source code