PDA

View Full Version : Delay(0) - Teensyduino 1.12 - BUG?



matheusbrat
02-07-2013, 06:51 PM
Hello Paul,

Delay(0) puts Teensy in a infinite loop;


void setup() {
delay(5000);
Serial.begin(57600);
Serial.println("oI");
}

void loop() {
Serial.println("AAA");
delay(1);
}

If you replace delay(1) to delay(0) the Teensy freeze

From pins_teensy.c


void delay(uint32_t ms)
{
uint32_t start = micros();

while (1) {
if ((micros() - start) >= 1000) {
ms--;
if (ms == 0) break;
start += 1000;
}
yield();
}
}

You can see that ms-- will trigger then ms will have the value -1 and that will keep going. I don't think this should be the correct behavior. Maybe an if on the begin is a solution? Anyway, delay(0) doesn't make sense I know, it is just a suggestion, otherwise I think it should be well documented that delay receives values starting at 1.


void delay(uint32_t ms)
{
if (ms == 0)
break;
uint32_t start = micros();

while (1) {
if ((micros() - start) >= 1000) {
ms--;
if (ms == 0) break;
start += 1000;
}
yield();
}
}
}

Jp3141
02-07-2013, 08:27 PM
Bit me too.

Can't you do:
if (ms-- == 0) break;

instead of

ms--;
if (ms == 0) break;

PaulStoffregen
02-07-2013, 10:30 PM
Opps. I've switched the order, so the zero check is before the decrement.



void delay(uint32_t ms)
{
uint32_t start = micros();

while (1) {
if ((micros() - start) >= 1000) {
if (ms == 0) break;
ms--;
start += 1000;
}
yield();
}
}


Looks like I'll need to push out 1.13 sooner than expected.....

matheusbrat
02-08-2013, 05:18 AM
I'm not complaining about your solution but if I get it right, it will wait 1ms before it breaks so delay(0) and delay(1) are the same. I know that this 1 ms is pretty much nothing, I'm just saying that it is not what you ask is what you get...

Does it worth saving 1 comparison + break? I don't know. It is up to you...

Keep the good job Paul. I will keep trying to improve it as well.

Have a good one!

:D

Jp3141
02-08-2013, 06:34 AM
Does this work ?


void mydelay(uint32_t ms) {
ms = micros()+ms*1000ul;
while (micros() < ms);
}

I think all these implementations have the bug that since micros() rolls over every 2^32 us (i.e. 71.x minutes), if the delay+micros() overflows, you will actually get zero delay for that call.

brianb00
09-08-2014, 05:51 AM
Hi, This roll over issue scares me. I use delay() in many spots in my code. As well I use the millis() function to measure time and then time events within the main loop. I have, on rare occasions, seen processor hangs, where rare can be up to 24 hours of continuous operation. As yet I have not been able to track them down, they could be due to many issues.

That said, is there a history of hangs when timing events using the millis() dor delay() functions ?

Regards,
Brian

PaulStoffregen
09-08-2014, 06:18 AM
This roll over issue scares me.

TL;DR = use elapsedMillis and elapsedMicros, which properly handle the internal roll-over.

Or you can write rollover-proof code yourself if you're careful.

This always works, if "previousMillis" is unsigned and "threshold" is less than half the maximum integer



if (millis() - previousMillis > threshold) {

}


You don't have to take my word for it. Just run this sketch to verify that substracting unsigned integers does indeed properly handle rollover.



void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("Rollover Test");
}

unsigned long previous = 0xFFFFFFF0;
unsigned long rightnow = 0xFFFFFFF0;

void loop() {
Serial.println(rightnow - previous);
rightnow++;
delay(250);
}


You'll see the number printed increments, starting at zero, and it keeps going up by 1 as it passes 16, where "rightnow" rolls over. Even as it prints very large numbers, you'll see they already always correctly incrementing and showing the elapsed time since start, even with rollover.

There are many intuitive ways that do NOT work. A common mistake involves computing the future target and then comparing the current value. But if you store the start time and subtract it from the current time, rollover is automatically handled, because the result of the substraction rolls over the same way, always giving the right result (assuming the result it under half the numerical range).

Or you can use the elapsedMillis and elapsedMicros types. They do this internally, always correctly, so you don't have to think about it or worry about incorrect rollover handling.

brianb00
09-08-2014, 06:32 AM
[QUOTE=PaulStoffregen;54259]TL;DR = use elapsedMillis and elapsedMicros, which properly handle the internal roll-over.





if (millis() - previousMillis > threshold) {

}


Thanks Paul,

I believe all my timing compares are done as you described. However, tomorrow I will pour over the code and review all for consistency. Your reply is a great help.

Brian

brianb00
09-08-2014, 04:23 PM
Hi Paul,
Regarding teensy 2.0++, what state is the interrupt system in at boot time once a simple hello world program is loaded ? Example, are int0 or int1 enabled ? Should they be pulled up if not in use ?

The Data sheet states: 1. When the BOOTRST Fuse is programmed, the device will jump to the Boot Loader address at
reset,

In your implementation is BOOTRST programmed, or is there a register programmed that would vector interrupts to locations other than what is shown in the Data sheet ?

Regards,

Brian