This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Low Power mode on sensortag

Other Parts Discussed in Thread: CC2650

Hello!

I started learning programming contiki os, using sensortag. So now i trying to make cc2650 sleep in standby mode.

I found this module for lpm - https://github.com/contiki-os/contiki/blob/master/cpu/cc26xx-cc13xx/lpm.h 

But i dont understand how to use it. 

I need to be in standby mode all time, exept when reed relay sensor have impulse.

I wrote a simple code:

PROCESS_THREAD(blink_example, ev, data)
{
  PROCESS_BEGIN();
  lpm_init();
  while(1) {
    PROCESS_WAIT_EVENT_UNTIL(ev == sensors_event &&
    (data == &button_sensor || data == &reed_relay_sensor));
    if (data == &reed_relay_sensor){

      //here i want to wakeup

      GetImpulse();

     lpm_drop();

     //after execute GetImpulse function i want to go to Satndby mode. How can i do it?
    }
  }
  PROCESS_END();
}

In this example sensortag doing nothing. But if a delete lpm_init(); and lpm_drop(); - GetImpulse() is working (Leds on and off). So do ypu have any example how to use lpm for sensortag or just cc2650.

Thank you!

  • As I know, you don't have to do this in your thread. It's been implemented in main function of Contiki-main.c.
  • Yes, i found it in code Contiki-main.c. But how to make it work? My sensortag using about 8,4 mA, but in standby mode it should be 1 µA.
    If i cant manually on standby mode, what should i do in my code to make it go to standby mode?
  • Do you turn off sensors in your application when your sensortag goes to sleeping mode?
  • No. If i'll turn off sensors how can i go to active mode when reed sensor give 1?
    Ok, how to turn off all sensors, but wake up of reed sensor?
  • I suggest you to study very-sleepy-demo in contiki\examples\cc26xx\very-sleepy-demo folder first.
  • I tryed to study very-sleepy-demo, but it doesnt work!

    When i load it to sensortag - and trying to POST mode=1&interval=30&duration=10 so Copper said - Server not responding. But another example - er-rest-example - work. So it's mean that 6lbr work. But why very-sleepy-demo not? I dont know. 

    And i didnt find here how to make cc2650 sleep and wakeup after reed sensor get 1.

    Is very-sleepy-demo is only one example? Is there another example? Or may be you can explain me how to work with standby/active mode?

  • Sometimes the latest code on Contiki Github doesn't work well. You can try to pull earlier version to test it. You can also study cc26xx-web-demo.
  • I am using Contiki OS on CC2650. The problem is that it is entering in the sleep mode, but instantly comes out of sleep mode. So it is spending less time in sleep mode.
    I tried with disabling sensors, increasing the scanning time for RDC, increasing max SLEEP time, etc. but there is same behaviour.
    I tried with very-sleepy-demo also, in that it make the radio off for sometime, but with that solution also, i don't hope I can achieve battery life of 1 year.
    I want controller to be in sleep for minimum of 60 seconds.

    Can anybody tell me how I can increase the time interval for timers which are responsible for controller wake-up...
  • I suggest you to post this issue on Contiki Github.
  • Hi Dimitri,

    Have you solved the problem with the lpm.h?
    I have kind of the same problem.
  • Hello!

    Yes, I solved problem. Contiki is very intelligent OS. So by default it go to sleep if controller do nothing. But it doesnt switch off transfering data. So to make sensortag deep sleep you should mac.off(). After calling this method sensortag resourses by coap will not be available. But if something in pins happen (reed sensor will get impulse or button will be pressed) sensortag will wake up. And if you will want to transfer data to you listener by coap you should first turn on transfering mac.on()

  • Hi again,

    I still have the problem that my program does not exsecute the tasks it should when there are the functions lpm_init() and lpm_drop().
    Could you maybe post some code?
  • Theck this example in attachment. Here uses LowPowerMode and Coap example

    exampleSleep.txt
    #include "contiki.h"
    #include "ti-lib.h"
    #include "sys/stimer.h"
    #include "dev/leds.h"
    
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    
    #include "scimage/scif.h"
    #include "net/netstack.h"
    
    //sc files
    #include  "aux-ctrl.h"
    #define BV(x)   (1<< (x))
    
    
    //coap files
    #include "rest-engine.h"
    #include "er-coap.h"
    
    //led driver
    #include "led.h"
    
    #include "net/ipv6/sicslowpan.h"
    
    extern resource_t res_leds, res_toggle, res_hello, res_event, res_event_sc, res_radio;
    
    static aux_consumer_module_t sc_test_aux = {NULL, AUX_WUC_SMPH_CLOCK};
    
    
    #define MAC_CAN_BE_TURNED_OFF  0
    #define MAC_MUST_STAY_ON       1
    static struct stimer st_min_mac_on_duration;
    static struct stimer st_duration;
    static struct stimer st_interval;
    static struct etimer et;
    static uint8_t state;
    
    #define LOOP_INTERVAL       (CLOCK_SECOND * 1 * 1) // cycle main loop
    #define PERIODIC_INTERVAL         CLOCK_SECOND
    #define INTERVAL    5 * 60 // Sleep time sec
    #define DURATION    10 // Normal time sec
    #define KEEP_MAC_ON_MIN_PERIOD 5 /* secs */
    
    #define STATE_NORMAL           0
    #define STATE_NOTIFY_OBSERVERS 1
    #define STATE_VERY_SLEEPY      2
    
    
    
    void
    print_network_status(void)
    {
      int i;
      uint8_t state;
      uip_ds6_defrt_t *default_route;
      uip_ds6_route_t *route;
      printf("--- Network status ---\n");
      /* Our IPv6 addresses */
      printf("- Server IPv6 addresses:\n");
      for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
        state = uip_ds6_if.addr_list[i].state;
        if(uip_ds6_if.addr_list[i].isused &&
           (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
            printf("-- ");
          uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
          printf("\n");
        }
      }
      /* Our default route */
      printf("- Default route:\n");
      default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose());
      if(default_route != NULL) {
          printf("-- ");
        uip_debug_ipaddr_print(&default_route->ipaddr);;
        printf(" (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval);
      } else {
          printf("-- None\n");
      }
      /* Our routing entries */
      printf("- Routing entries (%u in total):\n", uip_ds6_route_num_routes());
      route = uip_ds6_route_head();
      while(route != NULL) {
          printf("-- ");
        uip_debug_ipaddr_print(&route->ipaddr);
        printf(" via ");
        uip_debug_ipaddr_print(uip_ds6_route_nexthop(route));
        printf(" (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime);
        route = uip_ds6_route_next(route);
      }
      printf("----------------------\n");
    }
    /*---------------------------------------------------------------------------*/
    static void
    print_local_addresses(void)
    {
      int i;
      uint8_t state;
    
      printf("Server IPv6 addresses:\n");
      for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
        state = uip_ds6_if.addr_list[i].state;
        if(uip_ds6_if.addr_list[i].isused &&
           (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
            printf(" ");
          uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
          printf("\n");
        }
      }
    }
    /*---------------------------------------------------------------------------*/
    
    /*---------------------------------------------------------------------------*/
    /*
     * If our preferred parent is not NBR_REACHABLE in the ND cache, NUD will send
     * a unicast NS and wait for NA. If NA fails then the neighbour will be removed
     * from the ND cache and the default route will be deleted. To prevent this,
     * keep the MAC on until the parent becomes NBR_REACHABLE. We also keep the MAC
     * on if we are about to do RPL probing.
     *
     * In all cases, the radio will be locked on for KEEP_MAC_ON_MIN_PERIOD secs
     */
    static uint8_t
    keep_mac_on(void)
    {
      uip_ds6_nbr_t *nbr;
      uint8_t rv = MAC_CAN_BE_TURNED_OFF;
    
      if(!stimer_expired(&st_min_mac_on_duration)) {
        printf("MAC_MUST_STAY_ON first\n");
        return MAC_MUST_STAY_ON;
      }
    
    #if RPL_WITH_PROBING
      /* Determine if we are about to send a RPL probe */
      if(CLOCK_LT(etimer_expiration_time(
                    &rpl_get_default_instance()->probing_timer.etimer),
                  (clock_time() + PERIODIC_INTERVAL))) {
        rv = MAC_MUST_STAY_ON;
        printf("MAC_MUST_STAY_ON PROBING\n");
      }
    #endif
    
      /* It's OK to pass a NULL pointer, the callee checks and returns NULL */
      nbr = uip_ds6_nbr_lookup(uip_ds6_defrt_choose());
    
      if(nbr == NULL) {
        /* We don't have a default route, or it's not reachable (NUD likely). */
        rv = MAC_MUST_STAY_ON;
        printf("MAC_MUST_STAY_ON no default route\n");
      } else {
        if(nbr->state != NBR_REACHABLE) {
          rv = MAC_MUST_STAY_ON;
          printf("MAC_MUST_STAY_ON not NBR REACHABLE\n");
        }
      }
    
      if(rv == MAC_MUST_STAY_ON && stimer_expired(&st_min_mac_on_duration)) {
        stimer_set(&st_min_mac_on_duration, KEEP_MAC_ON_MIN_PERIOD);
        printf("Set keep mac on period timer\n");
      }
    
      return rv;
    }
    /*---------------------------------------------------------------------------*/
    static void
    switch_to_normal(void)
    {
      state = STATE_NOTIFY_OBSERVERS;
    
      /*
       * Stay in normal mode for 'duration' secs.
       * Transition back to normal in 'interval' secs, _including_ 'duration'
       */
      stimer_set(&st_duration, DURATION);
      stimer_set(&st_interval, INTERVAL);
    }
    /*---------------------------------------------------------------------------*/
    static void
    switch_to_very_sleepy(void)
    {
      state = STATE_VERY_SLEEPY;
    }
    
    PROCESS(coap_server_process, "coap server process");
    AUTOSTART_PROCESSES(&coap_server_process);
    
    /*****************************************************************************/
    
    
    /*---------------------------------------------------------------------------*/
    PROCESS_THREAD(coap_server_process, ev, data)
    {
      uint8_t mac_keep_on;
    
      PROCESS_BEGIN();
    
      printf("Long sleep test\n");
    
      etimer_set(&et, LOOP_INTERVAL);
      stimer_set(&st_duration, DURATION);
      stimer_set(&st_interval, INTERVAL);
    
      led_init();
      state = STATE_NORMAL;
    
      aux_ctrl_register_consumer(&sc_test_aux);
      scifInit(&scifDriverSetup);
      scifExecuteTasksOnceNbl(BV(SCIF_NEW_TASK_TASK_ID));
      leds_off(LEDS_GREEN);
      rest_init_engine();
      rest_activate_resource(&res_toggle, "actuators/toggle");
      rest_activate_resource(&res_leds, "actuators/leds");
      rest_activate_resource(&res_event, "test/event");
      rest_activate_resource(&res_radio, "test/rssi");
      rest_activate_resource(&res_hello, "test/hello");
      rest_activate_resource(&res_event_sc, "test/sc");
    
      switch_to_normal();
    
      while(1) {
    
        PROCESS_YIELD();
        printf("[%lu] periodic wakeup\n", clock_seconds());
        print_network_status();
        print_local_addresses();
        if (ev == PROCESS_EVENT_TIMER && (data == &et || data == &st_duration || data == &st_interval)) {
            printf("ET periodic\n");
    
            mac_keep_on = keep_mac_on();
            printf("mac_keep_on is %d\n", mac_keep_on);
    
            if(mac_keep_on == MAC_MUST_STAY_ON || state != STATE_VERY_SLEEPY) {
              leds_on(LEDS_GREEN);
              NETSTACK_MAC.on();
              printf("we need to be ON because we not in very sleepy - %d\n", state);
            }
    
            if(state == STATE_NOTIFY_OBSERVERS) {
              printf("Notify observers\n");
              res_event.trigger();
              state = STATE_NORMAL;
            }
    
              if(state == STATE_NORMAL) {
                if(stimer_expired(&st_duration)) {
                  printf("st_duration expired, go to very sleepy - %d\n", state);
                  stimer_set(&st_duration, DURATION);
                  switch_to_very_sleepy();
                }
              } else if(state == STATE_VERY_SLEEPY) {
                if(stimer_expired(&st_interval)) {
                    printf("st_interval expired, go to notify - %d\n", state);
                    switch_to_normal();
                }
              }
    
    
            if(mac_keep_on == MAC_CAN_BE_TURNED_OFF && state == STATE_VERY_SLEEPY) {
              leds_off(LEDS_GREEN);
              NETSTACK_MAC.off(0);
              printf("MAC off - %d\n", state);
            } else {
              leds_on(LEDS_GREEN);
              NETSTACK_MAC.on();
              printf("MAC on - %d\n", state );
            }
    
            etimer_set(&et, LOOP_INTERVAL);
        }
    
      }
      PROCESS_END();
    }

  • Hello Dmitrii,

    Please have a look in file github.com/.../contiki-main.c
    Here in while loop in main() function, there are below lines :
    while(1) {
    uint8_t r;
    do {
    r = process_run();
    watchdog_periodic();
    } while(r > 0);

    /* Drop to some low power mode */
    lpm_drop();
    }

    Here you can see, contiki os itself take it to lpm_drop(). So no need to explicitly call lpm_drop() in your code.
    But as soon as it goes in sleep mode, it is woken up by some events or interrupts.

    So to reduce the power consumption, you cam make radio off, and make radio on only when some data needed to be sent.

    Regards,
    Saurabh