Teensy-LC and delay()

Status
Not open for further replies.
My current project needs a startup delay, to allow some external electronics to stabilise before the main code runs. I'm having trouble with "delay()" though.

The code below works fine on a Teensy 3.1, but fails to introduce any delay on a Teensy-LC ( most of the time it fails ... very occasionally it works though ... weird ).

Code:
int LED_pin = 13;

void setup(void)
{
	Serial.begin(9600);
	digitalWrite(LED_pin,LOW);
	pinMode(LED_pin,OUTPUT);	
	delay(3000);
	Serial.println("Hello");	
}

void loop(void)
{
	digitalWrite(LED_pin,HIGH);
	delay(500);
	digitalWrite(LED_pin,LOW);
	delay(500);
}

Since this is always run from a reset, the workaround below works fine, but I'd like to be able to use delay() with confidence.

Code:
int LED_pin = 13;

void setup(void)
{
	Serial.begin(9600);
	digitalWrite(LED_pin,LOW);
	pinMode(LED_pin,OUTPUT);	
	while ( millis() < 3000 )
	{
	}
	Serial.println("Hello");	
}

void loop(void)
{
	digitalWrite(LED_pin,HIGH);
	delay(500);
	digitalWrite(LED_pin,LOW);
	delay(500);
}

Any ideas ?
 
Not sure to what effect but you need to swap two (Mode above Write) lines and try with this added line as well to show how long it waits:

Code:
void setup(void)
{
	Serial.begin(9600);
[B]	pinMode(LED_pin,OUTPUT);	[/B]
	digitalWrite(LED_pin,LOW);
	delay(3000);
	Serial.println("Hello");	
[B]	Serial.println(millis());	[/B]
}

edit : Also starting with digitalWrite(LED_pin, HIGH ); will let you see when it really starts the delay.
 
Last edited:
Are you certain the delay is not working?

I would try this:

Code:
int LED_pin = 13;

void setup(void)
{
	Serial.begin(9600);
	Serial.println("Pre-delay:" + String(millis());
	digitalWrite(LED_pin,LOW);
	pinMode(LED_pin,OUTPUT);	
	delay(3000);
	Serial.println("Post-delay:" + String(millis());
	Serial.println("Hello");	
}

void loop(void)
{
	digitalWrite(LED_pin,HIGH);
	delay(500);
	digitalWrite(LED_pin,LOW);
	delay(500);
}

This should tell you exactly how many milliseconds are running before and after delay.

You also mentioned that this is always run from a "reset". do you mean pressing the button on the Teensy? That button is a programming button, and not a reset button.

Hope this helps!
T
 
defragster :

1) You should always set the desired state of an output before you enable it, otherwise you could get a ( very brief ) unwanted pulse if you're not careful. That might be enough to launch the missile, or whatever.
2) setting the LED to ON is a good idea, but of course you need that to happen after the delay statement, so that LED ON signifies delay finished.
3) I've tried your suggestions in various permutations, several times for each code revision, but the delay only worked once out of the whole lot.

tenkai :

I am using the Arduino IDE and the Teensyloader, as you might expect. Click on "Upload" and at the end of the process the Teensy will reset. The other way to reset is to unplug it ( the USB lead, the only source of power ), and plug it back in again. I'm not pressing the button !

In either case, you will never see the first message because a) "Upload" takes control of the serial port so you can't open the "Serial monitor" until the upload has ended ... you might have a few tens of milliseconds to open the utility before the message has finished sending, but you need a good reaction speed and a lot of luck ... or b) if you reset by unplugging / reconnecting, you need precise synchronisation to plug in / wait for Windows to recognise a serial device and make the port available / then click the "Serial monitor" menu immediately afterwards. I have not had any luck with this method.

Finally, I don't see your second message either, because the delay is not working at all ... so the second message has disappeared like the first one did, before I could click to open the "Serial monitor".

I have had success by using "while millis() < 3000" before your first print statement, then "delay(3000)" between the first and second print statements ( the delay does seem to work reliably in this case ). Not sure why though. I'll do some more research tomorrow.

Thanks to you both for your ideas.
 
1) You should always set the desired state of an output before you enable it, otherwise you could get a ( very brief ) unwanted pulse if you're not careful. That might be enough to launch the missile, or whatever.

Good info - had not considered the state on power up - for the LED I never cared - but I always try to go ON ASAP so I can tell when setup() starts as the LED can show long before USB, especially when not connected.

I powered up my LC and crafted this example - after my sample output - that indeed shows a problem as far as I can tell. The Delay FAILS on the first call then Works properly on the second instance, and may intermittently work on the first instance:

Pre-delay:0
Delay Time Millis (should be 3000+):22
Delay Time Millis:3000
Delay Time Micros:3011
Post-delay:6033
Hello

edit> I powered the LC a couple times and the first LED flash is brief and should be 3 seconds, and the Serial output the last six times repeated as "Delay Time Millis (should be 3000+):20". After UPLOAD - or BUTTON for another Upload - the number repeats as shown at '22'.

Code:
unsigned long  StartedZero = 0;
unsigned long  Started = 0;
unsigned long  DelayedBad = 0;
unsigned long  Delayed = 0;
unsigned long  DelayedMics = 0;

void setup(void)
{
  Serial.begin(9600);
  digitalWrite(LED_BUILTIN, HIGH);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  StartedZero = Started = millis();
  delay(3000);
  DelayedBad = millis() - Started;
  digitalWrite(LED_BUILTIN, LOW);
  Started = millis();
  delayMicroseconds(3000000); 
  DelayedMics = millis() - Started;
  digitalWrite(LED_BUILTIN, HIGH);
  Started = millis();
  delay(3000);
  Delayed = millis() - Started;
  while (!Serial && (millis() <= 6000));

  Serial.println("Pre-delay:" + String(StartedZero) );
  Serial.println("Delay Time Millis (should be 3000+):" + String(DelayedBad) );
  Serial.println("Delay Time Millis:" + String(Delayed) );
  Serial.println("Delay Time Micros:" + String(DelayedMics) );
  Serial.println("Post-delay:" + String(millis()));
  Serial.println("Hello");
}

void loop(void)
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
}
 
Last edited:
I have a second LC and it showed the following on the first run after programming and then showed BAD on re-powering it - as it did after re-powering it twice more:
Pre-delay:0
Delay Time Millis (should be 3000+):3000
Delay Time Millis:3000
Delay Time Micros:3010
Post-delay:9010
Hello
Pre-delay:0
Delay Time Millis (should be 3000+):22
Delay Time Millis:3000
Delay Time Micros:3010
Post-delay:6033
Hello

I unwrapped a fresh 3.1 and over 5 re-powerings and it always runs right.
 
Many thanks for your detailed investigations ... your results confirm what I found : a) delay() used in the 'setup' section seems to be unpredictable / unreliable, and b) that your code above and my first listing both seem to work just fine on the Teensy 3.1.

The delay while booting is reliably achieved using (while millis()<something ) so I can use that, but the question is really whether delay() is reliable when used in the main 'loop' ... later code in my project will require this ... I don't expect great accuracy, but I do need it to work reliably. I guess I could use the 'while' method but it needs a few extra steps every time.

Thanks again.
 
I expect Paul might look at resolving this as it seems to indicate at least some unknown initial starting condition from LC power up, as I only saw it fail once and then seemingly work normally - though I didn't do any extensive tests in that direction.

I also demonstrated the usage of delayMicroseconds(3000000); that may work when delay doesn't, though it shows the odd consistency of running long by 10-11 milliseconds on the LC [consistently 5 millis over on 3.1], when a proper millisecond delay times out exactly (do they use different clock math?).

I just changed the loop() delay to run and test against 3000 and report when they don't do that until later tomorrow. Again on restart after the Upload to the LC the first delay(3000) worked at 3000, on a power off restart it returned to 22.
 
This sounds like something for Paul!

But if it were me, knowing that delay code is simply calling micros().
Code:
void delay(uint32_t ms)
{
	uint32_t start = micros();

	if (ms > 0) {
		while (1) {
			if ((micros() - start) >= 1000) {
				ms--;
				if (ms == 0) return;
				start += 1000;
			}
			yield();
		}
	}
}
I would have a tendency of thinking that maybe the initial call to micros is returning a bogus value.
So what I would do, is first see at the start of setup, I would do my own call to micros and save it away. After doing that does the call to delay work? I would then at some point print out the value of the initial call to micros as well as maybe the current one. Does it look valid? Or maybe was there some initial value put in like 0xffffffff that maybe waiting for first interrupt to increment to 0? ...
 
Thanks KurtE. I don't propose to do any further testing, but here is an interesting observation ( comments in code explain it all, I think ). Hopefully enough to point someone smarter than me in the right direction. It looks like the very first call to delay() must specify more than 344 mS, then subsequent delays appear to work fine ! Weird !

I have removed any calls to the Serial library to make sure that wasn't part of the problem. When connected to power, LED should be off for 344 or 345mS, then on for 3 seconds, then off for 3 seconds, then flash once a second ( 50% on, 50% off ).

Code:
int LED_pin = 13;

void setup(void)
{
	digitalWrite(LED_pin,LOW);
	pinMode(LED_pin,OUTPUT);
	
	// DUMMY delay below will effectively clear the bug if long enough duration
	delay(344);
	// 344 is NOT enough to kill the bug
	// 345 IS enough to kill it, so the next delay WILL work
	
	digitalWrite(LED_pin,HIGH);
	pinMode(LED_pin,OUTPUT);
	delay(3000);
	// the LED should have been on for 3 seconds
	// if the first delay does not kill the bug, it only flashes very briefly
	
	digitalWrite(LED_pin,LOW);
	delay(3000);
	// the LED should have been off for 3 seconds ...
	// always works because the previous delay was more than 344mS
}

void loop(void)
{
	digitalWrite(LED_pin,HIGH);
	delay(500);
	digitalWrite(LED_pin,LOW);
	delay(500);
}
 
I've put this on my list of bugs to investigate.

At the moment, I'm working on the SD library issues when playing multiple audio files... so it might be a week or so until I get to this.
 
A possible issue with this is that micros() doesn't return an ever-increasing number -- it wraps around at 2^32 = 4.3 G, or about 80 minutes. If you happen to call a delay when micros is within 1000 of that point, start will be a large number (e.g. 4.3G), and then when micros() wraps, you'll have a delay of ~ 80 minutes before the ms counter decrements.
 
As I mentioned, I think there is a simple Init issue. Here is a quick test program:
Code:
void setup() {
  // put your setup code here, to run once:
  uint32_t t1, t2, t3, t4;
  t1 = micros();
  delay(200);
  t2 = micros();
  delay(300);
  t3 = micros();
  delay(1000);
  t4 = micros();
  
  Serial.begin(38400);
  Serial.printf("%d %d(%d) %d(%d) %d(%d)\n", t1, t2, (t2-t1)/1000,
      t3, (t3-t2)/1000, t4, (t4-t3)/1000);

  Serial.printf("%x %x(%x) %x(%x) %x(%x)\n", t1, t2, (t2-t1)/1000,
      t3, (t3-t2)/1000, t4, (t4-t3)/1000);

}

void loop() {
  // put your main code here, to run repeatedly:

}
The results printed out are:
Code:
89464499 1448(4205504) 301459(300) 1301476(1000)
5551eb3 5a8(402bc0) 49993(12c) 13dbe4(3e8)
 
So your first delay(200) isn't actually 200 ms but 4,205,504 ms ? (about 70 minutes) -- this is close to 2^32.

Funny that the first micros returned 0x5551eb3 -- maybe it inited at 0x555.... ?
 
I am not worried about Paul's code having issue with wrap around, I am quite sure he has done it properly with unsigned math...

But, there is an initial setup issue. It had to be either the system tick counter not being properly setup to 0, or the system register SYST_CVR
is giving a bogus value until it gets the first tick which resets it to a proper value. I first did a hack to set the tick counter to 0 just before the call to setup. This had no effect.

I then went into the file mk20dx128.c into the procedure ResetHandler, and around line 721 I cleared out CVR. The new line plus a few before looks like:
Code:
	// initialize the SysTick counter
	SYST_RVR = (F_CPU / 1000) - 1;
	SYST_CSR = SYST_CSR_CLKSOURCE | SYST_CSR_TICKINT | SYST_CSR_ENABLE;
	SYST_CVR = 0; // KJE - see if init to some value helps/hurts
I reran my test case and I now see:
Code:
4088 204102(200) 504113(300) 1504122(1000)
ff8 31d46(c8) 7b131(12c) 16f37a(3e8)
Which looks a lot better!

Again not sure if this is the best way to fix it, but it looks like it might work an should hopefully give Paul and head start

Kurt
 
Sounds good to me, I will hack mine back up, (switch the two lines) and verify it still works. May then create a pull request, although maybe just as easy for Paul to make the one line change then go through PR...
 
Changed the order and verified that it still works. I went ahead and created a pull request.

Kurt
 
ARM document http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Bhccjgga.html tips suggests:

1. Program the reload value.
2. Clear the current value.
3. Program the Control and Status register.

FWIW, I looked at systick init firmware on other ARM critters. DUE and pyboard/STM32F4DISCOVERY follow the 3 steps. maple does not set the current value.

The android arch linux kernel also follows the 3 steps

I saved the current value SYST_CVR into a long at reset/boot and printed it in a sketch. For teensy 3.0 and 3.1 the value is 0, however for LC the value is 0x29A08... hence the difference. After power cycle, LC value is 0xFFFCBE

just for the record, the maple's initial value is 0
 
Last edited:
Status
Not open for further replies.
Back
Top