Reducing power consumption for ble mesh sensor server node using LPN mode

Hi, 

I am using nrf mesh sdk v5.0.0 and am using sensor server model example to build our own application on top of it. SOC we are using is  nRF52832.  I have enabled the LPN mode in the example and I am also able to establish friendship with a nearby friend node. And am also receiving messages intended to the LPN node when the LPN node polls its friend node. The purpose for LPN node is to reduce battery consumption by disabling the scanner. But the device is consuming a solid 5 - 8 mA after establishing friendship. Is it possible to reduce the battery consumption in the micro amperes range. Any guidance on how to achieve it would be really great. I am also interfacing an LED, I2C sensor and a switch with the SOC. Before and after establishing friendship, I am seeing same amount of current being consumed. 

Parents
  • Hi Hariharan, 

    Could you describe how did you do the test ? How did you do provisioning ? 


    Have you tested with the LPN example with no modification ? In the example the power consumption should drop down to few uA after it provisioned and get a friendship. 

    Which current do you see exactly after you establish friendship ? Have you verified that the CPU was not being kept awake by other modules ? 

  • I am provisioning the sensor node using an ESP32(acting as a provisioner). Once the provisioning and model configuration is done, I am initiating the friendship establishment procedure. The current consumption goes as low as 150ua after establishing friendship. But it increases to 3ma after publishing data once. And it should return to low power consumption mode right? But its not. The sensor node is constantly consuming 3ma after publishing. I dont know why this is happening. Can you please guide me?

  • Hi Hariharan, 

    Could you please give more detail on your observation. How did you know that the node is polling the friend node for every one or two seconds ? 
    I am curious on how you do publishing. There could be a chance that the CPU was not put to sleep after publishing. 

    Have you tried to test with our LPN example without modification ?

  • Hi Hung. 

    I am saying that the node is polling the friend node for every one or two seconds because the two events showed in the attachment are occuring and the corresponding logs are printed on the serial terminal.

    And I am curious about when this event occurs(attached in the screenshot below) in runtime?

    I am just setting the model publication state using an ESP32(provisioner) and once the model publication is set by the provisioner, a callback is called periodically for the set publish period. The CPU should be going back to sleep after publishing right? But its not. I don't know why it behaves that way. Could you please guide me if I missed anything in configuration? 

    I will try the LPN example now and get back to you shortly.

  • Hi Hariharan, 

    The LPN node is put to sleep when the mesh stack finished processing and it will return to the main loop which calls sd_app_evt_wait();
    The NRF_MESH_EVT_READY_TO_POWER_OFF event is not really related to the LPN feature of put the CPU to sleep when there is no activity. '

    It's about putting the device to POWER OFF , and you need to close down mesh stack before enter power off. So when you receive NRF_MESH_EVT_READY_TO_POWER_OFF  you can turn off the chip (System OFF , not CPU sleep) 

    I suspect that the higher power consumption may have something to do with the NRF_LOG that you are using. Is there any reason you can't use the __LOG via RTT like what we use in the LPN example ? 

  • Why do you think NRF_LOG may have something to do with higher power consumption? I am using NRF_LOG because we have developed our custom sensor board with nRf52832. We only have TX pin for logging in runtime. That's why I have used NRF_LOG.  As you will see in the video attached as URL below, current consumption goes around 150ua once friendship is established. But once sensor data is published once after model publication is set, the current consumption is in constant 3ma and above. I think the LPN node is not put to sleep after data is published once through the "app_sensor_get_cb()" callback function. Is the application is not returning back to the sd_app_evt_wait() in the main thread? Is there a chance that any interrupt is not cleared after data is published once?

    I am establishing a friendship with a friend node only after model publication is set by the provisioner. After model publication is set, the sensor node initiates the friendship procedure.

    https://www.kapwing.com/videos/63aed5592e16220088250022

  • Hi Hariharan, 


    Have you tested with the LPN example ? and measure the current consumption on the example ? 
    150uA is too low for the CPU (when active CPU consumes about 3mA-4mA), so I suspect it could be something else, UART can be the case. If a pin has a pull up and it set to low, it will draw some current.

    If you can test with the LPN example and achieve low power consumption when periodically sending some dummy data, you can try to compare with your application and see why it doesn't work as it should. 

Reply
  • Hi Hariharan, 


    Have you tested with the LPN example ? and measure the current consumption on the example ? 
    150uA is too low for the CPU (when active CPU consumes about 3mA-4mA), so I suspect it could be something else, UART can be the case. If a pin has a pull up and it set to low, it will draw some current.

    If you can test with the LPN example and achieve low power consumption when periodically sending some dummy data, you can try to compare with your application and see why it doesn't work as it should. 

Children
  • Yeah sure. I will try it with the LPN example. In my application, I am also reading battery voltage using adc and using i2c to read data from sensor. Should I disable the adc interface and i2c interface every time the data is read and enable it like every time I want to read battery voltage and sensor data?

  • Hi Hariharan, 
    In theory if a peripheral is not active it shouldn't consume power consumption. But for testing I would suggest to disable them one by one (not use them at all, not initialize ) and check if the power consumption goes down. Only wake up and send dummy data. So we can narrow down where the issue is. 

  • Hi Hung Bui,

    I tried the LPN example and the current consumption was in the range 150ua. And it was working as expected. After publishing, it went back to the low power state. 

    I tried disabling all the peripherals in my own application which I written over sensor_server example with LPN mode enabled and logging enabled using NRF_LOG_INFO, I observed the same behavior as LPN example. Only when I enable the peripherals, the current consumption is going to 3ma constant. 

    Peripherals used in my application: SAADC, I2C. 

    I am enabling the peripherals only in the callback which is called periodically to publish sensor data and disabling them immediately once data is published. But the peripherals are not disabled properly as my current consumption was a constant 3ma and above. Please guide me to correct sequence which I am using to enable and disable the peripherals, if its wrong.

    Sequence for i2c:

    //1. Code used to initialize and enable the i2c peripheral during startup
        err_code = nrf_drv_twi_init(&m_twi, &twi_lm75b_config, twi_handler, NULL);
        nrf_delay_ms(20);
        APP_ERROR_CHECK(err_code);
      
        NRF_LOG_INFO("Initializatiion completed!!!");
    
        nrf_drv_twi_enable(&m_twi);
        
    //2. I am disabling the i2c peripheral once firendship is established. 
            nrf_drv_twi_disable(&m_twi);
        
    //3. Code used in periodic callback to read data from i2c sensor 
        nrf_drv_twi_enable(&m_twi);
        // Read sensor data
        nrf_drv_twi_disable(&m_twi);

  • Hi,

    If the current consumption stuck at 3-4mA constant, it's more likely the CPU was not put to sleep. 
    Please try run in debug mode and check if the CPU would stuck in the callback ? 
    Could you post the whole source code ? where you access the SAADC and I2C.

  • Yeah sure. Disabling and deinitializing the i2c peripheral does not reduce the current consumption? Because the reason I am saying this is.....I am testing the application by enabling and disabling individual peripheral and what I observed is that, with i2c alone enabled in the application, After friendship is established, current consumption goes as low as 400ua and after publishing data too, it is returning to the same low power state (i.e., 400ua). So this means that CPU was put to sleep right? Only the I2C peripheral is not deinitialized properly. The sequence I am following for I2C is:

    1. Initialize and enable the i2c peripheral

    2. Read data from i2c sensor

    3. Disable and de-initialize the i2c peripheral (Doing steps 1 to 3 in the periodic callback itself)

    I have attached the initializing, deinitializing i2c code and the code used to get data from i2c sensor in the callback. I2C peripheral is successfully getting initialized and deinitialized because I am able to read data from i2c sensor successfully.

    //I2C initialization code
    void twi_init (void)
    {
        ret_code_t err_code;
        NRF_LOG_INFO("Initializing I2C!!!\r");
        err_code = nrf_drv_twi_init(&m_twi, &twi_config, twi_handler, NULL);
        nrf_delay_ms(20);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_INFO("Initialized I2C!!!\r");
        NRF_LOG_INFO("Enabling I2C!!!\r");
        nrf_drv_twi_enable(&m_twi);
        NRF_LOG_INFO("Enabled I2C!!!\r\n");
    }
    
    //I2C deinitialization code
    void twi_deinit(void)
    {
        NRF_LOG_INFO("Disabling I2C!!!\r");
        nrf_drv_twi_disable(&m_twi);
        NRF_LOG_INFO("Disabled I2C!!!\r");
        NRF_LOG_INFO("Deinitializing I2C!!!\r");
        nrf_drv_twi_uninit(&m_twi);
        NRF_LOG_INFO("Deinitialized I2C!!!\r\n");
    }
    
    
    //Code to read data from i2c sensor in the callback
    #if ENABLE_I2C || ENABLE_ALL
            twi_init();
            m_tx_done = false;
            m_rx_done = false;
    
            uint16_t t_ticks, h_ticks;
            uint16_t temp;
    
            /* Read 1 byte from the specified address - skip 3 bits dedicated for fractional part of temperature. */
            ret_code_t err_code;
        
            uint8_t reg[1] = {0xFD};
            err_code = nrf_drv_twi_tx(&m_twi, 0x44, reg, sizeof(reg), false);
            APP_ERROR_CHECK(err_code);
            while (m_tx_done == false);
            nrf_delay_ms(10);
    
            uint8_t rxData[6] = {0};
            err_code = nrf_drv_twi_rx(&m_twi, 0x44, rxData, sizeof(rxData));
            while(m_rx_done==false);
            nrf_delay_ms(10);
        
            t_ticks = rxData[0] * 256 + rxData[1];
            h_ticks = rxData[3] * 256 + rxData[4];
            temp = (175 * t_ticks / 65535) - 45;
            humidity = (125 * h_ticks / 65535) - 6;
    
            temp *= 10;
            p_out[0] = temp >> 8;
            p_out[1] = temp & 0xFF;
            APP_ERROR_CHECK(err_code);
            NRF_LOG_INFO("Temp - %d | Hum - %d\n\n",temp, humidity);
            twi_deinit();
    #endif
            required_out_bytes = 2;    

Related