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.

RM46L852: Hercules warm reset changing clock speeds

Part Number: RM46L852
Other Parts Discussed in Thread: HALCOGEN

I am working on the hercules bootstrap. It starts up fine from power on reset and runs fine. When I do a jtag reset or press my warm reset button it restarts fine.


However if I bootstrap in a RTOS app that runs at a different clock speed both jtag reset and warm reset do a reset into the hercules bootstrap, but it then hangs waiting on the pll csvstat to get to its expected value in a tight while loop. This is in the Hercules sample bootstrap mapClocks function.

Is there some sample assembler (or better C) code that will unlock the pll so the bootstrap will start up at the new clock rate?

Thanks, Steve

  • Hi Steve,

    It seems this might be related to a known issue on the device. Can you review errata SSWF021#45 and see if the recommended workarounds are effective in repairing the issue? The appropriate errata document will be dependent on the revision of the silicon you are using.

  • Hi Chuck,

    I am running rev c where the failure occurs. It appears the errata is only talking about power on PLL failures. In POR mode so far I always get a lock. The problem happens with either jtag system reset or our board's "warm reset" button. Not too surprising since at least on this Hercules board the jtag reset does a warm reset. My real use mode is when the rtos jumps to the bootstrap and the bootstrap wants to setup the entire system including the clock frequency - and it just hangs in the following wait loop.


    This is the hang routine in system.c of the hercules bootloader (rm46_can_ boot) example:

    void mapClocks(void)
    {
        
    /* USER CODE BEGIN (11) */
    /* USER CODE END */

        /** @b Initialize @b Clock @b Tree: */
        /** - Diable / Enable clock domain */
        systemREG1->CDDIS= (FALSE << 4 ) /* AVCLK 1 OFF */
                          |(TRUE << 5 ) /* AVCLK 2 OFF */
                          |(FALSE << 8 ) /* VCLK3 OFF */
                          |(FALSE << 10) /* AVCLK 3 OFF */
                          |(FALSE << 11); /* AVCLK 4 OFF */

        /** - Wait for until clocks are locked */
        while ((systemREG1->CSVSTAT & ((systemREG1->CSDIS ^ 0xFF) & 0xFF)) != ((systemREG1->CSDIS ^ 0xFF) & 0xFF))
        {
        }

    This while loop hangs until csvstat has the bits exactly equal to 0x73. It works when I do a power on reset, or when I reload the firmware via jtag. When I get in the hang and press pause in ccsv6 ccsvstat is equal to 0x33


    Which according to the trm means that pll2 bit is not set.

    Thanks for any help.

    Steve

  • Hi, I just want to restate one case I find interesting:

    It works when I do a power on reset, or when I reload the firmware via jtag.

    So reset via jtag does not fix the hang, but doing a firmware reload does? There must be some magic incantation on setting up the clock that will get me beyond the hang.

     

    Regards, Steve

  • Hi Steve,

    Before you enter into the while loop, can you check the value of the PLL slip flags in PLL1 and 2 to see if they're set? You could be seeing some glitching on the PLL caused by the reset/restart of the clocks/PLLs that are being captured as PLL slip events. Most likely this would be in PLL2 given the described behavior. You should be able to check if there is a slip encountered by evaluating the content of the ESM registers. You may also get some insight of some things to try by looking at section "14.5.3 Behavior on PLL Fail" of the TRM.
  • Chuck Davenport said:
    section "14.5.3 Behavior on PLL Fail" of the TRM.

    This kind of confuses me. I am using the trm from spnu514b.pdf - The pll info is in section 2.5 and section 10.5.

    In section 10.5.4 Recovery from a PLL Failure, It says " Neither the RFSLIP or FBSLIP status flags in the Global Status Register (GLBSTAT) of

    the System and Peripheral Control Registers are set." Which I confirm, it hangs but has no slip indicator. And the pll2 has no ROS bit.

    But anyway looking at those sections and what ccsv6 is showing me about the 2 registers, I tried just ignoring the pll2 bit:

    /** - Wait for until clocks are locked */
    while ((systemREG1->CSVSTAT & ((systemREG1->CSDIS ^ 0xFF) & 0xBF)) != ((systemREG1->CSDIS ^ 0xFF) & 0xBF))
    {
    }

    Note, I changed the "interesting bits" mask from 0xff to 0xbf.

    So empirically this fixes my restart pll hang problem, but I don't want to just ignore it - maybe there is a real problem? How would I know and is there an approved, official way to restart the pll?

    Thanks, Steve

  • Hi Steve,

    Sorry for the confusion on the chapter numbers. I was looking at the same information in a TRM for a similar Hercules part number and the chapter mapping was a bit different.

    In regard to ignoring the bit for PLL2. Do you use PLL2 in your project? When you restart the clocks do you restart PLL2 as well? If you don't it could be that the bit is never set because it hasn't been restarted/re-locked. i.e., on power up, the PLL2 is coming out of a power down state so it sets the bit when it locks but when you are going through a nRST, it never cycles so the bit never gets set again (in a way it is out of synch). Can you add the code to explicitly initialize and lock PLL2 and see if this helps?
  • Chuck Davenport said:
    Can you add the code to explicitly initialize and lock PLL2 and see if this helps?


    I am using the TI supplied example bootloader start up code. As far as I can tell it is explicitly setting up pll1, pll2 and pll3 before this test. I don't think there is a pll3, but there is a pll3 control register.

    Anyway we do not think we are using the pll2 - it seems to be for clocking some async external device via gpio? So I guess I will just ignore the lock and wait for an associated problem.


    Thanks for your help, Steve

  • Steve,

    So, in reviewing the Halcogen code generated with the latest version of Hlacogen, the clock startup routine uses the following contructs

    /* Disable PLL1 and PLL2 */
    systemREG1->CSDISSET = 0x00000002U | 0x00000040U;
    /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */

    This is used at startup to insure the PLLs are shutdown prior to re-initializing them.

    ALso, can you post your entire clock config code up to the point where it hangs so I can have a look to see if there is anything that is missing that might improve robustness.

  • Hi Chuck,

    No I don't find that code to disable the plls. Should I put it in the setupPLL function?

    Anyway here is the code from the TI ziped hercules bootstrap library "system.c"

    void setupPLL(void)
    {
    unsigned int multiplier;

    /* USER CODE BEGIN (3) */
    /* USER CODE END */

    /** - Configure PLL control registers */
    /** @b Initialize @b Pll1: */

    /** - Setup pll control register 1:
    * - Setup reset on oscillator slip
    * - Setup bypass on pll slip
    * - setup Pll output clock divider to max before Lock
    * - Setup reset on oscillator fail
    * - Setup reference clock divider
    * - Setup Pll multiplier
    */

    /* Fixed DIV: Ref. CLK DIV= 6; Output DIV=2; R DIV=2 for RM42/LS04 and 1 for other */
    /* Mutiflier: Multiplier = (SYS_CTL_CLK*6*2*2)/Crystal = 160*6*2*1/16=120 */
    /* Mutiflier: Multiplier = (SYS_CTL_CLK*6*2*2)/Crystal = 80*6*2*1/16=60 */
    #if defined(TMS570LS04) || defined(RM42)
    multiplier = (SYS_CLK_FREQ*6*2*2)/CRYSTAL_FREQ;
    #else
    multiplier = (SYS_CLK_FREQ*6*2*1)/CRYSTAL_FREQ;
    #endif

    systemREG1->PLLCTL1 = 0x00000000U
    | 0x20000000U
    | ((0x1F)<< 24U) /* R-divider, will be programmed later in mapClock() */
    | 0x00000000U
    | ((6U - 1U)<< 16U) /*reference clock divider:6 */
    | ((multiplier - 1U)<< 8U); /*Multiplier: 120*/

    /** - Setup pll control register 2
    * - Enable/Disable frequency modulation
    * - Setup spreading rate
    * - Setup bandwidth adjustment
    * - Setup internal Pll output divider
    * - Setup spreading amount
    */
    systemREG1->PLLCTL2 = 0x00000000U
    | (255U << 22U)
    | (7U << 12U)
    | ((2U - 1U)<< 9U) /*output divider: 2*/
    | 61U;

    /** @b Initialize @b Pll2: */

    /** - Setup pll2 control register :
    * - setup Pll output clock divider to max before Lock
    * - Setup reference clock divider
    * - Setup internal Pll output divider
    * - Setup Pll multiplier
    */
    systemREG2->PLLCTL3 = ((2U - 1U) << 29U)
    | ((0x1F)<< 24U)
    | ((5U - 1U)<< 16U)
    | ((30U - 1U) << 8U);

    /** - Enable PLL(s) to start up or Lock */
    systemREG1->CSDIS = 0x00000000U
    | 0x00000000U
    | 0x00000008U
    | 0x00000080U
    | 0x00000000U
    | 0x00000000U
    | 0x00000000U;
    }

    <snip>
    void mapClocks(void)
    {

    /* USER CODE BEGIN (11) */
    /* USER CODE END */

    /** @b Initialize @b Clock @b Tree: */
    /** - Diable / Enable clock domain */
    systemREG1->CDDIS= (FALSE << 4 ) /* AVCLK 1 OFF */
    |(TRUE << 5 ) /* AVCLK 2 OFF */
    |(FALSE << 8 ) /* VCLK3 OFF */
    |(FALSE << 10) /* AVCLK 3 OFF */
    |(FALSE << 11); /* AVCLK 4 OFF */

    /** - Wait for until clocks are locked */
    while ((systemREG1->CSVSTAT & ((systemREG1->CSDIS ^ 0xFF) & 0xBF)) != ((systemREG1->CSDIS ^ 0xFF) & 0xBF))
    {
    }

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ hangs here when masked with 0xff ^^^^^^^^^^^^^^^^^


    // while (!(systemREG1->CSVSTAT & 0x040));

    /* USER CODE BEGIN (12) */
    /* USER CODE END */

    /* Now the PLLs are locked and the PLL outputs can be sped up */
    /* The R-divider was programmed to be 0xF. Now this divider is changed to programmed value */
    #if defined(TMS570LS04) || defined(RM42)
    systemREG1->PLLCTL1 = (systemREG1->PLLCTL1 & 0xE0FFFFFF)|((2U - 1U)<< 24U);
    #else
    systemREG1->PLLCTL1 = (systemREG1->PLLCTL1 & 0xE0FFFFFF)|((1U - 1U)<< 24U);
    #endif
    systemREG2->PLLCTL3 = (systemREG2->PLLCTL3 & 0xE0FFFFFF)|((1U - 1U)<< 24U);

    /** - Map device clock domains to desired sources and configure top-level dividers */
    /** - All clock domains are working off the default clock sources until now */
    /** - The below assignments can be easily modified using the HALCoGen GUI */

    /** - Setup GCLK, HCLK and VCLK clock source for normal operation, power down mode and after wakeup */
    systemREG1->GHVSRC = (SYS_PLL1 << 24U)
    | (SYS_PLL1 << 16U)
    | SYS_PLL1;

    /** - Setup synchronous peripheral clock dividers for VCLK1, VCLK2, VCLK3 */
    #if defined(TMS570LS04) || defined(RM42)
    systemREG1->VCLKR = 1; //1U;
    systemREG1->VCLK2R = 1; //1U;
    systemREG2->VCLK3R = 1U;
    #else
    systemREG1->VCLKR = 1; //1U;
    systemREG1->VCLK2R = 1; //1U;
    systemREG2->VCLK3R = 1U;
    #endif
    /* USER CODE BEGIN (13) */
    /* USER CODE END */

    /** - Setup RTICLK1 and RTICLK2 clocks */
    systemREG1->RCLKSRC = (1U << 24U)
    | (SYS_VCLK << 16U)
    | (1U << 8U)
    | SYS_VCLK;

    /** - Setup asynchronous peripheral clock sources for AVCLK1 and AVCLK2 */
    systemREG1->VCLKASRC = (SYS_VCLK << 8U)
    | SYS_VCLK;

    systemREG2->VCLKACON1 = (1U << 24)
    | 1 << 20U
    | (SYS_VCLK << 16)
    | (1U << 8)
    | 1 << 4U
    #if defined(TMS570LS04) || defined(RM42)
    | SYS_VCLK;
    #else
    | SYS_PLL2;
    #endif
    /* USER CODE BEGIN (14) */
    /* USER CODE END */

    }
  • Steve,

    Yes, I would add the CSDIS write to disable the PLL1 and PLL2 at the start of the function. Basically add these lines:

    void setupPLL(void)
    {
    
    /* USER CODE BEGIN (3) */
    /* USER CODE END */
    
        /* Disable PLL1 and PLL2 */
        systemREG1->CSDISSET = 0x00000002U | 0x00000040U;
        /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
        while((systemREG1->CSDIS & 0x42U) != 0x42U)
        {
        /* Wait */
        }
    
        /* Clear Global Status Register */
        systemREG1->GBLSTAT = 0x301U;
    

    Basically, its a good idea in your case to make sure the PLL is disabled prior to reinitializing and re-enabling in the boot loader scenario. This may be contributing but I don't think they are the root cause. The while loop is also  different in the mapClocks function using the current code generated by Halcogen and I suspect it was updated because they found that the register read was somehow being optimized out or not being updated properly in the condition statement. Here is what mapClocks has now:

    /* SourceId : SYSTEM_SourceId_005 */
    /* DesignId : SYSTEM_DesignId_005 */
    /* Requirements : HL_SR469 */
    void mapClocks(void)
    {
        uint32 SYS_CSVSTAT, SYS_CSDIS;
    
    /* USER CODE BEGIN (11) */
    /* USER CODE END */
    
        /** @b Initialize @b Clock @b Tree: */
        /** - Disable / Enable clock domain */
        systemREG1->CDDIS = (uint32)((uint32)0U << 4U ) /* AVCLK 1 OFF */
                          | (uint32)((uint32)1U << 5U ) /* AVCLK 2 OFF */
                          | (uint32)((uint32)0U << 8U ) /* VCLK3 OFF */
                          | (uint32)((uint32)0U << 9U ) /* VCLK4 OFF */
                          | (uint32)((uint32)0U << 10U) /* AVCLK 3 OFF */
                          | (uint32)((uint32)0U << 11U); /* AVCLK 4 OFF */
    
    
        /* Work Around for Errata SYS#46:
         *
         * Errata Description:
         *            Clock Source Switching Not Qualified with Clock Source Enable And Clock Source Valid
         * Workaround:
         *            Always check the CSDIS register to make sure the clock source is turned on and check
         * the CSVSTAT register to make sure the clock source is valid. Then write to GHVSRC to switch the clock.
         */
        /** - Wait for until clocks are locked */
        SYS_CSVSTAT = systemREG1->CSVSTAT;
        SYS_CSDIS = systemREG1->CSDIS;
        while ((SYS_CSVSTAT & ((SYS_CSDIS ^ 0xFFU) & 0xFFU)) != ((SYS_CSDIS ^ 0xFFU) & 0xFFU))
        {
            SYS_CSVSTAT = systemREG1->CSVSTAT;
            SYS_CSDIS = systemREG1->CSDIS;
        } /* Wait */
    

    Of course, if your not using PLL2, you can simply disable it and not worry about all of this. It would result in a reduction of power as well.