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.

C28346 Control card PLL/Boot issue

Other Parts Discussed in Thread: CONTROLSUITE

Hi all,

I am using the C28346 Control cord with the Delfino C28346 DIM168 Experimenter's Kit. (Code composer  5.4.0.00091 using the USB to program/debug the device)

I am writing my own hello world program which flashes a LED. (Watchdog is disabled)

When I try to set the PLL settings to generate a 300 MHz clock (from the 20 MHz crystal on the dev board) the program jumps to 0x3FF626, which is somewhere in the BOOT ROM.

The strange thing is this only occurs when I press 'run' in the debugger (without any other break point set). When I step through the program it never crashes. It seems to be timing related. The code I use for the PLL settings is this:

// Configure PLL
const uint16_t InputMultiplier = 29;  // CpuClock = 20MHz * 30 / 2 = 300MHz
const uint16_t LowSpeedDivider = 2;  // LspClock =  300MHz / 4 = 75MHz

F28x::CPll Pll;
Pll.Init(InputMultiplier, LowSpeedDivider);
void CPll::Init
(
  const uint16_t InputMultiplier
, const uint16_t LowSpeedDivider
) const
{
  asm( "        EALLOW" );

  // Ensure PLL is on
  mrSystem.PLLSTS.bit.PLLOFF = 0x0;

  // Always set to 0
  mrSystem.PLLSTS.bit.DIVSEL = 0x0;
    
  // Configure multiplier and wait until locked
  mrSystem.PLLCR.bit.DIV = InputMultiplier;

  while( 0x0 == mrSystem.PLLSTS.bit.PLLLOCKS )
  {
  }

  mrSystem.PLLSTS.bit.DIVSEL = 0x2;

  // Configure high & low-speed prescalers
  mrSystem.LOSPCP.bit.LSPCLK = LowSpeedDivider;

  asm( "        EDIS" );
}

I've also found out that adding some delay to the Pll.Init() function result the the program running normally:

  void CPll::Init
  (
    const uint16_t InputMultiplier
  , const uint16_t LowSpeedDivider
  ) const
  {
    asm( "        EALLOW" );

    // Ensure PLL is on
    mrSystem.PLLSTS.bit.PLLOFF = 0x0;


    // Always set to 0
    mrSystem.PLLSTS.bit.DIVSEL = 0x0;
    
    // Configure multiplier and wait until locked
    mrSystem.PLLCR.bit.DIV = InputMultiplier;

    while( 0x0 == mrSystem.PLLSTS.bit.PLLLOCKS )
    {
    }

    for(uint32_t i=0; i<1000; i++)
    {
      F28x::DelayUs(50);
    }

    mrSystem.PLLSTS.bit.DIVSEL = 0x2;

    for(uint32_t i=0; i<1000; i++)
    {
      F28x::DelayUs(50);
    }

    // Configure high & low-speed prescalers
    mrSystem.LOSPCP.bit.LSPCLK = LowSpeedDivider;

    asm( "        EDIS" );
  }

But I want to find the root cause of the problem because I'm afraid this will not permanently fix the problem. I Then tried the "FlashingLeds-C28346_168" demo.

This programs works fine if the setting for the PLL is left as default:

// SYSTEM CLOCK speed based on Crystal = 20 MHz (R1.1 controlCARD)
// 0x0	= 10	Mhz	(0)
// 0x1	= 20	Mhz	(1)
// 0x2	= 30	Mhz	(2)
// 0x3	= 40	Mhz	(3)
// 0x4	= 50	Mhz	(4)
// 0x5	= 60	Mhz	(5)
// 0x6	= 70	Mhz	(6)
// 0x7	= 80	Mhz	(7)
// 0x8	= 90	Mhz	(8)
// 0x9	= 100	Mhz	(9)
// 0x13	= 200	Mhz	(19)
// 0x14	= 210	Mhz	(20)
// 0x15	= 220	Mhz	(21)
// 0x16	= 230	Mhz	(22)
// 0x17	= 240	Mhz	(23)
// 0x18	= 250	Mhz	(24)
// 0x19	= 260	Mhz	(25)
// 0x1A	= 270	Mhz	(26)
// 0x1B	= 280	Mhz	(27)
// 0x1C	= 290	Mhz	(28)
// 0x1D	= 300	Mhz	(29)


PLLset(0x13);	// choose from options above based on the reference crystal

But I found out that it stops working for values higher than 0x18. (i.e. the led does not start blinking anymore)

So this issue is also present on the TI supplied code. Can someone verify this and explain why this occurs?

  • Hi Ron,

    I would recommend using the InitPll() function in the below source file as a reference.
    \controlSUITE\device_support\c2834x\v112\DSP2834x_common\source\DSP2834x_SysCtrl.c

    This file is what we use in testing our device and it has been proven good.  Comparing it with your code and the relevant FlashingLeds code, I see a few differences which may be worth exploring.  Could you try one of the examples in the below folder (or try with this code in your project) to see if you are now able to reach 300MHz?
    \controlSUITE\device_support\c2834x\v112\DSP2834x_examples_ccsv4\

    Hopefully this helps.


    Thank you,
    Brett

  • Brett,

    I used the InitPll function from \controlSUITE\device_support\c2834x\v112\DSP2834x_common\source\DSP2834x_SysCtrl.c as you suggested.

    It works without issues: (Thanks!)

      void CPll::Init(const uint16_t val, const uint16_t divsel)
      {
        // DIVSEL MUST be 0 before PLLCR can be changed from
        // 0x0000. It is set to 0 by an external reset XRSn
        // This puts us in 1/8
        if (mrSystem.PLLSTS.bit.DIVSEL != 0)
        {
          asm( "        EALLOW" );
          mrSystem.PLLSTS.bit.DIVSEL = 0;
          asm( "        EDIS" );
        }
    
        // Change the PLLCR
        if (mrSystem.PLLCR.bit.DIV != val)
        {
    
          asm( "        EALLOW" );
          mrSystem.PLLCR.bit.DIV = val;
          asm( "        EDIS" );
    
          // Optional: Wait for PLL to lock.
          // During this time the CPU will switch to OSCCLK/2 until
          // the PLL is stable.  Once the PLL is stable the CPU will
          // switch to the new PLL value.
          //
          // This time-to-lock is monitored by a PLL lock counter.
          //
          // Code is not required to sit and wait for the PLL to lock.
          // However, if the code does anything that is timing critical,
          // and requires the correct clock be locked, then it is best to
          // wait until this switching has completed.
    
          // Wait for the PLL lock bit to be set.
    
          // The watchdog should be disabled before this loop, or fed within
          // the loop via ServiceDog().
    
          // Uncomment to disable the watchdog
          //  DisableDog();
    
          while(mrSystem.PLLSTS.bit.PLLLOCKS != 1)
          {
            // Uncomment to service the watchdog
            // ServiceDog();
          }
    
        }
    
        // If switching to 1/4
        if (divsel == 1)
        {
          asm( "        EALLOW" );
          mrSystem.PLLSTS.bit.DIVSEL = divsel;
          asm( "        EDIS" );
        }
    
    
        // If switching to 1/2
        // * First go to 1/4 and let the power settle
        //   The time required will depend on the system, this is only an example
        // * Then switch to 1/2
        if(divsel == 2)
        {
          asm( "        EALLOW" );
          mrSystem.PLLSTS.bit.DIVSEL = 1;
          F28x::DelayUs(50L);
          mrSystem.PLLSTS.bit.DIVSEL = 2;
          asm( "        EDIS" );
        }
    
        // If switching to 1/1
        // NOTE: ONLY USE THIS SETTING IF PLL IS BYPASSED (I.E. PLLCR = 0)
        // * First go to 1/4 and let the power settle then go to 1/2 and let the power settle
        //   The time required will depend on the system, this is only an example
        // * Then switch to 1/1
        if(divsel == 3)
        {
          asm( "        EALLOW" );
          mrSystem.PLLSTS.bit.DIVSEL = 1;
          F28x::DelayUs(50L);
          mrSystem.PLLSTS.bit.DIVSEL = 2;
          F28x::DelayUs(50L);
          mrSystem.PLLSTS.bit.DIVSEL = 3;
          asm( "        EDIS" );
        }
      }

    This is also based on the same solution as I already found, which is to add delays after changing the DIVSEL value. I guess this is the only way to make it work but why is this necessary and why does the datasheet not include this in its PLL change procedure?

  • Hi Brett,

    The InitPll function from \controlSUITE\device_support\c2834x\v112\DSP2834x_common\source\DSP2834x_SysCtrl.c indeed works for me, thanks.

    But is also relies on the DELAY_US(50L); after a change to DIVSEL. Is this the only correct way then of configuring the PLL? And why does the PLL change procudre in the datasheet not mention this delay?