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 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;    

  • Hi again, 
    What I'm suspecting is that the CPU is stuck in a dead loop somewhere in the code. Besides high current consumption everything works ? 


    Even at 400uA , it's high current consumption in my opinion. I don't know how you configure the node, have you checked if 400uA is the idle current or it's the average current ? 

    Could you try doing I2C communication in the main loop (set a flag in the callback and execute the I2C activity in the main loop and go to sleep after that) and check if it make it high current consumption ? 
    Could you provide the minimal code (for example modify the LPN example) so that we can test here ? 

  • Hi,
    Yes. Besides higher current consumption, everything else is working as expected.

    Yes, it is a higher current consumption. Can you please tell me which node configuration you are referring to? When the CPU goes to sleep after friendship is established, the current goes down to around 400ua. When publishing it goes to upto 600-700ua and then back to 400. I am using multimeter to measure current consumed.

    So you are suggesting me to do the i2c read in main loop instead of in the callback itself without deinitializing and reinitializing it?

    Sure. Will provide one tomorrow. Its past 9 in the eve here.
Reply
  • Hi,
    Yes. Besides higher current consumption, everything else is working as expected.

    Yes, it is a higher current consumption. Can you please tell me which node configuration you are referring to? When the CPU goes to sleep after friendship is established, the current goes down to around 400ua. When publishing it goes to upto 600-700ua and then back to 400. I am using multimeter to measure current consumed.

    So you are suggesting me to do the i2c read in main loop instead of in the callback itself without deinitializing and reinitializing it?

    Sure. Will provide one tomorrow. Its past 9 in the eve here.
Children
  • Hi Hariharan, 
    I did a quick test here with the LPN example. What I found is that after LPN established friendship the current consumption should be around 16uA. What you have of 150uA or 700uA is still too high. 
    Please try to test with the LPN example again. Did you test using our nRF52 DK ? 

    Have you keep RTT logging when testing ? If you do please disconnect RTT or disable logging in the code. 

    Do you have a PPK2 (power profiler kit) ? If you do, you can capture the current consumption , for example here is what I have : 

    You can find the consumption is around 16uA with a peak every 2 seconds for polling friend node. 

    The idle current consumption is about 9uA: 

    If you see a peak of 100ms , it was because of RTT_INPUT_POLL_PERIOD_MS = 100ms. If you set RTT_INPUT_ENABLED = 0 in nrf_mesh_config_app.h you will not have this 100ms wake up period. 

    So if you see anything above dozen of uA , there must be something wrong. If you don't have a PPK2 I would strongly suggest to get hold of one. 

  • Hi,

    Previously, I have written our application using senor_server example as our base application and integrated all the peripherals and low power node in the sensor_server example. Now, I was integrating the peripherals and sensor models with the low power node example as our base application. 

    And it seems to be working so far. The device is consuming low current of 150ua (which is more than enough in our use case) when no peripherals were integrated. When the peripherals were integrated and initially in the unprovisioned state, the device was consuming around 1.8ma as a timer and LED is used to indicate the unprovisioned state. After provisioning, I disable the timer(I use timer's handler to toggle led - reason for higher current consumption) and the node goes to low power state immediately. 

    Now, I want to integrate the sensor models into the application. When I tried to initialize the sensor models in the low power node example with the API - "app_sensor_init(&m_sensor_server_0, APP_SENSOR_ELEMENT_INDEX);" , the return code which I am getting is 4 (which corresponds to NRF_ERROR_NO_MEM). Can you help me troubleshoot this issue?

    And we don't have a PPK2 with us.

  • Hi Hariharan,

    Could you please test with the unmodified LPN example ? As I mentioned in the last reply, 150uA is too high, you should see around 16uA. 

    Even if you don't have a PPK or a oscilloscope to measure the current/voltage drop , you can use a simple multiple meter and should see the similar average current. 

    If you don't there must be something wrong with your board. Please try to compare the current consumption on a Dev Kit and check why there is a difference. 150uA without doing any activity (except for polling the friend node) is not normal. 
    Even if you use a timer (RTC not the TIMER) 150uA is high. If you use a timer (RTC) the current should increase only a few uA and the timer (RTC) is already used by the mesh 

    Regarding your issue of NRF_ERROR_NO_MEM, if you read the description of the function , you can find this: 

    You may want to increase ACCESS_MODEL_COUNT or ACCESS_SUBSCRIPTION_LIST_COUNT. Please try to debug if you see an error, you can step into the code and check why the function throws an error. 

  • Yes, I have found the reason why it was giving me NRF_ERROR_NO_MEM error code. Sensor model example had 4 models in an element and low power had only three. Modified it in the nrf_mesh_config_app.h and the issue was resolved.

    Seems to be there an issue with the board. I will report this issue to my hardware team. I ran the unmodified lpn example in our board and got the same 150ua. The reason for 150ua is that am powering the board through a 5v to 3v3 regulator which consumes half of that current. So, the soc actually consumes only 60-70ua. 

    Is reading I2C data and ADC data inside sensor model's periodic callback to publish data a wrong idea? Because that seems to make the CPU consume higher current around 3ma.

  • Hi Hariharan, 
    If you have any activity that take longer time you should put it into thread context (main context). 
    Also , after the activity is finished (reading ADC for example) the CPU should go to sleep and you should see the current consumption goes down. If you don't see that there must be something wrong and the CPU was stuck. 

    I would suggest to use DCDC instead of LDO converter to save more current consumption. But still at 60-70uA it's high current consumption. You may want to try testing some very simple application that only put the CPU to sleep (try the RTC example) and check if you can achieve a few uA current consumption. This is to verify that your board doesn't have any fault. 

Related