8 years, 2 months ago.

Timing with Deepsleep + Interrupt

Hello,

I'm using the WakeUp library to get my KL25Z to wakeup after deepsleep. I'm keeping track of time using clock() which gives me the time in steps of 10 ms. However, since the frequency of the KL25Z is lowered in deepsleep I have to compensate for lost time. I got it to work just fine, but now I've introduced a _button to interrupt the deepsleep and now I'm losing track of time. My code:

#include "mbed.h"
#include "mbed_debug.h"
#include "WakeUp.h"

DigitalOut _led(PTB0);
InterruptIn _button(PTA4);
uint32_t t_lost = 0, t;

void keyPressed( void )
{
    // calculate the lost time again
    // t_lost -= ???;
    debug( "-button pressed-\r\n" );
}

int main(void)
{
    _button.mode( PullUp ); 
    WakeUp::calibrate(); 

    while( 1 )
    {
        // awake
        _led = 1;
        wait( 5 );
        t = clock() + t_lost;
        debug( "Time: %.2f\r\n", t/100.0 );

        // asleep
        _led = 0;
        _button.rise( &keyPressed );
        WakeUp::set_ms( 5000 );
        deepsleep();
        _button.rise( NULL );

        // compensate for the 'lost' time during deepsleep
        t_lost += 5000 / 10;
        t = clock() + t_lost;
        debug( "Time: %.2f\r\n", t/100.0 );
    }
}

This gives me something like this:

Time: 5.00
Time: 10.01
Time: 15.02
Time: 20.03
Time: 25.04
Time: 30.05
Time: 35.06
-button pressed-
Time: 40.09
Time: 45.11
-button pressed-
Time: 50.13
Time: 55.15

I know that during deepsleep the clock() still works but in a much lower frequency and I should substract those few count from the t_lost += 5000 / 10; line. But that's for later. My real problem is now that when I press the button, it wakes up from deepsleep but my time still increases with 5 s... Is there a way to find out how long my KL25Z was in deepsleep?

Thank you,

Bob

1 Answer

8 years, 2 months ago.

In deepsleep the clock is completely disabled on the KL25. Also a note: If you wake up from anything besides the regular WakeUp event, you need to call set_ms(0);. This restores the timer to its original state (if you don't use Tickers/Timeouts you don't need to do this).

Two options I see:

One is using the RTC. If you have a crystal for it, and got it running, deepsleep should not affect it.

The other one is using the low-power timer that WakeUp also uses. You will need to check the reference manual on how to do it exactly, but you can check how long passed according to the ticker. What I think works is:

uint32_t val_ms = (1000 * 5 * LPTMR0->CNR) / LPTMR0->CMR;

This does it using integer calculations, you can do the same by first converting them to floats so you have more precission.

CNR is the current count of the timer. CMR is the count at which it will wake up. So the ratio of those two is the part of your sleep time which passed. Multiplying it by your sleep time (5000ms), gives the time in ms that passed. Since an integer can't be a fraction, I first multiply with 5000 before dividing.

Thank you very much! I can see how that should have worked, but unfortunately I can't get CNR to give me the right data. CMR is indeed 5000, but no matter how long I wait before waking up my system, CNR gives me 98 back... Maybe I should read CNR at a different location / time in my script? Maybe it's not correct to do it in the keyPressed function?

InterruptIn _button(PTA4);
...
void keyPressed( void )
{
    // calculate the lost time again
    debug( "-button pressed (CNR: %d)- \r\n", LPTMR0->CNR );
}
...
_button.rise( &keyPressed );
...

Any advice is appreciated, thanks in advance!

posted by Bob Giesberts 26 Oct 2016

Late reaction, but what I got from reference manual:

Quote:

The CNR cannot be initialized, but can be read at any time. On each read of the CNR, software must first write to the CNR with any value. This will synchronize and register the current value of the CNR into a temporary register.

So try writing a random value to it first, and then reading it.

posted by Erik - 06 Nov 2016