contiki-os / contiki

The official git repository for Contiki, the open source OS for the Internet of Things
http://www.contiki-os.org/
Other
3.72k stars 2.58k forks source link

High power consumption with CC26xx Very Sleepy Demo when radio is re-enabled #1629

Open cedric-d opened 8 years ago

cedric-d commented 8 years ago

During some power consumption tests with CC2650STK, it appears that the very sleepy demo seems to not have exactly the expected behavior.

When the node is in normal mode, there is 8 current peaks per second which should be the RDC channel check. As soon as the node enters very sleepy mode, these peaks disappear. After the sleep interval is over, the node goes back to normal mode and the 8 peaks per second re-appear. However, during this switch, the node continuously has peaks as high as RDC channel check ones during almost 1 second (this duration depends on the interval: the greater the sleep is, the longer lasts this period of high consumption).

It seems that when the radio is switched on, ContikiMAC does all the channel checks that were not done because the radio was explicitly switched off.

I tried to modify ContikiMAC to skip the cycles with a start time in the past (see this commit) and the high consumption period went away. However I don't exactly understand all the code so I am not confident with my patch.

Here comes some captures of the power measurement to help understand (the time is on the horizontal axis, the complete width represents 1 second; the power drawn, measured on a shunt, is on the vertical axis).

bkozak-scanimetrics commented 8 years ago

Actually, looking at this code it seems to me that the transition between off and on in ContikiMAC is very buggy.

Very interesting things can happen if we call turn_off while powercycle is in the middle of it's loop or if we happen to leave ContkiMAC off for a long time (half of the clock wrap-around period or more).

It seems to me that the correct way to handle this transition is:

  1. When we call turn_off we cancel the rtimer (this would require some new synchronization logic to handle correctly I think).
  2. We force the radio off as we do now
  3. When we later call turn_on we reset the power_cycle proto-thread before scheduling the next powercycle

This will fix the issue you are seeing as well as some other problems that might occur rarely when transitioning between on and off states. I don' think this will be an easy fix however.

If you want to have an immediate solution for this, on the other hand, allow me to shamelessly plug my proposed re-implementation of ContikiMAC at #1549. I believe the code at this PR will fix all of your issues and I would appreciate if you would try it out and leave a comment on the github discussion so as to possibly motivate the maintainers to merge it sooner.

cedric-d commented 8 years ago

Sadly I don't feel confortable enough with Contiki to write a correction to ContikiMAC. I will try to have a look at your re-implementation.

darkopetrovic commented 8 years ago

If that could help, I've made the following modifications to turn on/off ContikiMAC correctly:

static int
turn_on(void)
{
    /* Prevent to jump in the middle of the protothread
     * and start properly a new RDC cycle. */
    PT_INIT(&pt);

  if(contikimac_is_on == 0) {
    contikimac_is_on = 1;
    contikimac_keep_radio_on = 0;
    rtimer_set(&rt, RTIMER_NOW() + CYCLE_TIME, 1,
               (void (*)(struct rtimer *, void *))powercycle, NULL);
  }
  return 1;
}

and then:

#define enableRDC()             NETSTACK_RDC.on()

/* When turned off, ContikiMAC doesn't kill automatically the next wake-up.
 * Therefore we disable the incoming wake-up from ContikiMAC with rtimer_arch_schedule(0).
 * Furthermore, we call rtimer_isr() to properly finish the LPL cycle. */
#define disableRDC(x)           NETSTACK_RDC.off(x);\
                                rtimer_arch_schedule(0);\
                                rtimer_isr()
bkozak-scanimetrics commented 8 years ago

If that could help, I've made the following modifications to turn on/off ContikiMAC correctly

It's a start but your code to cancel rtimer won't work. Firstly, rtimer_isr() is only available on some platforms. Secondly, all sorts of things can go wrong if you happen to call disableRDC right before the RTC time hits zero. Thirdly, the rtimer needs to be cancelled before disabling the RDC otherwise the powercycle function could still turn the radio right back on after you turn it off. There is some complicated asynchronous code at work here so there's probably a few more problems that I haven't even noticed yet.

To fix this without introducing a platform generic way to disable interrupts would be a real challenge. Even with the ability to disable interrupts it'll still be easy to get wrong.