This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2640R2F: CC2640R2F: OSC_AdjustXoscHfCapArray

Part Number: CC2640R2F

Hi,

I've exact the same need for a BLE Project where I use SDK version 4.10 for CC2640r2 chip. 

Thanks to all of you, I'm able to make the dynamic configuration work for my project. 

However, I do make a modification in the osc.c file to make it work. 

As mentioned in the TechnicManual: The XOSCHF is stable when the DDI_0_OSC:STAT0.PENDINGSCLKHFSWITCHING is asserted after starting the crystal. So I had to add a check of this flag at the beginning of OSCHF_SwitchToRcOscTurnOffXosc function. Otherwise, my application will go to ICall_abort for all the time. 

Could you explain why OSCHfSourceReady is called in OSCHF_AttemptToSwitchToXosc but not OSCHF_SwitchToRcOscTurnOffXosc ? As the two APIs are used to switch osc source. 

Best regards,

Yang

  • Hi Yang, thank you for the detailed information. Either I or someone on my team will get back to you with the relevant information as soon as we can.

  • Hi Yang,

    Thank you for reaching out. I believe you will find the links to the API documentation for each of those API calls useful. I have them listed below:

    OSCHfSourceReady()

    OSCHF_AttemptToSwitchToXosc()

    OSCHF_SwitchToRcOscTurnOffXosc()

    Upon reviewing the documentation, it seems that the reason that OSCHF_SwitchToRcOscTurnOffXosc() does not call OSCHfSourceReady() to verify is because this functions should only be called if the XOSC_HF is ready. This allows the function to execute faster because it has less processing to do. However, this means that the responsibility of verifying if the XOSC_HF is ready for the switch is passed onto the programmer. The OSCHF_AttemptToSwitchToXosc() checks if the XOSC_HF is ready and does the switch if it is ready. This means that this function will take longer than the other function, but ensures that this switch occurs only if the XOSC_HF is ready.

    Best Regards,

    Jan

  • Hi Jan,

    Thanks for your quick response.

    I do read this documents, and I've tested with the host_test project by two different SWs:

    1st SW: 

    1. at the end of HostTestApp_init after line "Host_testApp_Queue = Queue_create(NULL, NULL);", call OSCClockSourceGet to verify the source that is used for OSC_SRC_CLK_HF. And I found, that the return result is OSC_XOSC_HF as expected. With this result, I suppose that my XOSC_HF is already ready. 

    2. call OSCHfSourceReady to verify that it's really ready before calling OSCHF_SwitchToRcOscTurnOffXosc by writing while(!OSCHfSourceReady()), however, my software is stuck here permanently. which means that DDI_0_OSC:STAT0.PENDINGSCLKHFSWITCHING is never set to 1.

    2nd SW:

    1. do the same thing as step1 of 1st SW

    2. call OSCHF_SwitchToRcOscTurnOffXosc by adding "while(!OSCHfSourceReady())" at the beginning of the API. Then I found that DDI_0_OSC:STAT0.PENDINGSCLKHFSWITCHING will change to 1 at a moment which will allow me to turn off the XOSC. I didn't measure the time difference to say it takes how long to change this flag. 

    What I didn't understand is:

    if it's programmer's duty to do the check, why the same check works inside the OSCHF_SwitchToRcOscTurnOffXosc API but not in the HostTestApp_init API?

  • Hi Yang,

    To clarify, you are observing that when you call OSCHF_SwitchToRcOscTurnOffXosc() at the start of HostTestApp_init(), the switch happens as expected, but if you try to call the function at the end of the API, the switch does not happen as expected?

    Best Regards,

    Jan

  • Hi Jan,

    No, what I mean is that, when OSCHfSourceReady() is called inside HostTestApp_init(), the return is never TRUE. But it can be TRUE if it is called inside OSCHF_SwitchToRcOscTurnOffXosc().

    Best regards,

    Yang

  • [deleted]
  • Hi Yang,

    Got it. Thanks for the clarification. This seems strange. I expect the OSCHfSourceReady() to work in this case. Could you try making the call to OSCHfSourceReady() elsewhere in the code to verify if this is the case in this specific area of execution or if it happens throughout the program? Could you verify if this behavior is occurring in simple_peripheral? Also, is there any specific reason why you can't use OSCHF_AttemptToSwitchToXosc() function instead?

    Best Regards,

    Jan

  • Hi Yang,

    I found the following code that uses the OSCHfSourceReady() function. In the code, the hwi is turned off before calling the function. Can you try this and see if the behavior changes?

    E2E Thread: https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/631058/rtos-cc2640r2f-connect-to-external-clock

    Best Regards,

    Jan

  • Hi Jan, 

    I'll clarify what I want to do: our need is to change the XOSC_CAPARRAY_DELTA value at run time in order to facilitate our HW test. In order to do so, I follow the link https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/799819/cc2640r2f-osc_adjustxoschfcaparray

    With the host_test project in SDK v4.10, I've done the following modification to make it work:

    1. at the end of HostTestApp_init(), I add the following code:

    OSCHF_SwitchToRcOscTurnOffXosc();
    /* Create one-shot clocks to wait for 10ms for the Xosc turn off. */
    Util_constructClock(&OneShotClock, vidClockHandler, HTA_XOSC_OFF_EVT_PERIOD, 0, false,
                      HTA_XOSC_EVT);
    Util_startClock(&OneShotClock);

      The reason why I added a one-shot clock of 10ms is to wait for the XOSC to be turned off as suggested by you in the link above

    2. at the end of HostTestApp_taskFxn(), I add the following code:

      if (events & HTA_XOSC_EVT)
      {   
        /* Stop the timer */
        Util_stopClock(&OneShotClock);
        /* Adjust the Xosc Hf Capacitor array delta value 10ms later than Xosc is OFF */
        OSC_AdjustXoscHfCapArray((36));
        OSCHF_TurnOnXosc();
        while(!OSCHF_AttemptToSwitchToXosc())
    
    #ifdef RF_TEST_CW_MODE
        HCI_EXT_SetTxPowerCmd(HCI_EXT_TX_POWER_5_DBM);
        HCI_EXT_ModemTestTxCmd(HCI_EXT_TX_UNMODULATED_CARRIER, RF_TEST_TX_CHAN);
    #endif /*RF_TEST_CW_MODE*/
        }

    With these two parts of code, I'm able to change the XOSC_CAPARRAY_DELTA value at run time as defined by OSC_AdjustXoscHfCapArray() by using a spectrum analyser to check the CW frequency.

    However, I do modify the OSCHF_SwitchToRcOscTurnOffXosc() to make it work as following:

    OSCHF_SwitchToRcOscTurnOffXosc( void )
    {
      while(!OSCHfSourceReady())
      {
        /* waiting for the DDI_0_OSC:STAT0.PENDINGSCLKHFSWITCHING before turn off the XOSC */
      }
       // Set SCLK_HF and SCLK_MF to RCOSC_HF without checking
       // Doing this anyway to keep HF and MF in sync
    #if ( defined( ROM_OSCClockSourceSet ))
       ROM_OSCClockSourceSet( OSC_SRC_CLK_HF | OSC_SRC_CLK_MF, OSC_RCOSC_HF );
    #else
       OSCClockSourceSet( OSC_SRC_CLK_HF | OSC_SRC_CLK_MF, OSC_RCOSC_HF );
    #endif
    
       // Do the switching if not already running on RCOSC_HF
    #if ( defined( ROM_OSCClockSourceGet ))
       if ( ROM_OSCClockSourceGet( OSC_SRC_CLK_HF ) != OSC_RCOSC_HF )
    #else
       if ( OSCClockSourceGet( OSC_SRC_CLK_HF ) != OSC_RCOSC_HF )
    #endif
       {
          OSCHfSourceSwitch();
       }
    
       oscHfGlobals.timeXoscOff_CV  = AONRTCCurrentCompareValueGet();
       oscHfGlobals.tempXoscOff     = AONBatMonTemperatureGetDegC();
    }

     Because when I didn't check OSCHfSourceReady() in the code, the XOSC can be turned off by OSCHF_SwitchToRcOscTurnOffXosc(), but can not be turned on by OSCHF_AttemptToSwitchToXosc() even though the return status is 1. (Note: This part is verified by calling OSCClockSourceGet() which returns OSC_RCOSC_HF after OSCHF_AttemptToSwitchToXosc(). )

    In order to avoid changing osc.c, I've tried to call  OSCHfSourceReady() in HostTestApp_init() before calling OSCHF_SwitchToRcOscTurnOffXosc(). However the return status of OSCHfSourceReady() is always 0.  

    This is the reason why I post the question to you to understand the problem.

    I'll try to add the Hwi management to see if OSCHfSourceReady() works in HostTestApp_init() and also test with simple_peripheral project.

    Best regards,

    Yang

  • Hi Yang,

    Thank you for the thorough explanation. I now have a much better understanding of the inquiry at hand. Please let us know the results of adding the HWI management and verifying with simple_peripheral. This will help us get to the bottom of this more efficiently.

    Best Regards,

    Jan

  • Hi Jan,

    I didn't have time to do the same test in simple_peripheral project. However, I do test with the code below at the end of HostTestApp_init() for HWI and OSCHfSourceReady() remains always false:

    #ifdef CONFIG_XOSC_CAP_DELTA
      unsigned int prevHwi = Hwi_disable();
      while(!OSCHfSourceReady())
      {
        /* waiting for the DDI_0_OSC:STAT0.PENDINGSCLKHFSWITCHING before turn off the XOSC */
      }
      Hwi_restore(prevHwi);
      
      OSCHF_SwitchToRcOscTurnOffXosc();
      /* Create one-shot clocks to wait for 10ms for the Xosc turn off. */
      Util_constructClock(&OneShotClock, vidClockHandler, HTA_XOSC_OFF_EVT_PERIOD, 0, false,
                          HTA_XOSC_EVT);
      Util_startClock(&OneShotClock);
    #endif /* CONFIG_XOSC_CAP_DELTA */

    I have also took the screen shot for Disassembly code for you to check the difference. And I don't understand why the disassembly code are different for these two cases:

    1. OSCHfSourceReady() is called in HostTestApp_init():

    2. OSCHfSourceReady() is called in OSCHF_SwitchToRcOscTurnOffXosc():

    I use the host_test project from SDK, I think you can do the same test from your side to facilitate understanding of the problem.

    Best regards,

    Yang

  • Hi Jan,

    I've just added the call to OSCHfSourceReady() in SimplePeripheral_init() like below:

    and OSCHfSourceReady() returns FALSE at the time like in the host_test project.

    Best regards,

    Yang

  • Hi Yang,

    Thanks for running these steps. Based on these observations, it seems that the OSCHfSourceReady() only works when called within the context of the osc.c file. I noticed that the function is declared with the static keyword which leads me to believe that this is done by design.

    As a quick experiment, can you try removing the static keyword from the function and seeing what behavior is observed?

    Best Regards,

    Jan

  • Hi Jan,

    I've already tried to read the value of the address directly from HostTestApp_init(), and the code stuck always in the while:

    while(((*(volatile uint8_t*)(0x400CA034)) & (0x01)) == 0x00)
    {
    /* waiting for the DDI_0_OSC:STAT0.PENDINGSCLKHFSWITCHING before turn off the XOSC */
    }
    OSCHF_SwitchToRcOscTurnOffXosc();
    /* Create one-shot clocks to wait for 10ms for the Xosc turn off. */
    Util_constructClock(&OneShotClock, vidClockHandler, HTA_XOSC_OFF_EVT_PERIOD, 0, false,
                      HTA_XOSC_EVT);
    Util_startClock(&OneShotClock);

    Normally, this part of code does the same thing as OSCHfSourceReady().

    Best regard,

    Yang

  • Hi Yang,

    Looping in our driver lib experts to comment now. Thank you for your patience.

  • Hi,

    Generally speaking, cap array tuning is not required for BLE applications is not required. The specifications require +/-50ppm crystal accuracy so - unlike sub-1GHz applications - there is no need to modify cap-array tuning.

    To answer the questions, all functions are available globally (not only inside the OSC module). The reason for OSCHfSourceReady() having the keyword “__STATIC_INLINE” is that it must be so when it’s declared in the h-file. Otherwise you could get multiple instances of the same function if used in several compile units (giving linker error).

    The OSCHfSourceSwitch() function are always waiting for HfSourceReady (the ‘PENDING’ bit).

    See a more detailed description of the OSCHfSourceSwitch() behavior below. I’m therefore striving to see why while(!OSCHfSourceReady()) should make any difference.

    Please note that these functions must operate in this order:

          OSCHF_TurnOnXosc();
    
          while(!OSCHF_AttemptToSwitchToXosc());
    
          OSCHF_SwitchToRcOscTurnOffXosc();

    With other words:

    • Do not call OSCHF_TurnOnXosc() if it’s already on.
    • Do not call while(!OSCHF_AttemptToSwitchToXosc()) unless you are currently on RCOSC and have turned on XOSC
    • Do not call OSCHF_SwitchToRcOscTurnOffXosc() unless you are currently on XOSC

     

    I tested this right now by putting it into a while loop like this:

    volatile uint32_t doClockSwitchingTest ;
    
    void TestClockSwitching( void )
    
    {
    
       while ( doClockSwitchingTest ) {
    
          OSCHF_TurnOnXosc();
    
          while(!OSCHF_AttemptToSwitchToXosc());
    
          OSCHF_SwitchToRcOscTurnOffXosc();
    
       }
    
    }

    This works 100% fine for me.

    Randomly setting a breakpoint at this line OSCHF_TurnOnXosc() shows that I’m always on RCOSC

    Randomly setting a breakpoint on this line OSCHF_SwitchToRcOscTurnOffXosc() shows that I’m always on XOSC

     

    And finally a bit more detailed description of what the OSCHfSourceSwitch() ROM function does:

    The OSCHfSourceSwitch() function are always doing the following (inside a ROM function/cannot be executed from Flash):

    1. Wait for ‘PENDINGSCLKHFSWITCHING’ to become true
      (This is the same as OSCHfSourceReady() returning true)
    2. Start the clock switching by setting DDI_0_OSC_CTL0_ALLOW_SCLK_HF_SWITCHING
    3. Wait for ‘PENDINGSCLKHFSWITCHING’ to become false
    4. Clear the clock switching request

     I hope this will help,

    Best regards,

  • Hi Clément,

    Thanks for the detailed explanation about OSCHfSourceSwitch() function. 

    I've retested the code that I've previously posted on the LaunchPad, I found that it works as expected without calling the OSCHfSourceReady() before OSCHF_SwitchToRcOscTurnOffXosc(). 

    I'm not so sure what's happened during my latest tests with the debugger. Fortunately, I'm able to change the cap array value in the run time and test with CW now. 

    Thanks for the help. 

    Best regards