"wfi" on Teensy 4.0 stops millis()

defragster

Senior Member+
Using "wfi" on Teensy 4.0 1062 has been odd - in use since noted during Beta with link to NXP doc - finally found an example showing even when it 'works' - it breaks millis() and micros(). And it explains when it works as noted on T_3.x but not T_4 because millis() is not driven by an interrupt.

This example works because it was code for a forum post with a falling _isr() trigger. In adding to the code printing millis() shows it no longer changes - even after 5 minutes

What is the fix or alternative code to get "wfi" to generally work without explicitly setting up an interrupt workaround - which may still break millis()?

Code:
// https://forum.pjrc.com/threads/60313-Configuring-Extenal-Interrupts-(Teensy-LC)?p=234803&viewfull=1#post234803
volatile bool LED_State = LOW;
volatile uint32_t iCnt = 0;

void setup() {
	Serial.begin(115200);
	while (!Serial && millis() < 4000 );
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	pinMode(0, INPUT_PULLUP);
	attachInterrupt(digitalPinToInterrupt(0), startBit_isr, FALLING);

	pinMode(LED_BUILTIN, OUTPUT); // LED for debugging
	LED_State = HIGH;
	digitalWrite(LED_BUILTIN, LED_State);
}

uint32_t myiCnt = 0;
void loop() {
	if ( myiCnt != iCnt) {
		myiCnt = iCnt;
		Serial.printf("_isr() @%lums %luus [iCnt%lu]\n", millis(), micros(), iCnt);
	}
	[B]asm volatile("wfi");[/B]
}

void startBit_isr()
{
	LED_State = !LED_State;
	iCnt++;
	digitalWriteFast(LED_BUILTIN, LED_State);
}

Output from a series of presses - millis() never changes and micros() only varies by some limited small amount based on ARM_CNT changes:
T:\tCode\FORUM\ISR_LED\ISR_LED.ino Apr 2 2020 11:55:10
_isr() @412ms 412002us [iCnt1]
_isr() @412ms 412008us [iCnt2]
_isr() @412ms 412015us [iCnt3]
_isr() @412ms 412021us [iCnt4]
_isr() @412ms 412027us [iCnt5]

// 5-10 minutes later …

_isr() @412ms 412357us [iCnt55]
_isr() @412ms 412363us [iCnt56]
_isr() @412ms 412370us [iCnt57]

NOTE: This is running on T_4.0, when the same code runs on a T_3.6 it has no issue
 
Longer code with intervalTimer added - note I saw recently suggested a timer interrupt or something would keep "wfi" running where otherwise no interrupts occur to WAKE the T_4 - but it does not help millis().

Run this code with "wfi" commented and the prints of millis() tracks with the interval timer driven wCnt::
Code:
// https://forum.pjrc.com/threads/60313-Configuring-Extenal-Interrupts-(Teensy-LC)?p=234803&viewfull=1#post234803
// https://forum.pjrc.com/threads/60315-quot-wfi-quot-on-Teensy-4-0-stops-millis()?p=234808&viewfull=1#post234808
volatile bool LED_State = LOW;
volatile uint32_t iCnt = 0;
volatile uint32_t wCnt = 0;

IntervalTimer myTimer;

void setup() {
	Serial.begin(115200);
	while (!Serial && millis() < 4000 );
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	pinMode(0, INPUT_PULLUP);
	attachInterrupt(digitalPinToInterrupt(0), startBit_isr, FALLING);

	pinMode(LED_BUILTIN, OUTPUT); // LED for debugging
	LED_State = HIGH;
	digitalWrite(LED_BUILTIN, LED_State);
	myTimer.begin(wfiWake, 1000);  // blinkLED to run every 0.15 seconds
	[B]wCnt = millis();[/B]
}
void wfiWake() {
	wCnt++;
}

uint32_t myiCnt = 0;
void loop() {
	if ( myiCnt != iCnt) {
		myiCnt = iCnt;
		Serial.printf("_isr() @%lums %luus [iCnt%lu - wCnt%lu]\n", millis(), micros(), iCnt, wCnt);
	}
[B]	asm volatile("wfi");[/B]
}

void startBit_isr()
{
	iCnt++;
	digitalWriteFast(LED_BUILTIN, LED_State);
	LED_State = !LED_State;
}
 
Last edited:
I vaguely recall, that millis() is not based on periodic interrupt. In fact, for my loggers I had to remove wfi from loop() do ensure sufficient loop circles for disk writes.
 
Indeed it is NOT - There was a note to that effect recently - saying for WFI to work required some 'other' interrupt for it to wake. I had intermittent results over time - when the sketch Serial.print()'s 'right' it triggers a USB interrupt it seems then would wake - print and repeat … unless the timing was wrong.

That is interesting to know - but having millis() drop dead as a side effect was not yet noted that I saw. I'm not sure what triggers the millis() counter - but with WFI usage … it is nothing for a trigger? And without an overt using WFI is a hang.

Have pointed to a longer NXP App Note doc twice { this one : AN12085_LowPower.pdf ??? } with details on making WFI do something properly … a page or two for prep and exit around WFI as the basis of multiple power modes.
 
That means this "_VectorsRam[15] = my_systick_function;" code isn't getting run for some reason and EventResponder will also be disabled?
Code:
extern "C" void systick_isr(void)
{
	systick_cycle_count = ARM_DWT_CYCCNT;
	systick_millis_count++;
	MillisTimer::runFromTimer();
}
 
Yes, the SYSTICK does not wake the CPU, on IMXRT. NXP designed it this way.
Other interrupts can do that, and thats seems to be configurable(?) - It must be somewhere in the Bible (NXP RefManual) or ARM Architecture Manual, or..
 
The doc is : nxp.com/docs/en/application-note/AN12085.pdf

Doesn't look like it would offer any solution here - but it gives the proper way to get to 'System Idle' with WFI.

Dropping speed/voltage and clocks before WFI wouldn't help here and then waking to raise voltage/speed and clocks as needed would add some time - could do most of that time testing with set_arm_clock 600>132>600.

It does that - in addition to toggling some other bits before and after WFI to maximize power reduction.

But the problem given the non-waking interrupt as the base for millis() is the current form of asm'wfi' breaks millis and eventResponder and could lead to stalled/coma execution if used like in the T_3.x family.
 
USB activity can wake him up, so there's probably a way to do this with every interrupt... you could use a timer interrupt.
I had this on my todo list, but I didn't feel like looking for it yet.
 
sample code in p#2 above does wake with an interval timer - and it also wakes onpin interrupt - which is what I wrote for another thread forum answer when I decided to add WFI to it and saw millis() die.

The table in the doc says GPIO will wake: wakeup.png
 
Doesn't it wake with the GPIO Interrupt? (#P2)
What is "Other wake-up Source" ?

Yes samples as noted in p#10 were first tested on pin interrupt - because that is what the other forum post was about.

As far as 'other' … not sure … in the doc it notes:
o SW8 user key wake-up.
o GPT timer wake-up.

Not sure if there is any others ...
 
So you may need to use GPT or RTC to keep millis() running.
But I wonder for what that would be needed... :)
 
A short delay(#) like 'SNOOZE' like function that wraps 'wfi'. Rather than just 'wfi until interrupt' - it would be wfiNap(#) that repeats 'wfi' for a fixed time "#" in some fashion - though should return on a true 'waking interrupt' perhaps wfiNap(0)?

The RTC is not much use because it only exposes seconds - and will have to check if ARM_CNT stalls during 'wfi'. Would take some repeat timers to get to requested time - fix the systick_millis_count and return?
 
Perhaps micros() and millis() could be implemented on top of a GPT running at 1 MHz (using the peripheral clock, ipg_clk), so its counter is directly in microseconds, and wraps around every ~ 4295 seconds (71.5 minutes)?

Then, add an RTC interrupt every few seconds, maybe once a minute or so (anything from once per second to once every 2147 seconds would work), whatever is sensible to restrict the maximum duration of a single wfi. Have the default interrupt handler for that execute micros64(), discarding the result.

Finally, implement micros64() returning a 64-bit unsigned integer. It would read the 32-bit GPT counter, and compare its 8 high bits to the last stored 8 high bits. If they wrapped around, the 24-bit overflow counter is incremented. These two fields are packed in a single 32-bit word, which is stored atomically (exclusive store). Note that if micros64() gets interrupted by a call that does the same, it does not matter which one succeeds, as either one will yield correct results; as long as there is at least two micros64() calls during each GPT counter wraparound period. The function returns the combined 24+32 = 56-bit microsecond counter.

Then, micros() is just a wrapper that returns the low 32 bits of micros64(), and millis() returns the low 32 bits of (micros64()/1000).

This does add a bit of overhead to both millis() and micros() (especially the 64-bit division to millis()!), but as far as I can tell, it would solve this issue with minimal impact on existing code. Note that it would also make sense to implement the delay functions using the underlying micros64(), converting the duration of delay to 64-bit microseconds. Also, the GPT does not need to have an overflow interrupt, so it would not interfere with wfi (but you'd still need to use an RTC interrupt to limit wfi to a half hour or less; fifteen minutes or less to be extra careful).

The 56-bit microsecond counter only wraps every couple of millenia (256 microseconds ≃ 2283 years). After 4295 seconds (71 minutes, or a bit over an hour) of run time, millis() would no longer be micros()/1000, but that's because both millis() and micros() would increment at a steady rate and micros() wrap at 32-bit boundaries, without any kind of jumps.
 
Last edited:
FALSE :: "wfi" stops the processor - so it stops the interval timer! p#2 above only seemed to work because USB processing the .printf() resulted in a WAKE from wfi.
<<EDITING THIS>>

Changing to this with second "wfi" NEVER WAKES - this results in a COMA!!!!
>> WRONG - the code wasn't properly run and tested. It silently counts IntervalTimer 1ms ticks and only displays them on button interrupt. Pushing the button shows the timer is running as reported in posts above.


That was discovered when trying to get the time for clock speed changes. millis() appears to run well on an unchanged clock when no "wfi".
Changing clock when voltage and other changes are needed going LOW then HIGH back to 600 MHz seems to take 1.8 ms each cycle - so a clock change would give a 'sleep' of near 2ms minimum with clock drop, even if there is a way to assure the "wfi" won't cause a COMA.
>> This 'COMA' report also isn't right - the timer was running as " myTimer.begin(wfiWake, 1000000); " - so those interrupts were too few to get timely results!
Changing to : myTimer.begin(wfiWake, 1000); completes the test below in a timely fashion for the loops of 1,000

>> Using a proper timer freq this does show it takes about 1.8ms to drop and raise the CPU speed - but using 'wfi' does not stop IntervalTimer operation
I got it to WAKE using a Serial1.print - filling the FIFO, like USB - causes it to wake. Without the Serial1.print("1234567890"); shown below the Teensy 4.0 hibernates:
>> - It is true that the FIFO send interrupt does work to terminate the 'wfi'.
Code:
//
extern "C" uint32_t set_arm_clock(uint32_t frequency);
int32_t ii, tt, oc, wCnt = 0;
elapsedMillis aTime;
IntervalTimer myTimer;

void wfiWake() {
	wCnt++;
}
void setup() {
	// put your setup code here, to run once:
	Serial.begin(115200);
	Serial1.begin(2000000);
	myTimer.begin(wfiWake, 1000000);
	while (!Serial && millis() < 4000 );
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

	oc = F_CPU_ACTUAL;
}

#define CLK_BASE 	600000000
#define CLK_528 	528000000
#define CLK_132 	132000000
#define CLK_120 	120000000
#define CLK_32 		32000000
#define iiLOOPS		1000

void loop() {
	set_arm_clock(oc);
	aTime = 0;
	for ( ii = 0; ii < iiLOOPS; ii++ ) {
		set_arm_clock(CLK_528);
		set_arm_clock(CLK_BASE);
	}
	tt = aTime;
	Serial.printf("#%lu @528<>600 in %lu ms\n", ii, tt);

	set_arm_clock(oc);
	aTime = 0;
	for ( ii = 0; ii < iiLOOPS; ii++ ) {
		set_arm_clock(CLK_132);
		set_arm_clock(CLK_120);
	}
	tt = aTime;
	Serial.printf("#%lu @132<>120 in %lu ms\n", ii, tt);

	set_arm_clock(oc);
	aTime = 0;
	for ( ii = 0; ii < iiLOOPS; ii++ ) {
		set_arm_clock(CLK_120);
		set_arm_clock(CLK_BASE);
	}
	tt = aTime;
	Serial.printf("#%lu @120<>600 in %lu ms\n", ii, tt);

	set_arm_clock(oc);
	aTime = 0;
	for ( ii = 0; ii < iiLOOPS; ii++ ) {
		set_arm_clock(CLK_32);
		set_arm_clock(CLK_BASE);
	}
	tt = aTime;
	Serial.printf("#%lu @32<>600 in %lu ms\n", ii, tt);

	set_arm_clock(oc);
	aTime = 0;
	for ( ii = 0; ii < iiLOOPS; ii++ ) {
		set_arm_clock(CLK_BASE);
		Serial1.print("1234567890");
		asm volatile("wfi");
		set_arm_clock(CLK_BASE);
	}
	tt = aTime;
	Serial.printf("#%lu @600<>600 in %lu ms || WFI\n", ii, tt);

	set_arm_clock(oc);
	aTime = 0;
	for ( ii = 0; ii < iiLOOPS; ii++ ) {
		set_arm_clock(CLK_120);
		Serial1.print("1234567890");
		asm volatile("wfi");
		set_arm_clock(CLK_BASE);
	}
	tt = aTime;
	Serial.printf("#%lu @120<>600 in %lu ms || WFI\n", ii, tt);

	set_arm_clock(oc);
	aTime = 0;
	for ( ii = 0; ii < iiLOOPS; ii++ ) {
		set_arm_clock(CLK_32);
		Serial1.print("1234567890");
		asm volatile("wfi");
		set_arm_clock(CLK_BASE);
	}
	tt = aTime;
	Serial.printf("#%lu @32<>600 in %lu ms || WFI\n", ii, tt);

	set_arm_clock(oc);
	delay(5000);
	Serial.print("\n");
}
 
Last edited:
Updated p#17 - IntervalTimer does run across and wake 'wfi'! as originally tested and reported.

millis() as reported does lose time across the 'wfi' - but IntervalTimer runs well.

Updated above code to use IntervalTimer to measure time and print that and slipping millis during the testing - with the Serial1.print()'s removed.:
Code:
T:\tCode\T4\WFI_ClockSet\WFI_ClockSet.ino Apr  6 2020 23:50:13
#1000 @528<>600 in 1798 ms 	{millis=2150 | 2150}
#1000 @132<>120 in 107 ms 	{millis=2257 | 2257}
#1000 @120<>600 in 1817 ms 	{millis=4075 | 4075}
#1000 @32<>600 in 1857 ms 	{millis=5932 | 5932}
[B]#1000 @600<>600 in 999 ms || WFI 	{millis=5942 | 6931}
#1000 @120<>600 in 2000 ms || WFI 	{millis=7791 | 8931}
#1000 @32<>600 in 2004 ms || WFI 	{millis=9666 | 10935}[/B]

* the 'ms' timings are intervalTimer _isr 1 ms ticks, and on the right millis is the millis() reported time versus the
* the 600<>600 loses the most time with WFI because the clock change is a NOP going 600 to 600 MHz so the 'wfi' is really stopping millis()
>otherwise this shows the intervalTimer and millis() run unchanged as the set_arm_clock() is used for slower clocks - when 'wfi' isn't used.

NOTE: I edited the post #2 code to have the IntevalTimer prove it is alive with 500ms blink and print a '.' each second and then each minute (60K ms ticks) print the line like a button _isr does:
Code:
T:\tCode\FORUM\ISR_LED\ISR_LED.ino Apr  7 2020 00:45:17
............................................................
_wfiWake() @345ms 346000us [iCnt=0 - wCnt=60000]
............................................................
_wfiWake() @345ms 346000us [iCnt=0 - wCnt=120000]
............................................................
_wfiWake() @345ms 346000us [iCnt=0 - wCnt=180000]

That shows the 'wfi' has frozen the millis()and micros() count at 345 just after startup - even as time passes … now 10 minutes and running in SerMon. I should measure current to see the effect here and on p#17 code.
 
Last edited:
Was there any resolution to this issue?

I, too, would like to use WFI to help save some power, but it's painful to lose the functionality of millis(). Is there an alterative to WFI or an alternative to millis() that makes this problem go away?

Thanks,

Chip
 
Was there any resolution to this issue?
...
Chip

Hi Chip, did a quick play with this, then distracted, and this the first callback to it.

Github says this was a week ago {act 7/10/23?}: github.com/Defragster/TeensySketches/blob/main/WFIon1062_TickSet/WFIon1062_TickSet.ino

Ran it and saw mixed/unexpected results. The goal/plan was:
> start an RTC based wake _ISR()
> Execute 'wfi' - stopping the processor
----
Processor will wake on ANY 'real' interrupt - including the RTC_ISR()
When this happens the systick_millis_count will be stalled where it was when 'wfi' initiated the 'stop'
> a call to RTC that keeps time can get sync'd back to real time, but code above didn't get a good reference
==> As we know 'time is an illusion, lunchtime doubly so'
----

Looking at that code the first attempt was made to make 'time' relevant to 'one day of seconds' with: (tv.tv_sec % 86400)
Typing this perhaps:
> the whole of 'seconds to 1970' into a 64 bit value
> do {'that 64b#' * 1000}
> then taking the RTC's 'tv.tv_usec' add in the number of milliseconds that represents
> put the low 32 bits of that into systick_millis_count

-> that might keep millis() from jumping on wake and give it continuity to 1970
--> it would stay valid after setting until the next 'wfi'
--> but still wrap as normal when the 32b ticks overflows
-> but only when systick_millis_count is reset after wake from 'wfi', checking millis() without doing that would have it be 'stale' by the time 'wfi' stopped the processor?
-> Would also require 'correct' adjustment to the "systick_cycle_count = ARM_DWT_CYCCNT ( ??? )" value for micros() to be valid.
--> linked code looked really bad at this.

If that seems to encapsulate a solution - post if you try, or if noted as 'usable plan' I could get back to that here?
 
Code:
    // keep memory powered during sleep
    CCM_CGPR |= CCM_CGPR_INT_MEM_CLK_LPM;
    // keep cpu clock on in wait mode (required for systick to trigger wake-up)
    CCM_CLPCR &= ~(CCM_CLPCR_ARM_CLK_DIS_ON_LPM | CCM_CLPCR_LPM(3));
    // set SoC low power mode to wait mode
    CCM_CLPCR |= CCM_CLPCR_LPM(1);
    // ensure above config is done before executing WFI
    asm volatile("dsb");
    // sleep
    asm volatile("wfi");
 
Code:
    // keep memory powered during sleep
    CCM_CGPR |= CCM_CGPR_INT_MEM_CLK_LPM;
    // keep cpu clock on in wait mode (required for systick to trigger wake-up)
    CCM_CLPCR &= ~(CCM_CLPCR_ARM_CLK_DIS_ON_LPM | CCM_CLPCR_LPM(3));
    // set SoC low power mode to wait mode
    CCM_CLPCR |= CCM_CLPCR_LPM(1);
    // ensure above config is done before executing WFI
    asm volatile("dsb");
    // sleep
    asm volatile("wfi");

Interesting - just need a test sketch to see if that indeed makes the current 'sys_tick' into a real _ISR - and if it results in lower temp/current.

Given p#20 linked sketch updated to code that 'text' and it seems to be giving a better result:
Code:
extern "C" int _gettimeofday(struct timeval * tv, void *ignore __attribute__((unused)));
extern volatile uint32_t systick_millis_count;
extern volatile uint32_t systick_cycle_count;
void resetMMclocks() {
  _gettimeofday(&tv, &aV);
  uint64_t ms1970;;
  __disable_irq();
[B]  ms1970 = 1000 * tv.tv_sec + tv.tv_usec / 1000;
  systick_millis_count = ms1970;
  systick_cycle_count = ARM_DWT_CYCCNT - F_CPU_ACTUAL * 1000000.0 / tv.tv_usec;
[/B]  __enable_irq();
}

Sketch runs 10 times without clock correct after 'wfi' then does correction. Note RTC _ISR() running at 1/8'th second:
Code:
Millis=1932958047 [ms diff=125] Micros=222764800 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958047 [ms diff=0] Micros=222764800 deg  C=47.90 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958047 [ms diff=0] Micros=222764800 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958047 [ms diff=0] Micros=222764800 deg  C=47.90 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958047 [ms diff=0] Micros=222764800 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958047 [ms diff=0] Micros=222764800 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958048 [ms diff=0] Micros=222764854 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958048 [ms diff=0] Micros=222764982 deg  C=47.90 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958048 [ms diff=0] Micros=222765099 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958048 [ms diff=0] Micros=222765216 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
Millis=1932958048 [ms diff=0] Micros=222765344 deg  C=47.24 RTC time=Thu Jul 20 12:11:45 2023
[B]Millis=1932959422 [ms diff=1374] Micros=224139800 deg  C=47.24 RTC time=Thu Jul 20 12:11:46 2023[/B]
Millis=1932959547 [ms diff=125] Micros=224264800 deg  C=47.24 RTC time=Thu Jul 20 12:11:46 2023
Millis=1932959672 [ms diff=125] Micros=224389800 deg  C=47.24 RTC time=Thu Jul 20 12:11:47 2023
Millis=1932959797 [ms diff=124] Micros=224514800 deg  C=47.24 RTC time=Thu Jul 20 12:11:47 2023
Millis=1932959922 [ms diff=125] Micros=224639800 deg  C=47.24 RTC time=Thu Jul 20 12:11:47 2023
Millis=1932960047 [ms diff=125] Micros=224764800 deg  C=47.24 RTC time=Thu Jul 20 12:11:47 2023
Millis=1932960172 [ms diff=125] Micros=224889800 deg  C=47.90 RTC time=Thu Jul 20 12:11:47 2023
Millis=1932960297 [ms diff=125] Micros=225014800 deg  C=47.24 RTC time=Thu Jul 20 12:11:47 2023

Here is a snippet with it changed to 1Hz RTC_ISR {the 10 sec bold cusp is 20th second after not updating for first 10 seconds - so that '0 based' looks right too:
Code:
Millis=1933299673 [ms diff=0] Micros=564390086 deg  C=47.24 RTC time=Thu Jul 20 12:17:27 2023
Millis=1933299673 [ms diff=0] Micros=564390203 deg  C=47.24 RTC time=Thu Jul 20 12:17:27 2023
Millis=1933299673 [ms diff=0] Micros=564390331 deg  C=47.90 RTC time=Thu Jul 20 12:17:27 2023
Millis=1933299673 [ms diff=0] Micros=564390448 deg  C=47.24 RTC time=Thu Jul 20 12:17:27 2023
[B]Millis=1933310672 [ms diff=10999] Micros=575389800 deg  C=47.24 RTC time=Thu Jul 20 12:17:38 2023
[/B]Millis=1933311672 [ms diff=1000] Micros=576389800 deg  C=47.90 RTC time=Thu Jul 20 12:17:39 2023
Millis=1933312672 [ms diff=999] Micros=577389800 deg  C=47.24 RTC time=Thu Jul 20 12:17:40 2023
Millis=1933313672 [ms diff=1000] Micros=578389800 deg  C=47.24 RTC time=Thu Jul 20 12:17:41 2023
Millis=1933314672 [ms diff=1000] Micros=579389800 deg  C=47.90 RTC time=Thu Jul 20 12:17:42 2023
 
It doesn't save as much power as the default sleep mode (because obviously the CPU clock isn't halted like it otherwise would be) but still saves a bit/lowers the temperature. Not sure if the part about keeping memory powered is strictly required for Teensy or if it only applies to synchronous external memory (SDRAM etc).
 
That p#21 code works to wake each millisecond!

Testing on T_4.1 on socketed breakout so temp not showing difference the bare T_4.0 did, and not measuring current.

This code allows testing it: https://github.com/Defragster/TeensySketches/blob/main/WFIon1062/WFIon1062.ino
It is PRE_RTC and uses IntervalTimer to wake in the alternative
Code:
void setup() {
  Serial.begin(9600);
  while (!Serial);  // wait for serial connect
  if (CrashReport) Serial.print( CrashReport );
  Serial.println("\nTeensy 4.x WFI for lower Temp/Power");
}

extern "C" uint32_t set_arm_clock(uint32_t frequency);
#include "intervaltimer.h"
IntervalTimer Alpha;
void testAlpha() {
  Alpha.end(); // stop the timer
}
bool doneOnce = false;
void loop() {
#if 1 // DEBUG show periodic wake and temp to monitor
  pinMode( 13, OUTPUT );
  digitalToggle( 13 );
  Serial.printf( "   deg  C=%2.2f  ms=%lu\n" , tempmonGetTemp(), millis() );
  delayMicroseconds(100); // USB print interrupts will wake WFI so delay until print complete
#endif
  if ( F_CPU_ACTUAL > 30000000 ) // T_4.0 at 35C==95F w/WFI
    set_arm_clock(24000000);
#if 1 // To wake from WFI require an explicit interrupt
#if 0 // To wake from WFI require an intervaltimer interrupt
  if ( !doneOnce ) {
    Serial.println( "   wake with intervaltimer" );
    delayMicroseconds(100);
    doneOnce = true;
  }
  Alpha.begin( testAlpha, 2000000 ); // T_4.0 at 45C==113F
  asm volatile( "wfi" );  // WFI instruction will start entry into STOP mode
  Serial.print( "iT:" );
#else
[B]  if ( !doneOnce ) {
    Serial.println( "   wake with SYS_TICK as real ISR" );
    delayMicroseconds(100);
    doneOnce = true;
    // keep memory powered during sleep
    CCM_CGPR |= CCM_CGPR_INT_MEM_CLK_LPM;
    // keep cpu clock on in wait mode (required for systick to trigger wake-up)
    CCM_CLPCR &= ~(CCM_CLPCR_ARM_CLK_DIS_ON_LPM | CCM_CLPCR_LPM(3));
    // set SoC low power mode to wait mode
    CCM_CLPCR |= CCM_CLPCR_LPM(1);
    // ensure above config is done before executing WFI
    asm volatile("dsb");
  }
  asm volatile( "wfi" );  // WFI instruction will start entry into STOP mode
  Serial.print( "ST:" );
[/B]#endif
#else
  delay(200);  // T_4.0 at 60C==140F
#endif
}
 
re p#42:

plugged in T_4.0 at 23.02°

Running no 'wfi': 30.5° {30.28...30.94} now rising to some 31.60

As written - unfair compare as systick waking 1000/sec not 1-8 times per sec with RTC doing full stop and printing each time as written
> Temp the same and it has turned up this PC's fans processing 1000 SerMon msgs per second

Funny though, returning to RTC based 'wfi' wake temp climbed to 38 ???

Return to p24 code and quickly to 36 from 41 and dropping to 34 ... 32.92 ...

Something else afoot? ... return to RTC sketch and instantly 35 and climbing ... 37 ... 39 ...
> It is reading RTC time - but sleeping/Stopped a full second?
 
Back
Top