_delay_us problem - Page 1
Forum section: electronics / general

author: m.m.m
author_rank: Regular Contributor
timestamp: September 22, 2014, 12:01:45 pm
content: hi, I wanted to send a signal using a 433MHz transceiver and a atmega32a, so I wrote this code with fuses set to 8MHz:Code:#include <avr/io.h>#include <util/delay.h>#define F_CPU 8000000UL;int main(void) {DDRD=0xFF;while(1){PORTD=0xFF;_delay_us(685);PORTD=0x00;_delay_us(1300);PORTD=0xFF;_delay_us(735);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(1300);PORTD=0xFF;_delay_us(740);PORTD=0x00;_delay_us(1300);PORTD=0xFF;_delay_us(735);PORTD=0x00;_delay_us(641);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1430);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(1300);PORTD=0xFF;_delay_us(760);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1400);PORTD=0x00;_delay_us(640);PORTD=0xFF;_delay_us(1410);PORTD=0x00;_delay_us(1300);PORTD=0xFF;_delay_us(685);PORTD=0x00;_delay_ms(100);}}but when I see it with my logic analyzer, all the delays are wrong, for example for the first ON time which should be 685 microseconds, I get 85 uS! what is wrong? thanks.

author: Kremmen
author_rank: Super Contributor
timestamp: September 22, 2014, 12:09:07 pm
content: Check the avr-libc doc page in the net. the maximum delay you can get from _delay_us is 768 / F_CPU (in MHz). So your max will be 768/8 i.e. far shorter than any of those in your code. The compiler will silently replace invalid calls with _delay_ms but obviously your mileage has varied significantly ...

author: m.m.m
author_rank: Regular Contributor
timestamp: September 22, 2014, 12:14:14 pm
content: Quote from: Kremmen on September 22, 2014, 12:09:07 pmthanks a lot, so now I should either change the F_CPU or use _delay_ms instead, am I right?

author: m.m.m
author_rank: Regular Contributor
timestamp: September 22, 2014, 12:22:56 pm
content: thanks a lot man, I fixed it and it worked!

author: Jeroen3
author_rank: Super Contributor
timestamp: September 22, 2014, 01:58:00 pm
content: A better way would be to use the spi peripheral set to a bit timing of the shortest pulse required.This will just shift the bits to the transmitter, not requiring these ambiguous and ugly delays.Please note the delays will be wrong if you have any interrupts.

author: dannyf
author_rank: Super Contributor
timestamp: September 22, 2014, 04:20:03 pm
content: "685 microseconds, I get 85 uS"685 / 85 = 8.Maybe you clicked the /8 clock setting - your true cpu speed is 1Mhz.

author: mikerj
author_rank: Super Contributor
timestamp: September 22, 2014, 10:58:23 pm
content: Quote from: dannyf on September 22, 2014, 04:20:03 pmWhy would running the CPU 8 times slower yield delays that are 8 timesshorter?The answer has already been given; thedelay_us functionhas an inherent limit on the achievable delay for a given clock speed.

author: bktemp
author_rank: Super Contributor
timestamp: September 23, 2014, 08:39:51 am
content: The documentation clearely says, it automatically uses _delay_ms instead of _delay_us when the time is to long, so it should work upto the _delay_ms limits.The true problem is here:#include <util/delay.h>#define F_CPU 8000000UL;My guess: F_CPU is defined somewhere else and defaults to 1MHz. Therefore all delay calculations are done for 1MHz.Swap both lines and it should work.

author: alank2
author_rank: Super Contributor
timestamp: September 23, 2014, 12:20:40 pm
content: The built in functions for delay are not that great, especially in terms of accuracy with smaller delays. An example might be that you ask for a uS delay that is less than one clock cycle and it delays three clock cycles instead. I've come up with a header I use which uses the internal function to generate an exact number of clock cycles. The floating point and calculations in the code below will get optimized out by the compiler and leave you with the delay only.Also, make certain your F_CPU is correct, if it is wrong, your delays will be wrong.Code:#ifndef CDELAY_H#define CDELAY_H#define Delay_ns(__ns) if((unsigned long) (F_CPU/1000000000.0 * __ns) != F_CPU/1000000000.0 * __ns)\__builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000000.0 * __ns)+1);\else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000000.0 * __ns))#define Delay_us(__us) if((unsigned long) (F_CPU/1000000.0 * __us) != F_CPU/1000000.0 * __us)\__builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000.0 * __us)+1);\else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000.0 * __us))#define Delay_ms(__ms) if((unsigned long) (F_CPU/1000.0 * __ms) != F_CPU/1000.0 * __ms)\__builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000.0 * __ms)+1);\else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000.0 * __ms))#define Delay_s(__s) if((unsigned long) (F_CPU/1.0 * __s) != F_CPU/1.0 * __s)\__builtin_avr_delay_cycles((unsigned long) ( F_CPU/1.0 * __s)+1);\else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1.0 * __s))#endif