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.

C6670 PLL configuration to the 1200 MHz

Other Parts Discussed in Thread: TMS320C6670

Hi, everyone,

 

We are trying to run the TMS320C6670 at 1200 MHz CPU frequency. We are using pdk_C6670_1_1_2_6 and we found couple of bugs in the platform_init() routine.

 

1) one of the arguments of the platform_init() function is the structure platform_init_config. But the thing is that only the pllm and mastercore are usable parameters. All dividers don't change anything, which make the frequency process adjustment very annoying.

2) in the prog_pll1_values function on the line 92 BWADJ value calculated incorrectly:

 

temp = ((hwSetup->pllM + 1)>> 1) - 1;

 

According to the data manual, BWADJ parameter is half of PLLM rounded down. For instance, we are trying to set PLLM=624 and PLLD=31 as n Table 2-13 of the data manual. With input clock 122.88 MHz and output divider enabled that gives 122.88*(624+1)/2/(31+1)=1200 MHz. If so, BWADJ=PLLM/2 should be 624/2=312. Above formula calculates it wrong to 311.

 

We don't need to subtract 1, because we do that in the platform init function on the line's 383-384:

 

pllc_hwSetup.pllM =

(((p_config->pllm) ? p_config->pllm : PLATFORM_PLL1_PLLM_val) - 1);

 

Just in case, prog_pll1_values() functions does violate prescribed sequence of PLLM programming. According to the data manual, upper [12:6] bits of PLLM should be written to MAINPLLCTL0 before programming lower [5:0] bits of PLLM to PLLM register.

 

3) the CorePllcGetHwSetup function working just incorrectly, because on the line 291:

hwSetup->preDiv     =  PREDIV_REG;

 

and if we go to the platform_internal.h:

#define   PREDIV_REG            (*((volatile uint32_t *) 0x02310114))

 

So the thing is that in the Data manual it's said that 0x02310114 is a Reserved address, but not the address of the preDiv. We check that, and we notice that it's has value of 0, no matter what preDiv you establish.

Moreover, the value of PLLM is read incorrectly here. PLLM is split in two fields, bits [5:0] read from PLLM control register of the PLL controller, while its upper [12:6] bits have to be read from MAINPLLCTL0. This read and bitfields merger are not performed in the mentioned function, so just 6 LSbs are returned, not real PLLM.

That is why the platform_get_frequency () function calculating the wrong frequency value, and ONLY in the case of default preDiv (which is 1) it's working correctly.

 

I wonder if TI has any idea, how the customer should cope with those troubles. Is there any solution to deal with all of that without make changes into the library? I doubt that all my company members would be happy to change in on their PC, especially every new PDK version will be released.

 

Best Regards,

Pavlo!

  • Hi Pavlo,
    I'm working on this issue and get back to you.
  • Could you please suggest, is there any way to probe resulting frequency on some output pin with a scope to make sure we got right frequency?
  • Hello Rrlagic,

    The SYSCLKOUT pin (AA26 in C6670 device) is available to probe resulting frequency with a scope to make sure you got right frequency. Please note SYSCLKOUT is derived from SYSCLK7 and you need to enable it in the register DEVCFG.SYSCLKOUTEN.

    Regards,
    Senthil
  • Hello,
    Thank you for suggestion. Unfortunately, that pad was not routed. Wrote on wishlist for next revision of the board.
  • Hi,
    I hope you have 1.2GHz supported C6670 EVM.
    You can confirm with DEVSPEED register (0x026203F8)
    You can also use gel file code in your app to configure to 1.2GHz.

    Which type of board are you testing ?

    Custom or EVM board ?

    Right now, just I have 1GHz alone and don't have 1.2GHz to modify & test.

    I'm working on your reported issues.

  • Hello,

    Thank you for your care about our issue. I am a colleague of Pavlo, so let me clarify the situation.

    We are working on a custom board with TMS320C6670ACYP2. That chip does support 1.2GHz core clock. We have read DEVSPEED register and found correct value. So, on h/w side everything is just fine to run at 1.2GHz.

    I have looked at GEL file guts at TI\ccsv6\ccs_base\emulation\boards\evmc6670l\gel\evmc6670l.gel. It does contain all the same mistakes and violations. Let me explain.

    Let us see the function prog_pll1_values() in above mentioned GEL file. Before we proceed, may I note, that use of argument names like pll_multiplier, pll_divider is misleading just because those values are not defined in the data manual. In the manual one would find the formula CLK=CLKIN*(PLLM+1)/(2*(PLLD+1)). So, pll_multiplier - is that (PLLM+1) or PLLM? The former is actual multiplication factor, the latter is multiplier register value.

    What is term "2" in denominator? I'm sure that is output divider. But isn't it programmable? Description of SECCTL tell it is, so I would say correct formula is  CLK=CLKIN*(PLLM+1)/((OUTPUTDIVIDE+1)*(PLLD+1)). However, take a look at Figure 7-7 in the data manual. Do you see there CLK? Or maybe CLKIN? No! There are SYSCLK, ALTCORECLK, while actual PLL input is not marked, and PLL output clock is labelled as PLLOUT, not CLK. If I was about to give a code or manual to colleague or customer I would care to not have such ambiguity.

    Well, that's minor. Let us see the code at line 1245:

    /* Set pll multipler (13 bit field) */                            
    PLL1_PLLM     = (pll_multiplier & 0x0000003F); /* bits[5:0]  */   
    TEMP          = (pll_multiplier & 0x1FC0) >> 6;/* bits[12:6] */   
    MAINPLLCTL0  &=~(0x0007F000);                /*Clear PLLM field */
    MAINPLLCTL0  |=((TEMP << 12) & 0x0007F000);                       
    

    This fragment shows that pll_multiplier was meant to be PLLM. OKAY. Let us proceed to the data manual SPRS689D, page 139, a note in the top of the page:

    MAINPLLCTL0 register PLLM[12:6] bits should be written just before writing to PLLM register PLLM[5:0]

    I read above fragment as "First write MAINPLLCTL0, after that write PLLM register". English is not my native language, but I hope I understood that correct. Do you see that in above fragment of the code the sequence is exactly opposite: PLLM reg is written first, then MAINPLLCTL0. How do we judge this situation? GEL file is wrong? Data manual note is not significant?

    Next, let us proceed to BWADJ value setup at line 1250:

    /* Set the BWADJ     (12 bit field)                                          *  
      * BWADJ[11:8] and BWADJ[7:0] are located in MAINPLLCTL0 and MAINPLLCTL1     * 
      * registers. BWADJ[11:0] should be programmed to a value equal to half of   * 
      * PLLM[12:0] value (round down if PLLM has an odd value)                    * 
      * Example: If PLLM = 15, then BWADJ = 7                                     */
     TEMP = ((pll_multiplier + 1) >> 1) - 1; /* Divide the pllm by 2 */             
     MAINPLLCTL0 &=~(0xFF000000);  /* Clear the BWADJ Field */                      
     MAINPLLCTL0 |=  ((TEMP << 24) & 0xFF000000);                                   
     MAINPLLCTL1 &=~(0x0000000F);   /* Clear the BWADJ field */                     
     MAINPLLCTL1 |= ((TEMP >> 8) & 0x0000000F);                                     
    

    Again, I clearly see, that BWADJ should be the half of PLLM, rounded down if PLLM is odd. As we just discovered in above fragment, pll_multiplier is used for PLLM. Imagine PLLM is 15, then ((15+1)>>1)-1 would give you 7. But wait, what if PLLM is 624? See, 624+1=625, then 625>>1=312, and finally 312-1=311. So, is BWADJ=311 a half of PLLM=624? I would say it is not. So again, there is an error in the code.

    For you to know, the function prog_pll1_values() in TI\pdk_C6670_1_1_2_6\packages\ti\platform\evmc6670l\platform_lib\src\evmc6670.c has all the same errors, but with more ambiguous variable names added. I would be happy if that's all. But take a look at the function CorePllcGetHwSetup() in evmc6670.c starting at line 288.

    hwSetup->divEnable = 0;                 
                                            
    hwSetup->pllM       = (PLLM_REG & 0x3F);
    hwSetup->preDiv     = PREDIV_REG;       
    hwSetup->pllDiv2    = PLLDIV2_REG ;     
    hwSetup->pllDiv5    = PLLDIV5_REG;      
    hwSetup->pllDiv8    = PLLDIV8_REG;      
    

    What a hell is hwSetup->divEnable = 0;? Aren't we supposed to read that value from the register?

    What a hell is hwSetup->pllM = (PLLM_REG & 0x3F); PLLM is 13-bit field stored in two registers, so to get correct value of PLLM one have to read two registers and merge appropriate bit fields.

    What a hell is hwSetup->preDiv     = PREDIV_REG;? evmc6670.c has the only include "platform_internal.h", and in TI\ccsv6\ccs_base\emulation\boards\evmc6670l\gel\platform_internal.h one may find

    #define   PREDIV_REG            (*((volatile uint32_t *) 0x02310114))

    OKAY, proceed to SPRS689D data manual, Table 7-14 in the clause 7.5.2 PLL Controller Memory Map:

    Hex Address Range     Acronym       Register Name
    0231 0114                -          Reserved

    I do qualify that as read from reserved location. Isn't it undefined?

    Now let us proceed to TI\pdk_C6670_1_1_2_6\packages\ti\platform\evmc6670l\platform_lib\src\platform.c, function platform_get_frequency(), see at line 116:

    dsp_freq = (hwSetupRead.pllM + 1)>> 1;                                      
    dsp_freq = (dsp_freq * PLATFORM_BASE_CLK_RATE_MHZ)/(hwSetupRead.preDiv + 1);
    

    Do I need to explain, why this fragment does not work right with even PLLM? Should I mention that output divider is hardcoded to be on?

    Finally, please do not take this post as a hate speech. Just understand us, your customers. We reviewed just couple lines of code and found so many troubles there. I am just afraid to use any provided code after that. It would be nice if someone reviewed and told if there is any hope to get that usable.

    Thanks in advance.

  • Hi,

    What is term "2" in denominator? I'm sure that is output divider. But isn't it programmable? Description of SECCTL tell it is, so I would say correct formula is CLK=CLKIN*(PLLM+1)/((OUTPUTDIVIDE+1)*(PLLD+1)). However, take a look at Figure 7-7 in the data manual. Do you see there CLK? Or maybe CLKIN? No! There are SYSCLK, ALTCORECLK, while actual PLL input is not marked, and PLL output clock is labelled as PLLOUT, not CLK. If I was about to give a code or manual to colleague or customer I would care to not have such ambiguity.


    The denominator is "2" default divider "two", we can't change it.

    In gel file, mentioned PLLM=31; PLLD=1 to generate DSP clock 983MHz (~1GHz).

    DSP_FREQ = {122.88MHz * (31+1)} / (1+1)
    = 196608 / 2 (default divider value) // denominator value "2" used now here
    = 98304 = 983MHz

    If you want to generate 1.2GHz on C6670 with ref clock 122.88MHz, then

    You have to use PLLM = 624, PLLD = 31

    DSP_FREQ = {122.88MHz * (624+1)} / (31+1)
    = 240000 / 2 (default divider value) // denominator value "2" used now here
    = 120000 = 1.2GHz

    Try to use the following line in gel file and share the gel file o/p log.

    // Init_PLL(PLL1_M, PLL1_D);//Also can use 471,28
    Init_PLL(624, 31);//Titus : DSP @ 1.2GHz

    PS: I don't have a EVM with 1.2GHz processor.
  • Hi,
    Also, I've tried the following line in gel file to generate 1GHz freq. Try this and let me know the results.

                Init_PLL(471, 28);//Titus : DSP @ 1.0GHz

    I can understand that some discrepancy there by referring on various documents(UG,manual etc.,) , sorry for that.

    Well, that's minor. Let us see the code at line 1245:

    1
    2
    3
    4
    5
    /* Set pll multipler (13 bit field) */                           
    PLL1_PLLM     = (pll_multiplier & 0x0000003F); /* bits[5:0]  */  
    TEMP          = (pll_multiplier & 0x1FC0) >> 6;/* bits[12:6] */  
    MAINPLLCTL0  &=~(0x0007F000);                /*Clear PLLM field */
    MAINPLLCTL0  |=((TEMP << 12) & 0x0007F000);                      

    This fragment shows that pll_multiplier was meant to be PLLM. OKAY. Let us proceed to the data manual SPRS689D, page 139, a note in the top of the page:

    MAINPLLCTL0 register PLLM[12:6] bits should be written just before writing to PLLM register PLLM[5:0]

    I read above fragment as "First write MAINPLLCTL0, after that write PLLM register". English is not my native language, but I hope I understood that correct. Do you see that in above fragment of the code the sequence is exactly opposite: PLLM reg is written first, then MAINPLLCTL0. How do we judge this situation? GEL file is wrong? Data manual note is not significant?




    In gel file, actually we followed the PLL UG (sprugv2f) PLL sequence 3.1.1, that sequence not followed in this PLL UG.
    In 4th step of PLL init (3.1.1, page no 16), write PLLM -> MAINPLLCTL0
    Need to confirm factory team for that on which one is correct.
    Let me check and confirm.

    Next, let us proceed to BWADJ value setup at line 1250:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /* Set the BWADJ     (12 bit field)                                          * 
      * BWADJ[11:8] and BWADJ[7:0] are located in MAINPLLCTL0 and MAINPLLCTL1     *
      * registers. BWADJ[11:0] should be programmed to a value equal to half of   *
      * PLLM[12:0] value (round down if PLLM has an odd value)                    *
      * Example: If PLLM = 15, then BWADJ = 7                                     */
     TEMP = ((pll_multiplier + 1) >> 1) - 1; /* Divide the pllm by 2 */            
     MAINPLLCTL0 &=~(0xFF000000);  /* Clear the BWADJ Field */                     
     MAINPLLCTL0 |=  ((TEMP << 24) & 0xFF000000);                                  
     MAINPLLCTL1 &=~(0x0000000F);   /* Clear the BWADJ field */                    
     MAINPLLCTL1 |= ((TEMP >> 8) & 0x0000000F);                                    

    Again, I clearly see, that BWADJ should be the half of PLLM, rounded down if PLLM is odd. As we just discovered in above fragment, pll_multiplier is used for PLLM. Imagine PLLM is 15, then ((15+1)>>1)-1 would give you 7. But wait, what if PLLM is 624? See, 624+1=625, then 625>>1=312, and finally 312-1=311. So, is BWADJ=311 a half of PLLM=624? I would say it is not. So again, there is an error in the code.

    I'll check with team, any problem could occur due to wrong BWADJ value.

    It seems to be calculating right values for ODD multiplier value and not for EVEN values.

    So, you can try this code and update us.

    Global_Default_Setup_Silent():
    
                Init_PLL(624, 31);//Titus ; DSP @ 1.2GHz
    
    
    prog_pll1_values():
    
        if(pll_multiplier % 2 == 0)
        {
            TEMP = ((pll_multiplier + 1) >> 1); // Divide the pllm by 2
            GEL_TextOut ( "Titus : FOUND EVEN MULTIPLIER; TEMP %d pll_multiplier %d\n",,2,,,TEMP,pll_multiplier);
        }
        else
        {
            TEMP = ((pll_multiplier + 1) >> 1) - 1; // Divide the pllm by 2
            GEL_TextOut ( "Titus : FOUND ODD MULTIPLIER; TEMP %d pll_multiplier %d \n",,2,,,TEMP,pll_multiplier);
    
        }
    
    
    //    TEMP = ((pll_multiplier + 1) >> 1) - 1; /* Divide the pllm by 2 */
    
        MAINPLLCTL0 &=~(0xFF000000);  /* Clear the BWADJ Field */
        MAINPLLCTL0 |=  ((TEMP << 24) & 0xFF000000);
        MAINPLLCTL1 &=~(0x0000000F);   /* Clear the BWADJ field */
        MAINPLLCTL1 |= ((TEMP >> 8) & 0x0000000F);

  • Hi,

    What a hell is hwSetup->preDiv     = PREDIV_REG;? evmc6670.c has the only include "platform_internal.h", and in TI\ccsv6\ccs_base\emulation\boards\evmc6670l\gel\platform_internal.h one may find

    1
    #define   PREDIV_REG            (*((volatile uint32_t *) 0x02310114))

    OKAY, proceed to SPRS689D data manual, Table 7-14 in the clause 7.5.2 PLL Controller Memory Map:

    1
    2
    Hex Address Range     Acronym       Register Name
    0231 0114                -          Reserved

    I do qualify that as read from reserved location. Isn't it undefined?

    #define   PREDIV_REG            (*((volatile uint32_t *) 0x02310114))


    Its read and write register only and will check with factory team for updating the doc.

    PREDIVIDER is the one which presents before PLLM.

  • Hello Titus,

    Thank you for keep watching. Because there are several issues, let me comment them separately to not loose any one.

    First of all, I do not understand, why you say we cannot change output divider. According to data manual, clause 7.5.2.1 PLL Secondary Control Register (SECCTL), output divider can have 2 allowed values:

    Output divider ratio bits
    0h = ÷1. Divide frequency by 1
    1h = ÷2. Divide frequency by 2

    To be sure, we got the EVM an tried to program 0 and 1 to this register and we observed appropriate frequencies synthesized. I believe output divider is programmable and we saw how appropriate programming of secondary control register does take effect.

    Another story is that prog_pll1_values() function programs output divider always 2. See line 105 of TI\pdk_C6670_1_1_2_6\packages\ti\platform\evmc6670l\platform_lib\src\evmc6670.c :

    SECCTL_REG   |= ((1 << 19) & 0x00780000) ;

    In contrast, prog_pll1_values() function in TI\ccsv6\ccs_base\emulation\boards\evmc6670l\gel\evmc6670l.gel programms this value as

    PLL1_SECCTL   |= ((odiv << 19) & 0x00780000) ;

    Another story is that this function is called as

    prog_pll1_values(pll_mult, pll_div, 1);

    in Init_PLL function of the GEL file, in other words, the divider was hardcoded there.

    Again, I saw that output divider can be programmed either 0 or 1, resulting in effective division by 1 or 2 and I observed those changes on TP12 of the EVM, which is DSP_SYSCLKOUT.

    Could you please clarify, why you believe output divider cannot be changed?

  • Its me again,

    When it is about integer division, rounding down happens naturally. So one can get right BWADJ value with simple division:

    TEMP = pll_multiplier / 2; /* Divide the pllm by 2 */              
    MAINPLLCTL0 &=~(0xFF000000);  /* Clear the BWADJ Field */                       
    MAINPLLCTL0 |=  ((TEMP << 24) & 0xFF000000);                                   
    MAINPLLCTL1 &=~(0x0000000F);   /* Clear the BWADJ field */                      
    MAINPLLCTL1 |= ((TEMP >> 8) & 0x0000000F);    

    This way 14/2=7, 15/2=7, 16/2=8. Compiler is smart enough to see integer division, though one may opt to use RSH operation as

    TEMP = pll_multiplier >> 1; /* Divide the pllm by 2 */

    This will give exactly same result. No need to make unnecessary conditions to check, whether PLLM was even or odd. And yes, we tried that in our setup.

    One thing I ask you to clarify, what is correct value for BWADJ. Could you please contact aware person with the example of 14/2=7, 15/2=7, 16/2=8?

    Thanks in advance.

  • Hello again,

    Could you please clarify, what is a meaning of "read and write register only"?

    Second, if we think about PLLD, its value is supposed to be programmed to MAINPLLCTL0[5:0]. At least if we refer to either evmc6670.c or evmc6670l.gel, the value of PLLD is programmed to MAINPLLCTL0. I could imagine 0x02310114 might be kind of shadow copy of MAINPLLCTL0, but we checked on hardware, regardless of actual value of PLLD, address 0x02310114 always reads as 0x00000000.

    From what I see,

    #define   PREDIV_REG            (*((volatile uint32_t *) 0x02310114

    cannot be used to get PLLD value. At least on our custom board with 1.2GHz DSP and on EVM we always read 0 from there.

    Could you please clarify this point again?

    Thanks in advance.

  • Hello Titus,
    Could you please update about the progress? Still we want to know about output divider and correct PLLM programming sequence.
    Thanks.
  • Hi,
    In KeyStone I products including both the C6670 and C6678, the output divider of the PLL is fixed at /2. The default value in the OUTPUT DIVIDE field is 1 and that field shouldn’t be changed. Changing this field shouldn’t have an effect.
    I'm following up with team for PLLM programming sequence.
  • Hi,

    Could you please clarify again about output divider? As per SPRS689D data manual, clause 7.5.2.1 PLL Secondary Control Register, SECCTL[22:19] is responsible for output divider and there are two allowed settings:

    Output divider ratio bits

    0h = ÷1. Divide frequency by 1

    1h = ÷2. Divide frequency by 2

    How do I interpret above info?

    And just in case, we tried to change output divider, and I believe we saw appropriate frequency change on EVM. Is there any other document prescribing to not change output divider?

    Thanks.

  • How did you confirm that you are getting appropriate freq for OUTPUT DIVIDE value ?
    Able to see the OUTPUT DIVIDE value after new value get updated ?
  • I saw that output divider can be programmed either 0 or 1, resulting in effective division by 1 or 2 and I observed those changes on TP12 of the EVM, which is DSP_SYSCLKOUT, using oscilloscope. Please see

  • Tell me the settings (PLLM,OUTPUT DIVIDE etc.,)and will check it.
    What is your EVM with exact part and version no ? whether it supports 1.2G (DEVSPEED) ?
  • We used 1GHz EVM, PLLD = 0, PLLM = 7. If output divide is 0, then core speed is 122.88*(1+7)/(1+0)/(1+0)=983.04 MHz. SYSCLKOUT is 1 / 6 of that, which is 163.84 MHz. We saw that frequency on TP12. If output divide is 1, then we saw 81.92 MHz on TP12.
  • Hi,

    I don't see that behavior on C6670( @1GHz) EVM board and able to see the 163MHz for odiv=0 and 1

    Could you please check one more time.

    BTW, which source are you using gel file or platform code ?

    FYI : I've tested this using gel file.

    Function : Global_Default_Setup_Silent()

    Init_PLL(7, 0);//Titus ; DSP @ 983MHz (PLLM=7,PLLD=0,OUTPUT DIVIDE=0)

    Function : hotmenu Init_PLL(int pll_mult, int pll_div )

    prog_pll1_values(pll_mult, pll_div, 0); //FYI : 3rd argument is the OUTPUT DIVIDE

    Function : prog_pll1_values(unsigned int pll_multiplier, unsigned int pll_divider, unsigned int odiv)

       /* Set the OUTPUT DIVIDE (4 bit field) in SECCTL */

       PLL1_SECCTL    &= ~(0x00780000);     /* Clear the field       */

       PLL1_SECCTL   |= ((odiv << 19) & 0x00780000) ;

  • Hello Titus,

    Neither platform code, nor gel file are not suitable to do the job, because as I explained in the https://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/p/424517/1519906#1519906 both methods were hardcoding 1. I noticed you have changed GEL file, but I am not strong in that. Instead, we have modified platform code in a way that it allows programming of all values. To make sure, please monitor SECCTL at 0x02310108. It has value of 0x00090000 when ODIV is 1 and 0x00010000 when ODIV is 0. We made a short video to demonstrate.

    www.youtube.com/watch

  • Hi,
    Thanks for your video.
    Yes, I'm also able to see that behavior, it means OUTPUT DIVIDE is accessible only with 0h and 1h and not anyother values.
    Let me ask internal team that why I'm facing this behavior.
  • Well, I think we just confirmed, that output divider can produce division by 1 or 2, and that correlates with data manual. I think you could not change the divider because of hardcoded values. It would be nice if both gel and platform C code get updated to allow greater flexibility.
    And as soon you going to contact other group, may I ask to clarify about PLLM programming sequence and BWADJ value calculation. It would be nice if related code get fixed in platform too.
    Thanks.
  • Sure, I will also ask other points too.
    Can you please try OUTPUT DIVIDE in 3h ?
  • Hi,
    I'm also getting modified frequency for 0x3h (~41MHz)
    I've requested the factory to look into that.
    Let me update once I get update.