CC2340R5: Z-Boss Stack Freezes During Boot-up in RNG Initialization

Part Number: CC2340R5
Other Parts Discussed in Thread: SYSCONFIG,

Tool/software:

Hello,

I am developing a Zigbee device using CC2350R5 and I'm facing a boot issue.

My device normally stays in shutdown mode and wakes up via a button press. While this process works most of the time, some devices frequently freeze during the boot sequence and require a hard reset to recover.

I have isolated the issue to the Z-Boss stack initialization, where the code hangs. This situation appears to be identical to the one described in a previous post here in the forum (Post: "The initialization froze after the restart")

I can reliably reproduce the problem with a minimally modified on/off zigbee switch example. The bug often appears within seconds just by rapidly pressing the wake-up button. I was also able to trigger the freeze during a normal debug session (by repeatedly restarting the firmware using the reset button on the IDE), which indicates the issue is not exclusive to waking from shutdown.

During a freeze in the debugger, I captured the call stack, and it's stuck in the exact same function mentioned in the referenced post. Please see the image below:

And below, my example based o nthe on/off switch example, which can be used to reproduce the bug. Simply keep pressing the button until the green LED stays ON indicating the ZBoss init function did not return, and the device no longer reboots.

----------------------------------------------------------------------------------

MAIN()
{
ARGV_UNUSED;

PowerLPF3_ResetReason resetReason = PowerLPF3_getResetReason();

GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_ON);
if (resetReason == PowerLPF3_RESET_SHUTDOWN_IO)
PowerLPF3_releaseLatches();
else
GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_ON);

/* Global ZBOSS initialization */
Log_printf(LogModule_Zigbee_App, Log_ERROR, "before");
ZB_INIT("on_off_switch");
Log_printf(LogModule_Zigbee_App, Log_ERROR, "after");

GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_OFF);
GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF);

GPIO_setConfig(CONFIG_GPIO_BTN1, GPIO_CFG_IN_PU | GPIO_CFG_SHUTDOWN_WAKE_LOW);
Power_shutdown(0, 0);

while(1){}

...

------------------------------------------------------------

As a workaround, I could try to use the watchdog to detect this situation and reboot the device, but I don't like this "solution", and it could also cause a loop that would consume the entire battery.

What could cause the stack to hang indefinitely during random number generation? Considering we do not have access to the stack code neither for debug, shouldn't this function return an error or call an abort function acceble to the user app, as "zb_ti_f3_abort" instead of freezing?

This is a critical issue for my application, and the only way to reset the device in the field is by removing the battery, which is a very difficult procedure for the end-user.

Any help would be greatly appreciated.

Thank you.

  • Hi Tiago,

    First, please try upgrading you TI Arm CLANG Compiler or remove LTO and determine if this eliminates the behavior, see this E2E thread for reference.  I would also be curious to know whether you can mitigate this behavior by putting your Power TI Driver PowerLPF3_getResetReason/PowerLPF3_releaseLatches functions in main(void) or *main_task_function(void *arg0) of ti_f3_main.c instead of in MAIN().

    Can this behavior occur on every device or a select few, and what percentage of trials display the issue?  Are you evaluating with TI LaunchPads or custom hardware?

    Regards,
    Ryan

  • We are using a custom hardware. It is a very simple device, a wireless switch powered by a battery CR2032. The behavior occurs on every device. 

    I am using 30 units for testing. With our complete firmware, the problem occurs frequently. If I repeatedly press the button on all devices, I can see the problem in most cases after a few minutes clicking (may be a few hundred clicks/resets). 

    With my minimal example, that do not have transmission and goes to shutdown immediately after stack initialization, what allows a fast cycle of resets, I can reproduce this problem in seconds (most times, less than 100 resets), on every hardware I have tried.

    Unfortunately, I do not have LaunchPad for cc2340 here to test. I am curious if this situation occurs on Launch Pad. Couldn't you try to reproduce it in you hardware?

    I don't know what causes it, but certanly the problem is with randon noise capture and RNG Health Check Tests. A workaround that eliminated the problem completely, even in my minimal example, was to disabled RNG Heath Test in SysConfig:

    After disabling these two checks, I couldn't reproduce the problem even after clicking many times for many minutes in my minimal example. I know it is not a good solution, so I will try your suggestions.

    I am using TI Arm CLANG v4.0.3, but will try v4.0.4 and disabling LTO. I will also try putting PowerLPF3_getResetReason on main(), but I don't thik it will help.

    Another test I did was putting a 15ms and a 100ms cpu delay before stack init to give more time for random capture, but it didn't help. I could try changing parameters for the RNG insted of disabling Health Check completlly, but I fear I could be just reducing the probability of a lock. As we will be using a lot of devices, even a lock probability of one in a million, is not good enouth as this problem will cause the battery to be drained completely. 

    One thing that worried me a lot is that other situation like this one make use of a continuous loop. Inside the stack, any abort should call an abort function that could be customized by the user. There is "void zb_ti_f3_abort(void)" declared inside ti_f3_main.c, but it is not being called in this situation. I think I need to implement a Watchdog to avoid a locklike this one.

    The development team should be aware of this situation and try to avoid this kind of situation (continuous loop inside the stack). 

    As soon as I have new results with your suggestions, I post it here.

    Thanks for the help.

  • What SDK and SysConfig versions are you using?  I believe there needs to be a way to replicate the error in functioning Zigbee code, i.e. not just shutting down continuously from MAIN.  I'm not sure what is happening with your device's power during these situations given the custom hardware.  I also already gave suggestions about resolving Power TI Driver APIs before MAIN was entered which I don't see evidence has been investigated.

    Regards,
    Ryan

  • I updated all my tools, as listed below:

    CCS v20.3.1.5__1.9.1

    TI Arm CLANG v4.0.4

    Simplelink F3 v9.12.0.19

    SysConfig v1.25.0

    Then tried your suggestions by putting Power TI Driver PowerLPF3_getResetReason/PowerLPF3_releaseLatches functions in main() and disabling LTO., but got the same behaviour.

    Then I did a really minimal example, removed all the shutdown code and just turned LED ON before calling ZB_INIT and after it returns, turn LED OFF and enter in a while(1){}.

    Using this code, I tried to trigger the bug by resetting the board using the reset button on my programmer (a cc1352 LaunchPad). After some time, the green LED stayed ON, indicating a lock inside ZB_INIT.

    Then, I tried to trigger the bug by just resetting the device from the IDE (using shortcut ctrl+shift+R to reset, then F5 to run), in order to minimize physical interference. After some time I could trigger the bug again and as I was in the debugger, I could see the call stack.

    And your suggestion about finding "a way to replicate the error in functioning Zigbee code, i.e. not just shutting down continuously from MAIN.", I can't think how I could trigger this bug without resetting the device, as the bug occurs exactly on the boot process on my real firmware and I think that this RNG initialization process happens only on boot. Any idea on what I could try?

    From my side, I could try to initialize the RNG module and check its Health without touching ZBoss initialization, but I couldn't find any example on how to use RNG module alone. Is it possible? If so, I could try to trigger the bug in an empty example, that could isolate the bug only on the RNG module.

  • Hi Tiago,

    Thank you for providing all of this information.  You could copy simplelink_lowpower_f3_sdk_9_12_00_19\source\ti\drivers\rng\RNGLPF3RF.c into your local workspace directory to further debug RNG_getRandomBits -> RNGLPF3RF_getValidatedNumber, nevertheless I have found an internal bug ticket similar to the behavior you've described and will further inquire internally.

    Does an extra SW reset with PMCTLResetSystem after PowerLPF3_releaseLatches (i.e. only reset during wakeup from shutdown) help alleviate the behavior?  This is as a test, not a recommended workaround.

    Regards,
    Ryan

  • Hi Tiago,

    I tried but was not able to replicate the behavior.  I am using the Dependencies listed in the SimpleLink F3 SDK v9.12.0.19 Release Notes

    TI Code Composer Studio: CCS 20.1.0
    TI ARM Clang Compiler: 4.0.2.LTS
    SysConfig: 1.23.01
    UniFlash: 9.0.0
    IAR Embedded Workbench: 9.60.3

    Using the default CC2340R5 on/off switch, my changes are as follows.  First in ti_f3_main.c:

    int main(void)
    {
      pthread_t           thread;
      pthread_attr_t      attrs;
      struct sched_param  priParam;
      int                 retc;
      int                 detachState;
      
      PowerLPF3_ResetReason resetReason = PowerLPF3_getResetReason();
    
      if (resetReason == PowerLPF3_RESET_SHUTDOWN_IO)
        PowerLPF3_releaseLatches();

    And then in on_off_switch.c:

      else
      {
        // GPIO_setConfig(CONFIG_GPIO_BTN1, GPIO_CFG_IN_PU);
        // GPIO_setConfig(CONFIG_GPIO_BTN2, GPIO_CFG_IN_PU);
        // // if either button 1 or button 2 gets pressed
        // zb_bool_t sideButtonPressed = ((GPIO_read((zb_uint8_t)CONFIG_GPIO_BTN1) == 0U) || (GPIO_read((zb_uint8_t)CONFIG_GPIO_BTN2) == 0U));
        // // then perform a factory reset
        // if (sideButtonPressed)
        // {
        //   perform_factory_reset = ZB_TRUE;
        //   Log_printf(LogModule_Zigbee_App, Log_INFO, "perform factory reset");
        // }
    
        zb_osif_led_button_init();
    #ifndef ZB_COORDINATOR_ROLE
        ZB_SCHEDULE_APP_ALARM(off_network_attention, 0, 1 * ZB_TIME_ONE_SECOND);
    #endif /* ZB_COORDINATOR_ROLE */
    
        zb_osif_led_on(0);
    
        GPIO_setConfig(CONFIG_GPIO_BTN1, GPIO_CFG_IN_PU | GPIO_CFG_SHUTDOWN_WAKE_LOW);
    
        Power_shutdown(0, 0);
        
        /* Call the application-specific main loop */
        my_main_loop();

    Can you help me further understand the differences between our setups?  I recommend that you use the SysConfig and TI Clang Compiler from the Release Notes.

    Regards,
    Ryan

  • Hello,

    Apologies for the delay in my response. I have spent some time investigating this issue further and have some important updates.

    Here are my findings:

    • I tried adding an extra software reset (PMCTLResetSystem() after PowerLPF3_releaseLatches()) as you suggested, but it did not help.

    • By copying RNGLPF3RF.c into my project, I've successfully isolated the problem to be independent of the Z-Boss stack. I was able to reproduce the freeze by simply initializing the RNG, without ever calling ZB_INIT(). The hang occurs specifically within the RNG Health Tests. I believe this is what's causing the stack initialization to fail.

    • While debugging with different devices, I noticed unit-to-unit variation. On some of our devices, the bug is very difficult to trigger (more than 100 resets/power cycles), while on others, it's extremely easy (a few 10s resets). This strongly suggests a hardware component is contributing to this behavior.

    We have reviewed our hardware design and have not found any obvious issues. Our RF section, which is generally trickier to get right, was validated in our lab and shows excellent performance. The CC2340R5 hardware design is simpler than the previous CC13xx/CC26xx generation, with which we have more experience. Perhaps a subtle issue related to the crystal or oscillator is affecting the noise used by RNG for seed generation? Any idea how to verify it?

    Crucially, if I disable the RNG Health Tests, the problem disappears completely, and the system works perfectly.

    Below, some evidences from my tests using code based on the switch example. Our device is a custom hardware that uses cc2340R5 RGE, not RKP, so it was necessary to modify the example to custom board and change the device package (In a previous post it can be seen in the SysConfig file header). Besides that, the example was modified to use only RNG with no call to ZBoss init (code attached).

    I also tried to generate an even simpler project using the empty project example as base, but RNG has dependencies that I couldn't provide without enabling Zigbee stack, what defeats my purpose. So I gave up this path for now.

    Below, the evidences from using code based on the switch example.

    I could trigger the bug with debbug connected as I said before. As seen below, when the bug is triggered, I can't generate random bits, with return error "-8", which means the RNG subsystem was not initialized.

    It was not initialized because RNGLP3RF_conditionNoise returned a error code "-32"

    Triggered by HealthTests failing, as seen in the following sequence:

    And error "-32" is defined here:

    So I could isolate the bug very precisely, but I don't know what is causing it. Could you provide any guidance on what else I could investigate here from the firmware side? And what hardware aspects could influence the RNG's Health Tests that we should verify?

    /******************************************************************************
     Group: CMCU LPRF
     Target Device: cc23xx
    
     ******************************************************************************
     
     Copyright (c) 2024-2025, Texas Instruments Incorporated
     All rights reserved.
    
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
    
     *  Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
    
     *  Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
    
     *  Neither the name of Texas Instruments Incorporated nor the names of
        its contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
     ******************************************************************************
     
     
     *****************************************************************************/
    /*
     PURPOSE: Platform specific for TI F3 SoC.
     */
    #define ZB_TRACE_FILE_ID 30011
    
    #include "zb_common.h"
    
    #ifdef ZB_ZGPD_ROLE
    #include "zb_osif.h"
    #else // R23_MAC
    #include "zb_osif_platform.h"
    // Required for sleepy zed check in zb_osif_sleep()
    #include "zb_mac_globals.h"
    #endif /* ZB_ZGPD_ROLE */
    
    /*cstat -MISRAC2012-* */
    #if !defined(NORTOS)
    #include <pthread.h>
    
    /* RTOS header files */
    #include <FreeRTOS.h>
    #include <task.h>
    #else
    #include <NoRTOS.h>
    #endif //NORTOS
    
    #include <ti/drivers/Power.h>
    #include <ti/drivers/dpl/HwiP.h>
    #include <ti/drivers/dpl/SemaphoreP.h>
    #include <ti/devices/DeviceFamily.h>
    #include DeviceFamily_constructPath(driverlib/pmctl.h)
    
    #include "ti_drivers_config.h"
    
    #if defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    #include <ti/zigbee/osif/include/zb_hal_crypto.h>
    #endif
    /*cstat +MISRAC2012-* */
    
    /* Stack size in bytes */
    /* Stack size in bytes */
    #if defined SNCP_MODE || defined ZB_ZGPD_ROLE || defined ZBOSS_REV22
    /* increased because of large aps binding table */
    #define THREADSTACKSIZE    2048U
    #else //defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    #define THREADSTACKSIZE    6000U
    #endif // defined SNCP_MODE || defined ZB_ZGPD_ROLE
    #include <ti/log/Log.h>
    
    #define MAX_INT_DEPTH 8
    
    static zb_bool_t gs_platform_init_done = ZB_FALSE;
    static volatile zb_uint8_t count = 0;
    static uintptr_t hwiKey;
    extern SemaphoreP_Handle wakeSem;
    
    #include <ti/drivers/RNG.h>
    #include <ti/drivers/rng/RNGLPF3RF.h> // required for external syscfg variable RNGLPF3RF_noiseInputWordLen
    #include <ti/drivers/GPIO.h>
    
    // Use RNG
    #define RANDOM_BYTES_SIZE 16u
    
    // Use the function provided by RCL to read noise input //
    extern int_fast16_t RCL_AdcNoise_get_samples_blocking(uint32_t *buffer, uint32_t numWords);
    
    uint8_t randomBytesArray[RANDOM_BYTES_SIZE] = {0};
    uint32_t localNoiseInput[152]; //Minimum array size 80 words
    
    void *main_task_function(void *arg0)
    {
      RNG_Handle handle;
      int_fast16_t rclStatus, result;
    
      ZVUNUSED(arg0);
    
      Log_printf(LogModule_Zigbee, Log_DEBUG, "initialized");
    
      GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_ON);
    
      //  RNG_fillPoolIfLessThan(RNG_POOL_BYTE_SIZE);
      
      // Clear noise input //
      memset(localNoiseInput, 0, sizeof(localNoiseInput));
    
      // Fill noise input from RCL //
      rclStatus = RCL_AdcNoise_get_samples_blocking(localNoiseInput, RNGLPF3RF_noiseInputWordLen);
      if (rclStatus != 0)
        FATAL_ERR();
    
      // Initialize the RNG driver noise input pointer with global noise input array from user //
      result = RNGLPF3RF_conditionNoiseToGenerateSeed(localNoiseInput);
      if ( rclStatus != 0)
        FATAL_ERR();
    
      RNG_init();
    
      handle = RNG_open(0, NULL);
      if (!handle)
        FATAL_ERR();
    
      result = RNG_getRandomBits(handle, randomBytesArray, RANDOM_BYTES_SIZE * 8);
      if (result != RNG_STATUS_SUCCESS)
        FATAL_ERR();
    
      GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_OFF);
    
      //while(1){}
      GPIO_setConfig(CONFIG_GPIO_BTN1, GPIO_CFG_IN_PU | GPIO_CFG_SHUTDOWN_WAKE_LOW);
      Power_shutdown(0, 0);
    
    //  zb_ti_f3_main();
    
      return NULL;
    }
    #if !defined(NORTOS)
    int main(void)
    {
      pthread_t           thread;
      pthread_attr_t      attrs;
      struct sched_param  priParam;
      int                 retc;
      int                 detachState;
    
      PowerLPF3_ResetReason resetReason = PowerLPF3_getResetReason();
    
      if (resetReason == PowerLPF3_RESET_SHUTDOWN_IO)
      {
        PowerLPF3_releaseLatches();
        //PMCTLResetSystem(); // Adding this line do not helps
      }
    
      /* Call driver init functions */
      Board_init();
    
      /* Set priority and stack size attributes */
      retc = pthread_attr_init(&attrs);
      if (retc != 0)
      {
        /* pthread_attr_init() failed */
        FATAL_ERR();
      }
    
      priParam.sched_priority = 1;
    
      detachState = PTHREAD_CREATE_DETACHED;
      retc = pthread_attr_setdetachstate(&attrs, detachState);
      if (retc != 0)
      {
          /* pthread_attr_setdetachstate() failed */
          FATAL_ERR();
      }
    
      retc = pthread_attr_setschedparam(&attrs, &priParam);
      if (retc != 0)
      {
        /* pthread_attr_setschedparam() failed */
        FATAL_ERR();
      }
    
      retc = pthread_attr_setstacksize(&attrs, THREADSTACKSIZE);
      if (retc != 0)
      {
          /* pthread_attr_setstacksize() failed */
          FATAL_ERR();
      }
    
      retc = pthread_create(&thread, &attrs, main_task_function, NULL);
      if (retc != 0)
      {
          /* pthread_create() failed */
          FATAL_ERR();
      }
    
      /* Start the FreeRTOS scheduler */
      vTaskStartScheduler(); /* does not return */
    
      return (0);
    }
    #else
    int main(void)
    {
      /* Call driver init functions */
      Board_init();
    
      /* Start NoRTOS */
      NoRTOS_start();
    
      /* Call mainThread function */
      main_task_function(NULL);
    
      return (0);
    }
    #endif //NORTOS
    
    void zb_ti_f3_platform_init(bool gpd)
    {
      if (gs_platform_init_done)
      {
        return;
      }
    
      gs_platform_init_done = ZB_TRUE;
    
      if(gpd)
      {
    #ifdef ZB_USE_BUTTONS
        ti_f3_buttons_init();
    #endif //ZB_USE_BUTTONS
      }
      else
      {
    #ifdef ZB_HAVE_SERIAL
        zb_osif_serial_init();
    #endif // ZB_HAVE_SERIAL
    
    #if defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
        zb_osif_timer_init();
    
        if (zb_osif_random_init() != RET_OK)
        {
          FATAL_ERR();
        }
    
        ZB_TIMER_CTX().canstop = ZB_TRUE;
    #endif //defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
      }
    }
    
    void zb_ti_f3_abort(void)
    {
      FATAL_ERR();
    }
    
    void zb_ti_f3_enable_all_inter(void)
    {
      const unsigned int prev_val = count;
      if(count != 0U)
      {
        count -= 1;
      }
    
      if (prev_val == 1) {
          HwiP_restore(hwiKey);
          hwiKey = 0;
      }
    }
    
    void zb_ti_f3_disable_all_inter(void)
    {
      const unsigned int prev_val = count++;
      if (prev_val == 0) {
          hwiKey = HwiP_disable();
      }
    
    }
    
    #ifdef ZB_ZGPD_ROLE
    void gboss_platform_init(ARGC_ARGV_PROTO)
    {
      zb_ti_f3_platform_init(true);
    }
    
    void osif_deep_sleep(void)
    {
      /* switch to shutdown mode, the parameters are default, they are device-specific and not used */
      Power_shutdown(0, 0);
    }
    
    void zgpd_wait_for_event(void)
    {
      do
      {
        if (TRANS_CTX().rx_int != 0u)
        {
          break;
        }
    
        /* just go to sleep, it's up to layer above to set timers */
        Power_idleFunc();
      }
      while (0);
    }
    #endif //ZB_ZGPD_ROLE
    
    #if defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    
    #ifdef ZB_USE_SLEEP
    extern void zb_osif_uart_wake_up(void);
    extern void zb_osif_uart_sleep(void);
    
    zb_uint32_t zb_osif_sleep(zb_uint32_t sleep_tmo)
    {
      zb_uint32_t sleep_ticks;
      zb_uint32_t t1;
      zb_uint32_t t2;
      zb_uint32_t slept_time_ms;
      zb_uint32_t tickPeriod = ClockP_getSystemTickPeriod();
    
    #ifndef NCP_MODE
    #ifdef ZB_HAVE_SERIAL
      zb_osif_uart_sleep();
    #endif
    #endif
    
      //Seconds_set(0);
      sleep_ticks = (sleep_tmo * 1000U)/tickPeriod;
    
      ZG->sleep.sleeping_now = ZB_TRUE;
    
      // Get starting time
      t1 = ClockP_getSystemTicks();
    
      // When device is a sleepy ZED, ensure that RX is off when going to sleep.
      if (MAC_PIB().mac_rx_on_when_idle == 0U)
      {
        ZB_TRANSCEIVER_SET_RX_ON_OFF(ZB_FALSE);
      }
    
      /* zzzzZZZZZzzzzzz */
      SemaphoreP_Status semStatus = SemaphoreP_TIMEOUT;
      if(NULL != wakeSem)
      {
        semStatus = SemaphoreP_pend(wakeSem, sleep_ticks);
      }
      else
      {
        ClockP_usleep(sleep_tmo * 1000U);
      }
    
      // Get ending time
      t2 = ClockP_getSystemTicks();
    
      if(SemaphoreP_TIMEOUT == semStatus)
      {
        slept_time_ms = sleep_tmo;
      }
      else
      {
        if(t2 > t1)
        {
          slept_time_ms = ((t2-t1) * tickPeriod)/1000U;
        }
        else
        {
          slept_time_ms = ((((uint64_t)t2 + 0xFFFFFFFFU - (uint64_t)t1) % 0xFFFFFFFFU) * tickPeriod)/1000U;
        }
      }
    
      ZG->sleep.sleeping_now = ZB_FALSE;
    
      return slept_time_ms;
    }
    #else
    
    zb_uint32_t zb_osif_sleep(zb_uint32_t sleep_tmo)
    {
      return 0;
    }
    #endif //ZB_USE_SLEEP
    
    void zb_osif_wake_up(void)
    {
    #ifndef NCP_MODE
    #ifdef ZB_HAVE_SERIAL
      zb_osif_uart_wake_up();
    #endif //ZB_HAVE_SERIAL
    #endif // !NCP_MODE
    }
    
    zb_uint8_t zb_get_reset_source(void)
    {
      zb_uint32_t rst_src;
      zb_uint8_t zboss_rst_src;
    
      /*cstat !MISRAC2012-Rule-11.1 Violation cause by a third-party library */
      rst_src  =  PMCTLGetResetReason();
    
      switch (rst_src)
      {
        case PMCTL_RESET_POR:     /* PWR_ON Power on reset*/
          zboss_rst_src = ZB_RESET_SRC_POWER_ON;
          break;
        case PMCTL_RESET_PIN:  /* PIN_RESET Reset pin*/
          zboss_rst_src = ZB_RESET_SRC_RESET_PIN;
          break;
        case PMCTL_RESET_VDDS:  /* Brown out detect on VDDS fall through */
        case PMCTL_RESET_VDDR:  /* Brown out detect on VDDR */
          zboss_rst_src = ZB_RESET_SRC_BROWN_OUT;
          break;
        case PMCTL_RESET_LFXT:   /* Clock loss detect */
          zboss_rst_src = ZB_RESET_SRC_CLOCK_LOSS;
          break;
        case PMCTL_RESET_SYSTEM:   /* Software reset via SYSRESET register fall through */
          zboss_rst_src = ZB_RESET_SRC_SW_RESET;
          break;
        default:                /* RSTSRC_WAKEUP_FROM_SHUTDOWN or RSTSRC_WAKEUP_FROM_TCK_NOISE or RSTSRC_WARMRESET */
          zboss_rst_src = ZB_RESET_SRC_OTHER;
          break;
      }
    
      return zboss_rst_src;
    }
    
    void zb_reset(zb_uint8_t param)
    {
      ZVUNUSED(param);
    
      PMCTLResetSystem();
    }
    
    /* The following stubs were added to satisfy MISRA Rule 8.6.
     * The prototypes are declared unconditionally in zb_osif.h but no
     * implementation is needed for SNCP. Linker will optimize it anyway. */
    /*********** BEGIN Stubs to satisfy MISRA Rule 8.6 ***********/
    zb_uint32_t osif_get_time_ms(void)
    {
      return ZB_UINT32_MAX;
    }
    
    zb_ret_t osif_set_transmit_power(zb_uint8_t channel, zb_int8_t power)
    {
      ZVUNUSED(channel);
      ZVUNUSED(power);
      return RET_OK;
    }
    
    void osif_set_default_trasnmit_powers(zb_int8_t *tx_powers)
    {
      ZVUNUSED(tx_powers);
      return;
    }
    
    zb_bool_t zb_osif_led_level_init(zb_uint8_t led_no)
    {
      ZVUNUSED(led_no);
      return ZB_FALSE;
    }
    
    void zb_osif_led_on_set_level(zb_uint8_t level)
    {
      ZVUNUSED(level);
      return;
    }
    /*********** END Stubs to satisfy MISRA Rule 8.6 ***********/
    #endif //defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    
    #if defined ZB_INTERRUPT_SAFE_CALLBACKS && (defined ZB_TRACE_LEVEL || defined DOXYGEN)
    zb_bool_t zb_osif_is_inside_isr(void)
    {
      return HwiP_inISR();
    }
    #endif /* defined ZB_INTERRUPT_SAFE_CALLBACKS && (defined ZB_TRACE_LEVEL || defined DOXYGEN) */
    
    // Required due to M0+ not allowing unaligned memory access.
    void zb_memcpy( void *dst, const void *src, unsigned int len )
    {
      uint8_t *pDst;
      const uint8_t *pSrc;
    
      pSrc = src;
      pDst = dst;
    
      while ( len-- )
        *pDst++ = *pSrc++;
    
    }
    
    zb_int8_t zb_memcmp(const void *src1, const void *src2, unsigned int len)
    {
      const uint8_t *pSrc1;
      const uint8_t *pSrc2;
    
      pSrc1 = src1;
      pSrc2 = src2;
    
      while (len > 0)
      {
          if (*pSrc1 != *pSrc2)
              return (*pSrc1 - *pSrc2);
          len--;
          pSrc1++;
          pSrc2++;
      }
      return 0;
    }
    
    void zb_memset(void *str, unsigned int c, unsigned int len)
    {
      uint8_t *pStr = str;
    
      while (len > 0)
      {
          *pStr = c;
          len--;
          pStr++;
      }
    }
    
    void zb_memmove(void *dst, const void *src, size_t len)
    {
        size_t i;
    
        /*
          * If the buffers don't overlap, it doesn't matter what direction
          * we copy in. If they do, it does, so just assume they always do.
          * We don't concern ourselves with the possibility that the region
          * to copy might roll over across the top of memory, because it's
          * not going to happen.
          *
          * If the destination is above the source, we have to copy
          * back to front to avoid overwriting the data we want to
          * copy.
          *
          *      dest:       dddddddd
          *      src:    ssssssss   ^
          *              |   ^  |___|
          *              |___|
          *
          * If the destination is below the source, we have to copy
          * front to back.
          *
          *      dest:   dddddddd
          *      src:    ^   ssssssss
          *              |___|  ^   |
          *                     |___|
          */
    
        if ((uintptr_t)dst < (uintptr_t)src)
        {
            zb_memcpy(dst, src, len);
            return;
        }
    
        /*
        * Copy by words in the common case.
        */
        if ((((uintptr_t)dst & 0x3) == 0) &&
            (((uintptr_t)src & 0x3) == 0) &&
            ((len % sizeof(zb_uint32_t)) == 0))
        {
    
            zb_uint32_t *d = dst;
            const zb_uint32_t *s = src;
    
            /*
              * The reason we copy index i-1 and test i>0 is that
              * i is unsigned -- so testing i>=0 doesn't work.
              */
            for (i=len/sizeof(zb_uint32_t); i>0; i--)
            {
                    d[i-1] = s[i-1];
            }
        }
        else
        {
            zb_uint8_t *d = dst;
            const zb_uint8_t *s = src;
    
            for (i=len; i>0; i--)
            {
                    d[i-1] = s[i-1];
            }
        }
    }
    

    Thank you,

  • Hi Tiago,

    Thank you for this detailed report, it is very helpful.

    We have reviewed our hardware design and have not found any obvious issues. Our RF section, which is generally trickier to get right, was validated in our lab and shows excellent performance. The CC2340R5 hardware design is simpler than the previous CC13xx/CC26xx generation, with which we have more experience. Perhaps a subtle issue related to the crystal or oscillator is affecting the noise used by RNG for seed generation? Any idea how to verify it?

    Have you submitted your hardware design to SIMPLELINK-2-4GHZ-DESIGN-REVIEWS for further review?

    Crucially, if I disable the RNG Health Tests, the problem disappears completely, and the system works perfectly.

    TI's SW R&D Teams have advised against turning off the RNG Health Tests, so we should further replicate and debug this issue.

    Our device is a custom hardware that uses cc2340R5 RGE, not RKP, so it was necessary to modify the example to custom board and change the device package (In a previous post it can be seen in the SysConfig file header). Besides that, the example was modified to use only RNG with no call to ZBoss init (code attached).

    I had not caught that before.  I am unable to replicate the issue with the CC2340R5RKP despite 100+ button presses, and don't currently have a CC2340R5RGE to test but I will try to find one in the upcoming week.  Have you tried using your test firmware on a CC2340R5 RKP LaunchPad?  I'm also interested in the device variation you've noted.  Can you confirm that you referenced the Using the RGE QFN24 package variant guide and are using the F3 SDK dependency versions that I listed in my past reply?

    I can't generate random bits, with return error "-8", which means the RNG subsystem was not initialized.
    It was not initialized because RNGLP3RF_conditionNoise returned a error code "-32"

    I will pass this information along to SW and Radio R&D for further review.

    Regards,
    Ryan

  • Hey Tiago,

    I was able to replicate the behavior you've described when using a CC2340R5RGE device variant instead of the CC2340R5RKP provided on LPs.  I will continue working with R&D Teams internally to address this issue and report back when I have an update.

    Regards,
    Ryan

  • Hi Ryan,

    That's fantastic news! Thank you so much for the update and for managing to replicate the issue.

    It's a huge relief to know it's reproducible on your end.

    We'll be looking forward to the update from you and the R&D team.

    Best regards,
    Tiago

  • Hi Tiago,

    Does your example pass more regularly when adding in an iterative loop?

    // Fill noise input from RCL //
    // RNGLPF3RF_noiseInputWordLen is external variable from RNGLPF3RF.h
    // Collect noise input from RCL till input has enough entropy.
    for (i = 0; i < 10; i++)
    {
        rclStatus = RCL_AdcNoise_get_samples_blocking(localNoiseInput, RNGLPF3RF_noiseInputWordLen);
        if (rclStatus != 0)
        {
            // Handle error
        }
        // Initialize the RNG driver noise input pointer with global noise input array from user //
        rclStatus = RNGLPF3RF_conditionNoiseToGenerateSeed(localNoiseInput);
        if ((rclStatus == RNG_STATUS_RCT_FAIL) || (rclStatus == RNG_STATUS_APT_FAIL) ||
            (rclStatus == RNG_STATUS_APT_BIMODAL_FAIL))
        {
            continue; // retry if health checks fail
        }
        else if (rclStatus != 0)
        {
            // Handle error
        }
        else
        {
            break; // break out of loop if success
        }
    }

    I got this idea from the Migration Guide and RNG file reference, and it produced different behavior on my CC2340R5RGE.  It crashes after 100 attempts but not where the GPIO is lit, and I don't fully understand this yet.  I'm still employing help from R&D.  I moved the PowerLPF3_ResetReason code to after Board_init although I am not sure whether this changed anything.

    /******************************************************************************
     Group: CMCU LPRF
     Target Device: cc23xx
    
     ******************************************************************************
     
     Copyright (c) 2024-2025, Texas Instruments Incorporated
     All rights reserved.
    
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
    
     *  Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
    
     *  Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
    
     *  Neither the name of Texas Instruments Incorporated nor the names of
        its contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
     ******************************************************************************
     
     
     *****************************************************************************/
    /*
     PURPOSE: Platform specific for TI F3 SoC.
     */
    #define ZB_TRACE_FILE_ID 30011
    
    #include "zb_common.h"
    
    #ifdef ZB_ZGPD_ROLE
    #include "zb_osif.h"
    #else // R23_MAC
    #include "zb_osif_platform.h"
    // Required for sleepy zed check in zb_osif_sleep()
    #include "zb_mac_globals.h"
    #endif /* ZB_ZGPD_ROLE */
    
    /*cstat -MISRAC2012-* */
    #if !defined(NORTOS)
    #include <pthread.h>
    
    /* RTOS header files */
    #include <FreeRTOS.h>
    #include <task.h>
    #else
    #include <NoRTOS.h>
    #endif //NORTOS
    
    #include <ti/drivers/Power.h>
    #include <ti/drivers/dpl/HwiP.h>
    #include <ti/drivers/dpl/SemaphoreP.h>
    #include <ti/devices/DeviceFamily.h>
    #include DeviceFamily_constructPath(driverlib/pmctl.h)
    
    #include "ti_drivers_config.h"
    
    #if defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    #include <ti/zigbee/osif/include/zb_hal_crypto.h>
    #endif
    /*cstat +MISRAC2012-* */
    
    /* Stack size in bytes */
    /* Stack size in bytes */
    #if defined SNCP_MODE || defined ZB_ZGPD_ROLE || defined ZBOSS_REV22
    /* increased because of large aps binding table */
    #define THREADSTACKSIZE    2048U
    #else //defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    #define THREADSTACKSIZE    6000U
    #endif // defined SNCP_MODE || defined ZB_ZGPD_ROLE
    #include <ti/log/Log.h>
    
    #define MAX_INT_DEPTH 8
    
    static zb_bool_t gs_platform_init_done = ZB_FALSE;
    static volatile zb_uint8_t count = 0;
    static uintptr_t hwiKey;
    extern SemaphoreP_Handle wakeSem;
    
    #include <ti/drivers/RNG.h>
    #include <ti/drivers/rng/RNGLPF3RF.h> // required for external syscfg variable RNGLPF3RF_noiseInputWordLen
    #include <ti/drivers/GPIO.h>
    
    // Use RNG
    #define RANDOM_BYTES_SIZE 16u
    
    // Use the function provided by RCL to read noise input //
    extern int_fast16_t RCL_AdcNoise_get_samples_blocking(uint32_t *buffer, uint32_t numWords);
    
    uint8_t randomBytesArray[RANDOM_BYTES_SIZE] = {0};
    uint32_t localNoiseInput[152]; //Minimum array size 80 words
    
    void *main_task_function(void *arg0)
    {
      RNG_Handle handle;
      int_fast16_t rclStatus, result;
    
      ZVUNUSED(arg0);
    
      PowerLPF3_ResetReason resetReason = PowerLPF3_getResetReason();
    
      if (resetReason == PowerLPF3_RESET_SHUTDOWN_IO)
      {
        PowerLPF3_releaseLatches();
        //PMCTLResetSystem(); // Adding this line do not helps
      }
    
      Log_printf(LogModule_Zigbee, Log_DEBUG, "initialized");
    
      GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_ON);
    
      //  RNG_fillPoolIfLessThan(RNG_POOL_BYTE_SIZE);
      
      // Clear noise input //
      memset(localNoiseInput, 0, sizeof(localNoiseInput));
    
    // Fill noise input from RCL //
    // RNGLPF3RF_noiseInputWordLen is external variable from RNGLPF3RF.h
    // Collect noise input from RCL till input has enough entropy.
    for (uint8_t i = 0; i < 10; i++)
    {
        rclStatus = RCL_AdcNoise_get_samples_blocking(localNoiseInput, RNGLPF3RF_noiseInputWordLen);
        if (rclStatus != 0)
        {
            // Handle error
        }
        // Initialize the RNG driver noise input pointer with global noise input array from user //
        rclStatus = RNGLPF3RF_conditionNoiseToGenerateSeed(localNoiseInput);
        if ((rclStatus == RNG_STATUS_RCT_FAIL) || (rclStatus == RNG_STATUS_APT_FAIL) ||
            (rclStatus == RNG_STATUS_APT_BIMODAL_FAIL))
        {
            continue; // retry if health checks fail
        }
        else if (rclStatus != 0)
        {
            // Handle error
        }
        else
        {
            break; // break out of loop if success
        }
    }
    
      RNG_init();
    
      handle = RNG_open(0, NULL);
      if (!handle)
        FATAL_ERR();
    
      result = RNG_getRandomBits(handle, randomBytesArray, RANDOM_BYTES_SIZE * 8);
      if (result != RNG_STATUS_SUCCESS)
        FATAL_ERR();
    
      GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_OFF);
    
      //while(1){}
      GPIO_setConfig(CONFIG_GPIO_BTN2, GPIO_CFG_IN_PU | GPIO_CFG_SHUTDOWN_WAKE_LOW);
      Power_shutdown(0, 0);
    
    //  zb_ti_f3_main();
    
      return NULL;
    }
    #if !defined(NORTOS)
    int main(void)
    {
      pthread_t           thread;
      pthread_attr_t      attrs;
      struct sched_param  priParam;
      int                 retc;
      int                 detachState;
    
      /* Call driver init functions */
      Board_init();
    
      /* Set priority and stack size attributes */
      retc = pthread_attr_init(&attrs);
      if (retc != 0)
      {
        /* pthread_attr_init() failed */
        FATAL_ERR();
      }
    
      priParam.sched_priority = 1;
    
      detachState = PTHREAD_CREATE_DETACHED;
      retc = pthread_attr_setdetachstate(&attrs, detachState);
      if (retc != 0)
      {
          /* pthread_attr_setdetachstate() failed */
          FATAL_ERR();
      }
    
      retc = pthread_attr_setschedparam(&attrs, &priParam);
      if (retc != 0)
      {
        /* pthread_attr_setschedparam() failed */
        FATAL_ERR();
      }
    
      retc = pthread_attr_setstacksize(&attrs, THREADSTACKSIZE);
      if (retc != 0)
      {
          /* pthread_attr_setstacksize() failed */
          FATAL_ERR();
      }
    
      retc = pthread_create(&thread, &attrs, main_task_function, NULL);
      if (retc != 0)
      {
          /* pthread_create() failed */
          FATAL_ERR();
      }
    
      /* Start the FreeRTOS scheduler */
      vTaskStartScheduler(); /* does not return */
    
      return (0);
    }
    #else
    int main(void)
    {
      /* Call driver init functions */
      Board_init();
    
      /* Start NoRTOS */
      NoRTOS_start();
    
      /* Call mainThread function */
      main_task_function(NULL);
    
      return (0);
    }
    #endif //NORTOS
    
    void zb_ti_f3_platform_init(bool gpd)
    {
      if (gs_platform_init_done)
      {
        return;
      }
    
      gs_platform_init_done = ZB_TRUE;
    
      if(gpd)
      {
    #ifdef ZB_USE_BUTTONS
        ti_f3_buttons_init();
    #endif //ZB_USE_BUTTONS
      }
      else
      {
    #ifdef ZB_HAVE_SERIAL
        zb_osif_serial_init();
    #endif // ZB_HAVE_SERIAL
    
    #if defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
        zb_osif_timer_init();
    
        if (zb_osif_random_init() != RET_OK)
        {
          FATAL_ERR();
        }
    
        ZB_TIMER_CTX().canstop = ZB_TRUE;
    #endif //defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
      }
    }
    
    void zb_ti_f3_abort(void)
    {
      FATAL_ERR();
    }
    
    void zb_ti_f3_enable_all_inter(void)
    {
      const unsigned int prev_val = count;
      if(count != 0U)
      {
        count -= 1;
      }
    
      if (prev_val == 1) {
          HwiP_restore(hwiKey);
          hwiKey = 0;
      }
    }
    
    void zb_ti_f3_disable_all_inter(void)
    {
      const unsigned int prev_val = count++;
      if (prev_val == 0) {
          hwiKey = HwiP_disable();
      }
    
    }
    
    #ifdef ZB_ZGPD_ROLE
    void gboss_platform_init(ARGC_ARGV_PROTO)
    {
      zb_ti_f3_platform_init(true);
    }
    
    void osif_deep_sleep(void)
    {
      /* switch to shutdown mode, the parameters are default, they are device-specific and not used */
      Power_shutdown(0, 0);
    }
    
    void zgpd_wait_for_event(void)
    {
      do
      {
        if (TRANS_CTX().rx_int != 0u)
        {
          break;
        }
    
        /* just go to sleep, it's up to layer above to set timers */
        Power_idleFunc();
      }
      while (0);
    }
    #endif //ZB_ZGPD_ROLE
    
    #if defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    
    #ifdef ZB_USE_SLEEP
    extern void zb_osif_uart_wake_up(void);
    extern void zb_osif_uart_sleep(void);
    
    zb_uint32_t zb_osif_sleep(zb_uint32_t sleep_tmo)
    {
      zb_uint32_t sleep_ticks;
      zb_uint32_t t1;
      zb_uint32_t t2;
      zb_uint32_t slept_time_ms;
      zb_uint32_t tickPeriod = ClockP_getSystemTickPeriod();
    
    #ifndef NCP_MODE
    #ifdef ZB_HAVE_SERIAL
      zb_osif_uart_sleep();
    #endif
    #endif
    
      //Seconds_set(0);
      sleep_ticks = (sleep_tmo * 1000U)/tickPeriod;
    
      ZG->sleep.sleeping_now = ZB_TRUE;
    
      // Get starting time
      t1 = ClockP_getSystemTicks();
    
      // When device is a sleepy ZED, ensure that RX is off when going to sleep.
      if (MAC_PIB().mac_rx_on_when_idle == 0U)
      {
        ZB_TRANSCEIVER_SET_RX_ON_OFF(ZB_FALSE);
      }
    
      /* zzzzZZZZZzzzzzz */
      SemaphoreP_Status semStatus = SemaphoreP_TIMEOUT;
      if(NULL != wakeSem)
      {
        semStatus = SemaphoreP_pend(wakeSem, sleep_ticks);
      }
      else
      {
        ClockP_usleep(sleep_tmo * 1000U);
      }
    
      // Get ending time
      t2 = ClockP_getSystemTicks();
    
      if(SemaphoreP_TIMEOUT == semStatus)
      {
        slept_time_ms = sleep_tmo;
      }
      else
      {
        if(t2 > t1)
        {
          slept_time_ms = ((t2-t1) * tickPeriod)/1000U;
        }
        else
        {
          slept_time_ms = ((((uint64_t)t2 + 0xFFFFFFFFU - (uint64_t)t1) % 0xFFFFFFFFU) * tickPeriod)/1000U;
        }
      }
    
      ZG->sleep.sleeping_now = ZB_FALSE;
    
      return slept_time_ms;
    }
    #else
    
    zb_uint32_t zb_osif_sleep(zb_uint32_t sleep_tmo)
    {
      return 0;
    }
    #endif //ZB_USE_SLEEP
    
    void zb_osif_wake_up(void)
    {
    #ifndef NCP_MODE
    #ifdef ZB_HAVE_SERIAL
      zb_osif_uart_wake_up();
    #endif //ZB_HAVE_SERIAL
    #endif // !NCP_MODE
    }
    
    zb_uint8_t zb_get_reset_source(void)
    {
      zb_uint32_t rst_src;
      zb_uint8_t zboss_rst_src;
    
      /*cstat !MISRAC2012-Rule-11.1 Violation cause by a third-party library */
      rst_src  =  PMCTLGetResetReason();
    
      switch (rst_src)
      {
        case PMCTL_RESET_POR:     /* PWR_ON Power on reset*/
          zboss_rst_src = ZB_RESET_SRC_POWER_ON;
          break;
        case PMCTL_RESET_PIN:  /* PIN_RESET Reset pin*/
          zboss_rst_src = ZB_RESET_SRC_RESET_PIN;
          break;
        case PMCTL_RESET_VDDS:  /* Brown out detect on VDDS fall through */
        case PMCTL_RESET_VDDR:  /* Brown out detect on VDDR */
          zboss_rst_src = ZB_RESET_SRC_BROWN_OUT;
          break;
        case PMCTL_RESET_LFXT:   /* Clock loss detect */
          zboss_rst_src = ZB_RESET_SRC_CLOCK_LOSS;
          break;
        case PMCTL_RESET_SYSTEM:   /* Software reset via SYSRESET register fall through */
          zboss_rst_src = ZB_RESET_SRC_SW_RESET;
          break;
        default:                /* RSTSRC_WAKEUP_FROM_SHUTDOWN or RSTSRC_WAKEUP_FROM_TCK_NOISE or RSTSRC_WARMRESET */
          zboss_rst_src = ZB_RESET_SRC_OTHER;
          break;
      }
    
      return zboss_rst_src;
    }
    
    void zb_reset(zb_uint8_t param)
    {
      ZVUNUSED(param);
    
      PMCTLResetSystem();
    }
    
    /* The following stubs were added to satisfy MISRA Rule 8.6.
     * The prototypes are declared unconditionally in zb_osif.h but no
     * implementation is needed for SNCP. Linker will optimize it anyway. */
    /*********** BEGIN Stubs to satisfy MISRA Rule 8.6 ***********/
    zb_uint32_t osif_get_time_ms(void)
    {
      return ZB_UINT32_MAX;
    }
    
    zb_ret_t osif_set_transmit_power(zb_uint8_t channel, zb_int8_t power)
    {
      ZVUNUSED(channel);
      ZVUNUSED(power);
      return RET_OK;
    }
    
    void osif_set_default_trasnmit_powers(zb_int8_t *tx_powers)
    {
      ZVUNUSED(tx_powers);
      return;
    }
    
    zb_bool_t zb_osif_led_level_init(zb_uint8_t led_no)
    {
      ZVUNUSED(led_no);
      return ZB_FALSE;
    }
    
    void zb_osif_led_on_set_level(zb_uint8_t level)
    {
      ZVUNUSED(level);
      return;
    }
    /*********** END Stubs to satisfy MISRA Rule 8.6 ***********/
    #endif //defined ZB_COORDINATOR_ROLE || defined ZB_ROUTER_ROLE ||  defined ZB_ED_ROLE || !defined ZB_ZGPD_ROLE
    
    #if defined ZB_INTERRUPT_SAFE_CALLBACKS && (defined ZB_TRACE_LEVEL || defined DOXYGEN)
    zb_bool_t zb_osif_is_inside_isr(void)
    {
      return HwiP_inISR();
    }
    #endif /* defined ZB_INTERRUPT_SAFE_CALLBACKS && (defined ZB_TRACE_LEVEL || defined DOXYGEN) */
    
    // Required due to M0+ not allowing unaligned memory access.
    void zb_memcpy( void *dst, const void *src, unsigned int len )
    {
      uint8_t *pDst;
      const uint8_t *pSrc;
    
      pSrc = src;
      pDst = dst;
    
      while ( len-- )
        *pDst++ = *pSrc++;
    
    }
    
    zb_int8_t zb_memcmp(const void *src1, const void *src2, unsigned int len)
    {
      const uint8_t *pSrc1;
      const uint8_t *pSrc2;
    
      pSrc1 = src1;
      pSrc2 = src2;
    
      while (len > 0)
      {
          if (*pSrc1 != *pSrc2)
              return (*pSrc1 - *pSrc2);
          len--;
          pSrc1++;
          pSrc2++;
      }
      return 0;
    }
    
    void zb_memset(void *str, unsigned int c, unsigned int len)
    {
      uint8_t *pStr = str;
    
      while (len > 0)
      {
          *pStr = c;
          len--;
          pStr++;
      }
    }
    
    void zb_memmove(void *dst, const void *src, size_t len)
    {
        size_t i;
    
        /*
          * If the buffers don't overlap, it doesn't matter what direction
          * we copy in. If they do, it does, so just assume they always do.
          * We don't concern ourselves with the possibility that the region
          * to copy might roll over across the top of memory, because it's
          * not going to happen.
          *
          * If the destination is above the source, we have to copy
          * back to front to avoid overwriting the data we want to
          * copy.
          *
          *      dest:       dddddddd
          *      src:    ssssssss   ^
          *              |   ^  |___|
          *              |___|
          *
          * If the destination is below the source, we have to copy
          * front to back.
          *
          *      dest:   dddddddd
          *      src:    ^   ssssssss
          *              |___|  ^   |
          *                     |___|
          */
    
        if ((uintptr_t)dst < (uintptr_t)src)
        {
            zb_memcpy(dst, src, len);
            return;
        }
    
        /*
        * Copy by words in the common case.
        */
        if ((((uintptr_t)dst & 0x3) == 0) &&
            (((uintptr_t)src & 0x3) == 0) &&
            ((len % sizeof(zb_uint32_t)) == 0))
        {
    
            zb_uint32_t *d = dst;
            const zb_uint32_t *s = src;
    
            /*
              * The reason we copy index i-1 and test i>0 is that
              * i is unsigned -- so testing i>=0 doesn't work.
              */
            for (i=len/sizeof(zb_uint32_t); i>0; i--)
            {
                    d[i-1] = s[i-1];
            }
        }
        else
        {
            zb_uint8_t *d = dst;
            const zb_uint8_t *s = src;
    
            for (i=len; i>0; i--)
            {
                    d[i-1] = s[i-1];
            }
        }
    }

    Regards,
    Ryan