Reference time after sleep mode 2

Hello,
I get some trouble to calculate the sleep duration after waking (by a pin interrupt or the sleep timer ) from sleep mode 2, the timers are stopped when entering to sleep mode and i try to capture the value of the sleep timer(on WORTIME0 and WORTIME1 register) after waking up but the values seem to be wrong.
Any idea ?
Thanks !
Nathan

Hello, Nathan.

We haven’t really done anything with the sleep modes on the CC2511F32 so I don’t know what to tell you. If you could simplify your code to the simplest thing possible that demonstrates the problem and post it here, I might be able to help. Your code should all be in one function if possible, and tell us how the actual behavior is different from the expected behavior.

–David

 systemInit();
 radioQueueInit ();

init_wixel() // initialize Interrupt + pin state + sleep timer

while(1)
    {

        if(!pin_interrupt) // pin_interrupt = 1 when an interrupt occurred on a chosen pin 
        {
        reset_sleep_interrupt(time_period); //  prepare the sleep timer  to wake up in 10s
        switchToRCOSC();
        sleep_process(); // Enter on sleep mode
        }

        if(Timer_interrupt || pin_interrupt)  // Timer_interrupt = 1 if the sleep Timer woke up the wixel
        {
             //prepare message
              uint32 time = getMs();
              data_messages[0] = WORTIME1; 
              data_messages[1] = WORTIME0;
              data_messages[2] = time >> 24;
              data_messages[3] = time >> 16;
              data_messages[4] = time >> 8;
              data_messages[5] = time;

              send_mail(data_messages); //transmit message

              Timer_interrupt = 0;
              pin_interrupt = 0;
        }
    }

By doing this I obtain the following result :

If i wait one period with just the sleep timer interrupt :
data_message =
0 0 0 0 0 46
wait 10 seconds
data_message =
0 0 0 0 0 97
The difference between the two times is only 51ms instead of 10s. The timer used by getMs() is stopped during the sleep mode.
So i can’t use it to determine how long the wixel was sleeping (If a pin interrupt woke up the wixel )

So i tried to use the WORTIME0 and WORTIME1 register to determine the sleep timer value :
data_message =
0 0 0 0 40 196
I wait 5 seconds and I generate the pin_interrupt
data_message =
0 2 0 0 40 247

In the second message WORTIME1 = 0 and WORTIME0 = 2
This correspond to 2/32 (32 is the resolution I choose for the sleep timer) = 0.0625 s instead 5s

If i wait 8s i get the same results : WORTIME1 = 0 and WORTIME0 = 2
So i can’t use this too. Maybe I’ m not reading the right registers.

I found a workaround by sending the computer time to the wixel but i would like to find an intern solution to be more independent of the computer.

This is an interesting problem, and something I would like to be able to do with the wixel, but I don’t think you’ve supplied enough information to allow others to figure out what is wrong.
Exactly how are you initializing and starting the timer?
What do you do in the interrupt routines?
Does the timer run as expected if the processor doesn’t sleep (i.e. you do something else for 10 s)?

I read in the datasheet http://www.ti.com/lit/ds/symlink/cc2511f32.pdf page 123 a note:

Note: The Sleep timer should not be used
in active mode

So that could explain why when I read the value of WORTIME1 and WORTIME0 I dont get what I expected.

I get page 9 :
PM2/3->Active Mode
Digital regulator off. HS RCOSC and high speed crystal
oscillator off. 32.768 kHz XOSC or low power RCOSC
running (PM2). No crystal oscillators or RC oscillators
are running in PM3.

The timer used by getMs() is stopped, because the hight speed oscillators are off in PM2.
The sleep timer seems to be the only one which could work in PM2, that is why I try to read the values of it’s registers.

So I have no idea to calculate the duration of a sleep, when the wixel is woken up by another interruption than the sleep timer interruption.

Thanks, I missed the warning about not using the timer in active mode, but I think they must mean to not use the wake-up interrupt (makes sense!). It seems clear from the example code that the counter keeps incrementing in active mode.

However, please post how are you initializing, starting the timer and entering sleep mode. Also on page 123 of the data sheet is this cautionary note:[quote]Entering PM{0 - 2} and/or updating EVENT0
has to be aligned to a positive edge on the
32 kHz clock source. The following code
examples should be used in order to update
EVENT0 and/or entering PM{0 - 2} correctly:[/quote]

The code that follows on pages 123&124 shows you how to do all this properly. Did you use that code?

void sleep_process()
{
    unsigned char temp;
    // Store current DMA channel 0 descriptor and abort any ongoing transfers,
    // if the channel is in use.
    unsigned char storedDescHigh = DMA0CFGH;
    unsigned char storedDescLow = DMA0CFGL;
    DMAARM |= 0x81;
    // Update descriptor with correct source.
    // NB! Replace &PM2_BUF with &PM3_BUF if powermode 3 is chosen instead.
    dmaDesc[0] = (unsigned int)& PM2_BUF >> 8;
    dmaDesc[1] = (unsigned int)& PM2_BUF;
    // Associate the descriptor with DMA channel 0 and arm the DMA channel
    DMA0CFGH = (unsigned int)&dmaDesc >> 8;
    DMA0CFGL = (unsigned int)&dmaDesc;
    DMAARM = 0x01;
    ////////////////////////////////////////////////////////////////////////////
    // NOTE! At this point, make sure all interrupts that will not be used to
    // wake from PM are disabled as described in the "Power Management Control"
    // chapter of the data sheet.
    // The following code is timing critical and should be done in the
    // order as shown here with no intervening code.
    // Align with positive 32 kHz clock edge as described in the
    // "Sleep Timer and Power Modes" chapter of the data sheet.
    temp = WORTIME0;
    while(temp == WORTIME0);
    // Make sure XOSC is powered down when entering PM{2 - 3} and that the
    // flash cache is disabled.
    // NB! Replace 0x06 with 0x07 if power mode 3 is chosen instead.
    MEMCTR |= 0x02;
    SLEEP = 0x06;
    // Enter power mode as described in chapter "Power Management Control"
    // in the data sheet. Make sure DMA channel 0 is triggered just before
    // setting PCON.IDLE.  

    __asm nop __endasm;
    __asm nop __endasm;
    __asm nop __endasm;
    if(SLEEP & 0x03)
    {
    __asm mov 0xD7,#0x01 __endasm;// DMAREQ = 0x01;
    __asm nop __endasm;
    // Needed to perfectly align the DMA transfer.
    __asm orl 0x87,#0x01 __endasm; // PCON |= 0x01;
    __asm nop __endasm;
    }
    // End of timing critical code
    ////////////////////////////////////////////////////////////////////////////
    // Enable Flash Cache.
    //MEMCTR &= ~0x02;
    boardClockInit();
    // Update DMA channel 0 with original descriptor and arm channel if it was
    // in use before PM was entered.
    DMA0CFGH = storedDescHigh;
    DMA0CFGL = storedDescLow;
    DMAARM = 0x01;

}

ISR(P0INT, 0)
{
    P0IFG = 0;   // Clear the flags so this interrupt doesn't run again.
    P0IF = 0;
    pin_interrupt = 1;
    SLEEP &= 0xFC; // Not required when resuming from PM0

}


ISR(ST, 0)
{
    // Clear IRCON.STIF (Sleep Timer CPU interrupt flag)
    IRCON &= 0x7F;
    // Clear WORIRQ.EVENT0_FLAG (Sleep Timer peripheral interrupt flag)
    // This is required for the CC111xFx/CC251xFx only!
    WORIRQ &= 0xFE;
   // STIE=0;
    Timer_interrupt = 1;
        // Clear the SLEEP.MODE bits, because an interrupt can also occur before
    // the SoC has actually ent ered PM. If this interrupt occurs in between the
    // three NOPs (that is; before the corresponding interrupt blocking has
    // actually taken effect) in Figure 2, then this clearing of the SLEEP.MODE
    // bits will ensure that the application does not enter PM{1 – 3}.
    SLEEP &= 0xFC; // Not required when resuming from PM0
}


void reset_sleep_interrupt(uint16 period)
{
    uint8 temp;
    WORCTRL = (WORCTRL|0x02) & (~0x01); ///Resolution of the timer = 1/32s
    WORCTRL |= 0x04;
    temp = WORTIME0;
    while(temp == WORTIME0); // Wait until a positive edge
    temp = WORTIME0;
    while(temp == WORTIME0); // Wait until a positive edge
    WOREVT1 = period >> 8; // Set EVENT0, high byte
    WOREVT0 = period;
}

Most of the code come from the data-sheet and the errata note due to a bug when the component woke up. They tell more about this in the Power Modes subject

On page 46 of the data-sheet we can see that the WORTIME0 an the WORTIME1 register have the retention status so they are normally not reset after PM2.
I don’t think that the problem come from the initialization of the sleep timer because the sleeping mode working well and woke up with a correct duration. I have the feeling that the sleep timer registers(WORTIME0 and WORTIME1) are reset after entering the normal mode.

I just find the solution.
If we want to read the correct values of WORTIME0 and WORTIME1 you need to be on a positive edge of the clock so:

    temp = WORTIME0;
    while(temp == WORTIME0);
    sleep_duration = WORTIME0;
    sleep_duration |= WORTIME1 << 8;

works.