DA14683: How to troubleshoot what is blocking extended sleep modes?

Hardware: 

Custom board using DA14683

SDK: 

1.0.14.1081 (last updated in 2018, despite what the new renesas download link says)

Situation:

The DA14683 won't go into extended sleep mode.  

I issue the "pm_set_sleep_mode(pm_mode_extended_sleep);" command but the sleep state does not change.  The power consumption does not change.  From what I can tell it never changes the sleep state.

Questions:

1) How should I go about troubleshooting what is keeping the sleep mode from running?  How can I determine what is keeping the code from going into sleep mode?

2) Can you debug the sleep mode operation?

Parents
  • Hi Nathan, 

    In addition to my previous comment, the SDK includes hooks that holds all the user-defined functions that will be used
    by the Power Manager at every wakeup/sleep cycle.

    Please check : https://www.renesas.com/eu/en/document/sws/sw-example-generating-pwm-pulses-timer0?language=en&r=1600761

    /*
     * Structure that holds all the user-defined functions that will be used
     * by the Power Manager at every wakeup/sleep cycle.
     */
    const adapter_call_backs_t timer_0_callbacks = {
            .ad_prepare_for_sleep      = ad_prepare_for_sleep_cb,
            .ad_wake_up_ind            = ad_wake_up_ind_cb,
    
            /*
             * Here, you can define a callback that hits in case the system was about
             * to sleep but eventually the sleep process was aborted.
             */
            .ad_sleep_canceled         = NULL,
    
            /*
             * Here, you can define a callback that hits once XTAL16MHz crystal is settled.
             */
            .ad_xtal16m_ready_ind      = NULL,
    
            /*
             * Here, you can define extra clock cycles needed for the system
             * to stay active, before entering sleep.
             */
            .ad_sleep_preparation_time = 0
    };

    Best regards, 

    PM_Renesas

  • (Sorry it took me a while to get back to this)

    Situation:

    I think I found the thing that's keeping the system from sleeping when I issue pm_set_sleep_mode(pm_mode_extended_sleep);

    In sys_power_mgr.c: "void pm_sleep_enter(uint32_t low_power_periods)"

    #if defined CONFIG_USE_BLE || defined CONFIG_USE_FTDF
         uint32_t tmp = CRG_TOP->SYS_STAT_REG;
    #endif
    
    #ifdef CONFIG_USE_BLE
    if ((tmp & CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Msk) == CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Msk) {
        mac_status = true;
    }
    #endif

    The problem here is that "tmp" is getting a value of 1786 from CRG_TOP->SYS_STAT_REG.  That causes "mac_status" to be set to "TRUE".

    Then later in that same pm_sleep_enter() function, having mac_status=true causes this conditional to fail and allow_entering_sleep remains "FALSE"

    if ((pm_current_sleep_mode != pm_mode_idle) && !mac_status) {
         /* We plan to enter sleep */
         allow_entering_sleep = true;
    }

    This keeps the system from going to sleep since allow_entering_sleep remains FALSE!

    Questions:

    1) What is going on here?  What is CRG_TOP->SYS_STAT_REG and why is it causing that check for mac_status to fail?

    2) Given this issue, what can I do here to get the system to sleep successfully?

  • More research:

    This is defined in DA14680BB.h

    /* ----------------------------  CRG_TOP_SYS_STAT_REG  ---------------------------- */
    #define CRG_TOP_SYS_STAT_REG_RAD_IS_DOWN_Pos  (0UL)                     /*!< CRG_TOP SYS_STAT_REG: RAD_IS_DOWN (Bit 0)                   */
    #define CRG_TOP_SYS_STAT_REG_RAD_IS_DOWN_Msk  (0x1UL)                   /*!< CRG_TOP SYS_STAT_REG: RAD_IS_DOWN (Bitfield-Mask: 0x01)     */
    #define CRG_TOP_SYS_STAT_REG_RAD_IS_UP_Pos    (1UL)                     /*!< CRG_TOP SYS_STAT_REG: RAD_IS_UP (Bit 1)                     */
    #define CRG_TOP_SYS_STAT_REG_RAD_IS_UP_Msk    (0x2UL)                   /*!< CRG_TOP SYS_STAT_REG: RAD_IS_UP (Bitfield-Mask: 0x01)       */
    #define CRG_TOP_SYS_STAT_REG_PER_IS_DOWN_Pos  (2UL)                     /*!< CRG_TOP SYS_STAT_REG: PER_IS_DOWN (Bit 2)                   */
    #define CRG_TOP_SYS_STAT_REG_PER_IS_DOWN_Msk  (0x4UL)                   /*!< CRG_TOP SYS_STAT_REG: PER_IS_DOWN (Bitfield-Mask: 0x01)     */
    #define CRG_TOP_SYS_STAT_REG_PER_IS_UP_Pos    (3UL)                     /*!< CRG_TOP SYS_STAT_REG: PER_IS_UP (Bit 3)                     */
    #define CRG_TOP_SYS_STAT_REG_PER_IS_UP_Msk    (0x8UL)                   /*!< CRG_TOP SYS_STAT_REG: PER_IS_UP (Bitfield-Mask: 0x01)       */
    #define CRG_TOP_SYS_STAT_REG_XTAL16_SW2_Pos   (4UL)                     /*!< CRG_TOP SYS_STAT_REG: XTAL16_SW2 (Bit 4)                    */
    #define CRG_TOP_SYS_STAT_REG_XTAL16_SW2_Msk   (0x10UL)                  /*!< CRG_TOP SYS_STAT_REG: XTAL16_SW2 (Bitfield-Mask: 0x01)      */
    #define CRG_TOP_SYS_STAT_REG_DBG_IS_ACTIVE_Pos (5UL)                    /*!< CRG_TOP SYS_STAT_REG: DBG_IS_ACTIVE (Bit 5)                 */
    #define CRG_TOP_SYS_STAT_REG_DBG_IS_ACTIVE_Msk (0x20UL)                 /*!< CRG_TOP SYS_STAT_REG: DBG_IS_ACTIVE (Bitfield-Mask: 0x01)   */
    #define CRG_TOP_SYS_STAT_REG_XTAL16_TRIM_READY_Pos (6UL)                /*!< CRG_TOP SYS_STAT_REG: XTAL16_TRIM_READY (Bit 6)             */
    #define CRG_TOP_SYS_STAT_REG_XTAL16_TRIM_READY_Msk (0x40UL)             /*!< CRG_TOP SYS_STAT_REG: XTAL16_TRIM_READY (Bitfield-Mask: 0x01) */
    #define CRG_TOP_SYS_STAT_REG_XTAL16_SETTLE_READY_Pos (7UL)              /*!< CRG_TOP SYS_STAT_REG: XTAL16_SETTLE_READY (Bit 7)           */
    #define CRG_TOP_SYS_STAT_REG_XTAL16_SETTLE_READY_Msk (0x80UL)           /*!< CRG_TOP SYS_STAT_REG: XTAL16_SETTLE_READY (Bitfield-Mask: 0x01) */
    #define CRG_TOP_SYS_STAT_REG_BLE_IS_DOWN_Pos  (8UL)                     /*!< CRG_TOP SYS_STAT_REG: BLE_IS_DOWN (Bit 8)                   */
    #define CRG_TOP_SYS_STAT_REG_BLE_IS_DOWN_Msk  (0x100UL)                 /*!< CRG_TOP SYS_STAT_REG: BLE_IS_DOWN (Bitfield-Mask: 0x01)     */
    #define CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Pos    (9UL)                     /*!< CRG_TOP SYS_STAT_REG: BLE_IS_UP (Bit 9)                     */
    #define CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Msk    (0x200UL)                 /*!< CRG_TOP SYS_STAT_REG: BLE_IS_UP (Bitfield-Mask: 0x01)       */
    #define CRG_TOP_SYS_STAT_REG_FTDF_IS_DOWN_Pos (10UL)                    /*!< CRG_TOP SYS_STAT_REG: FTDF_IS_DOWN (Bit 10)                 */
    #define CRG_TOP_SYS_STAT_REG_FTDF_IS_DOWN_Msk (0x400UL)                 /*!< CRG_TOP SYS_STAT_REG: FTDF_IS_DOWN (Bitfield-Mask: 0x01)    */
    #define CRG_TOP_SYS_STAT_REG_FTDF_IS_UP_Pos   (11UL)                    /*!< CRG_TOP SYS_STAT_REG: FTDF_IS_UP (Bit 11)                   */
    #define CRG_TOP_SYS_STAT_REG_FTDF_IS_UP_Msk   (0x800UL)                 /*!< CRG_TOP SYS_STAT_REG: FTDF_IS_UP (Bitfield-Mask: 0x01)      */

    And these are from the Datasheet: www.renesas.com/.../da14683-datasheet

  • 1786 = 0b0000011011111010
    #define CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Pos    (9UL)                     /*!< CRG_TOP SYS_STAT_REG: BLE_IS_UP (Bit 9)                     */
    #define CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Msk    (0x200UL)                 /*!< CRG_TOP SYS_STAT_REG: BLE_IS_UP (Bitfield-Mask: 0x01)       */
    ((tmp & CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Msk) == CRG_TOP_SYS_STAT_REG_BLE_IS_UP_Msk)
    Question:
    1) Does this imply that the sleep is failing because the processor is detecting that the BLE radio is still on?  
    2) Why isn't the radio powering down when the system tries to sleep?  How do I ensure that the BLE radio is not up when sleep mode is entered?
    3) If I wanted to enter sleep no matter what (like a full power down type situation in response to a push of the soft power button) what process of function calls would I need to make to shut down everything that could possible prevent the sleep event?
  • Question:

    1) Can I use the "hw_cpm_wait_rad_power_down()"  function after the "ble_gap_adv_stop()" function to confirm the radio is powered down before going to sleep?  Will that work?

    __STATIC_INLINE void hw_cpm_wait_rad_power_down(void)
    {
            while ((CRG_TOP->SYS_STAT_REG & REG_MSK(CRG_TOP, SYS_STAT_REG, RAD_IS_DOWN)) == 0);
    }

  • When I first call: ble_gap_adv_stop()

    Then Call: hw_cpm_wait_rad_power_down()

    ... The code hangs in the hw_cpm_wait_rad_power_down() function and never exits.  

    Question:

    1) What is the correct way to fully power down the ble radio before going to sleep?

    NOTE:  This should be a simple question to answer.  Either point me to the established answer in any available document or forum thread, or please answer it here.  I would appreciate it if this question didn't take a long time to answer and if I didn't have to ping it back to the top of the list every couple days so it doesn't get lost.  If for some reason this is a hard question, please describe why.  Thanks!

  • Hi Nathan, 

    In extended sleep mode, the device goes to sleep between advertising or connection intervals. It wakes up automatically via the BLE timer. 

    This means that during extended sleep mode, the chip can advertise and sleep between advertising intervals. Same for the connection, as it can be kept during extended sleep. 

    Of course, the average power consumption in t depends on the intervals: larger interval means more time in extended sleep, so less average power consumption. 

    If you have any peripheral blocks, such as sensors, please put them in power-down mode. 

    In case you would like to put the device into permanent sleep mode, all you need to do is to stop advertising by using ble_gap_adv_stop(). This can be done either via a timer (synchronously) or via an external interrupt. 

    In both cases, when calling the ble_gap_adv_stop(), you should get a BLE_EVT_GAP_ADV_COMPLETED message that is handled in for (;;) { } in the application task. So, the handle_evt_gap_adv_completed() callback is triggered when the advertising has been stopped. Inside handle_evt_gap_adv_completed(), put the device into the desired sleep mode. 

    static void handle_evt_gap_adv_completed( ble_evt_gap_adv_completed_t *evt)
    
    {
            pm_sleep_mode_set(pm_mode_extended_sleep);
    
    }
    
    
    case BLE_EVT_GAP_ADV_COMPLETED :
    
      handle_evt_gap_adv_completed((ble_evt_gap_pair_req_t *) hdr);
    
    break;

    Regards, 

    PM_renesas

  • Thank you for the response.

    I am doing as you noted above to try to put the device into permanent sleep.  I call ble_gap_adv_stop(), wait for the handle_evt_gap_adv_completed, then call pm_sleep_mode_set(pm_mode_extended_sleep);

    As I noted above, when I do that the code hangs in the hw_cpm_wait_rad_power_down() call in apply_wfi().  

    sys_power_mgr.c: apply_wfi()

    /*
    * Make sure that Radio PD is powered down
    */
    
    hw_cpm_wait_rad_power_down();

  • Hi Nathan, 

    The hw_cpm_wait_rad_power_down() checks if Radio PD is powered down by reading the SYS_STAT_REG[RAD_IS_DOWN] bitfield. 

    However, this bitfield is set by the HW automatically and as you can see from this DA14683 datasheet is read-only ( it's not writable). 

    Are you testing this on your custom board?  If yes, this sounds like a HW issue...

    Regards, 

    PM_renesas

Reply Children