Zigbee power consumption

Hi,

I'm measuring the power consumption on our BLE+Zigbee device.

After the zigbee device is commsioned, it uses an average of 600uA of current, which seems pretty high. I already enabled the sleepy behavior like this:

    zb_set_rx_on_when_idle(ZB_FALSE);
     

#if ! defined DISABLE_POWER_CONSUMPTION_OPTIMIZATION
    /* If sleepy behaviour is enabled, power off unused RAM to save maximum energy */
    if (ZB_PIBCACHE_RX_ON_WHEN_IDLE() == ZB_TRUE)
    {
        zigbee_power_down_unused_ram();
    }

See below the power usage with sleepy behavior:

If I totally disable the Zigbee stack, it uses average of 4.65uA:

I assume this +/-600uA increase is not normal for Zigbee.

Can you please suggest how to lower this power consumption?

Parents
  • Hi,

    • Are you using nRF Connect SDK or nRF5 SDK for Thread and Zigbee?
    • Which version of the SDK do you use?
    • Which example/sample are you basing your code on?
    • Have you made modifications to the example?

    I would expect 600 uA to typically be caused by the HFCLK running and/or UART.

    Best regards,
    Jørgen

  • Hi,

    See answers below:

    • nRF5_SDK_for_Thread_and_Zigbee_v4.1.0
    • I'm using my own code. But I started with the light switch example, because this is a (sleepy) end device
    • Yes, it is my own code.

    UART is disabled. For current measurement I disabled all the logging by the way to exclude this factor.

    I understand it's hard for you to figure this out based on my own code which you didn't see, but that's why I tried to isolate the problem to Zigbee only, by disabling en enabling it. Just to make sure it's nothing else in my code which causes this, but it seems like the Zigbee stack is the problem. 

    When I use the light switch example I get much lower values, but as far as I know nothing else is happening there.

    This the code I use for zigbee init:

    static void zigbee_init(void)
    {
        uint64_t factoryAddress;
    
        /* Read long address from FICR. */
        factoryAddress  = (uint64_t)NRF_FICR->DEVICEID[0] << 32;
        factoryAddress |= NRF_FICR->DEVICEID[1];
        memcpy(m_ieee_addr, &factoryAddress, sizeof(factoryAddress));
    
        /* Set Zigbee stack logging level and traffic dump subsystem. */
        ZB_SET_TRACE_LEVEL(ZIGBEE_TRACE_LEVEL);
        ZB_SET_TRACE_MASK(ZIGBEE_TRACE_MASK);
        ZB_SET_TRAF_DUMP_OFF();
        /* Initialize Zigbee stack. */
        ZB_INIT("multiprotocol_template");
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(m_ieee_addr);
        zb_set_long_address(m_ieee_addr);
        /* Set static long IEEE address. */
        zb_set_network_ed_role(ZB_TRANSCEIVER_ALL_CHANNELS_MASK);
        //zb_set_network_ed_role(IEEE_CHANNEL_MASK);
        
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
        zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
        sleepy_device_setup();
        UNUSED_RETURN_VALUE(ZB_MEMSET(&m_dev_ctx, 0, sizeof(m_dev_ctx)));
    
        ZB_AF_REGISTER_DEVICE_CTX(&device_ctx);
    
        // UNUSED_RETURN_VALUE(ZB_MEMSET(&on_off_switch_ctx, 0, sizeof(on_off_switch_ctx)));
    
        // ZB_AF_REGISTER_DEVICE_CTX(&on_off_switch_ctx);
    
        ZB_ZCL_REGISTER_DEVICE_CB(test_device_interface_cb);
    
        ZB_AF_SET_ENDPOINT_HANDLER(ZB_OUTPUT_ENDPOINT, zcl_specific_cluster_cmd_handler);
    
        window_covering_clusters_attr_init();
        power_config_battery_attr_init();
        /* Initialize application context structure. */
        //
        /* Register dimmer switch device context (endpoints). */
    
    
        /* Register callback for handling ZCL commands. */
        // ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
    
        //test_device_attr_init();
    }

    This is the zboss_signal handler:

    void zboss_signal_handler(zb_bufid_t bufid)
    {
        /* Read signal description out of memory buffer. */
        zb_zdo_app_signal_hdr_t * p_sg_p      = NULL;
        zb_zdo_app_signal_type_t  sig         = zb_get_app_signal(bufid, &p_sg_p);
        zb_ret_t                  status      = ZB_GET_APP_SIGNAL_STATUS(bufid);
        zb_ret_t                  zb_err_code;
        zb_bool_t                 comm_status;
        zb_time_t                 timeout_bi;
    
        switch(sig)
        {
            case ZB_BDB_SIGNAL_DEVICE_REBOOT:
                // BDB initialization completed after device reboot, use NVRAM contents during initialization. Device joined/rejoined and started.
                if (status == RET_OK)
                {
                    if (ZIGBEE_MANUAL_STEERING == ZB_FALSE)
                    {
                        NRF_LOG_INFO("Start network steering");
                        comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                        ZB_COMM_STATUS_CHECK(comm_status);
                    }
                    else
                    {
                        NRF_LOG_INFO("Coordinator restarted successfully");
                    }
                }
                else
                {
                    NRF_LOG_ERROR("Failed to initialize Zigbee stack using NVRAM data (status: %d)", status);
                }
                break;
    
            case ZB_BDB_SIGNAL_STEERING:
                if (status == RET_OK)
                {
                    if (ZIGBEE_PERMIT_LEGACY_DEVICES == ZB_TRUE)
                    {
                        NRF_LOG_INFO("Allow pre-Zigbee 3.0 devices to join the network");
                        zb_bdb_set_legacy_device_support(1);
                    }
    
                    /* Schedule an alarm to notify about the end of steering period */
                    NRF_LOG_INFO("Network steering started");
                    zb_err_code = ZB_SCHEDULE_APP_ALARM(steering_finished, 0, ZB_TIME_ONE_SECOND * ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            case ZB_ZDO_SIGNAL_DEVICE_ANNCE:
                {
                    zb_zdo_signal_device_annce_params_t * dev_annce_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_device_annce_params_t);
                    NRF_LOG_INFO("New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr);
    
                    zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(steering_finished, ZB_ALARM_ANY_PARAM);
                    if (zb_err_code == RET_OK)
                    {
                        NRF_LOG_INFO("Joining period extended.");
                        zb_err_code = ZB_SCHEDULE_APP_ALARM(steering_finished, 0, ZB_TIME_ONE_SECOND * ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
                        ZB_ERROR_CHECK(zb_err_code);
                    }
            } break;
    
            case ZB_COMMON_SIGNAL_CAN_SLEEP: {
    
                    // zb_sleep_now();
            } break;
    
            default:
                    /* Call default signal handler. */
                    ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
                    break;
        }
    
        /* Update network status LED */
        if (ZB_JOINED() && (ZB_SCHEDULE_GET_ALARM_TIME(steering_finished, ZB_ALARM_ANY_PARAM, &timeout_bi) == RET_OK))
        {
            bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);
        }
        else
        {
            bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
        }
    
        /* All callbacks should either reuse or free passed buffers. If bufid == 0, the buffer is invalid (not passed) */
        if (bufid)
        {
            zb_buf_free(bufid);
        }
    }

    To start the zigbee stack:

    err_code = zboss_start_no_autostart();
    ZB_ERROR_CHECK(err_code);

    And in my main loop:

    zboss_main_loop_iteration();
    UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());

    I would expect 600 uA to typically be caused by the HFCLK running and/or UART.

    HFCLK could be, but as far as I know I'm not in control of the usage of when the Zigbee stack is used?

  • I finally found the culprit. I had the function nrf_pwr_mgmt_run() in the mainloop running. Which I had in the BLE project. But apparently this is not cooperating with the zigbee scheduler, so I guess they where interfering or something. After removing this, I got a very low power output of around 17uA.

  • Hi,

    I am glad to hear that you figured it out.

    You are correct that calling nrf_pwr_mgmt_run() in the main loop will cause issues with the Zigbee scheduler. When using Zigbee in nRF5 SDK, you must use either zboss_main_loop() or zboss_main_loop_iteration() for the ZBOSS main loop, which will handle stack signals and ZCL callbacks. Calling nrf_pwr_mgmt_run() in the main loop will interfere with the ZBOSS main loop and, therefore, the Zigbee stack.
    However, nrf_pwr_mgmt_run() is called by the Zigbee stack when the Zigbee scheduler queue is empty, so there is no need to call this function yourself.

    Best regards,
    Marte

Reply
  • Hi,

    I am glad to hear that you figured it out.

    You are correct that calling nrf_pwr_mgmt_run() in the main loop will cause issues with the Zigbee scheduler. When using Zigbee in nRF5 SDK, you must use either zboss_main_loop() or zboss_main_loop_iteration() for the ZBOSS main loop, which will handle stack signals and ZCL callbacks. Calling nrf_pwr_mgmt_run() in the main loop will interfere with the ZBOSS main loop and, therefore, the Zigbee stack.
    However, nrf_pwr_mgmt_run() is called by the Zigbee stack when the Zigbee scheduler queue is empty, so there is no need to call this function yourself.

    Best regards,
    Marte

Children
Related