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.

Dynamic frequency changing issue in MSP430

Other Parts Discussed in Thread: TPS61097-33, MSP430F2418

Hello,

I m using MSP430F2418 in my design along with TPS61097-33.

most of the time, the MCU in sleep mode. therefore i disable the regulator in sleep mode and enable when it is woken up.

i change operating frequency to 1 MHz before sleeping and set to 16MHz after woken up (after enabling the regulator).

I have noticed that the MCU got stuck when the frequency is changing. I have observed it happens only changing the frequency from 16MHz to 1 MHz.

this is my code used to change the frequency...

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

void changeFrequency(uint16 fre){

switch(fre){
case 1:
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
break;
case 8:
BCSCTL1 = CALBC1_8MHZ;
DCOCTL = CALDCO_8MHZ;
break;
case 12:
BCSCTL1 = CALBC1_12MHZ;
DCOCTL = CALDCO_12MHZ;
break;
case 16:
BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;
break;
default:
return;
}

uint16 i;

while (IFG1 & OFIFG)
{
// Clear oscillator fault flag
IFG1 &= ~OFIFG;
for (i = 0x4800; i > 0; i--) asm("NOP");
}

runningFrequency = fre;
}

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

It is important that i have change the operating frequency in several places because several peripherals draws large current which affects the supply voltage. those places i have reduce the operating frequencies. 

Thanking you,

Ushan

  • See the device errata BCL12. Changing the RSEL can lead to a DCO dead time or may even stop the DCO alltogether. This depends on the RSEL setting the MCU is currently in and the RSEL you want to switch to. Also it's best to reset DCOCTL before writing new data to BCSCTL1, as it might be that you select a working frequency outside of the specifications.

    Something like this may work:

    void changeFrequency(uint16 fre){
     DCOCTL = 0;
    BCSCTL1 = 0x8D;
    switch(fre){
     ...
     }
    ...
    }

    This will be a waste of power as it always sets RSEL to 13, even if it is not necessary. So a better approach is probably to check if the current RSEL is > 13, and the wanted RSEL is < 13, and only take an intermediate step on RSEL = 13 if this is the case. I'll leave the implementation of that up to you.

     

  • Hi Bernhard,

    i have tried following, as you mentioned.

     DCOCTL = 0;
    BCSCTL1 = 0x8D;

    Still the issue is same. this is a random issue and cannot be seen always.

    could it be a silicone related issue? ( those are bought from a Chinese vendor)

    I ve been using dynamic frequency changing feature for last 6 months with the MCU from Digikey. nothing wrong could be observed.

    I m testing first few sample from China before mass scale manufacturing.

    Thanks ,

    Ushan

  • Maybe a short delay is also needed to let the new RSEL setting settle (so a _delay_cycles(10) or something) after the BCSCTL1 = 0x8D - but the switch() should provide a short delay as well.

    Hmm another thing that might cause this are corrupted calibration values - but then the problem should occur even when not switching the frequency. Can you check the values on the devices where you got that problem and post them here?

    If you get your devices from a different vendor, maybe you can also check which revision you got from digikey and which you get from China - maybe there is an issue because it's a different revision of the chip.

    I hope there are no faked MSPs around. 

  • Hello Bernhard,

    following values are given in IAR

    #define CALDCO_16MHZ_         (0x10F8u)  /* DCOCTL  Calibration Data for 16MHz */
    READ_ONLY DEFC( CALDCO_16MHZ , CALDCO_16MHZ_)
    #define CALBC1_16MHZ_ (0x10F9u) /* BCSCTL1 Calibration Data for 16MHz */
    READ_ONLY DEFC( CALBC1_16MHZ , CALBC1_16MHZ_)
    #define CALDCO_12MHZ_ (0x10FAu) /* DCOCTL Calibration Data for 12MHz */
    READ_ONLY DEFC( CALDCO_12MHZ , CALDCO_12MHZ_)
    #define CALBC1_12MHZ_ (0x10FBu) /* BCSCTL1 Calibration Data for 12MHz */
    READ_ONLY DEFC( CALBC1_12MHZ , CALBC1_12MHZ_)
    #define CALDCO_8MHZ_ (0x10FCu) /* DCOCTL Calibration Data for 8MHz */
    READ_ONLY DEFC( CALDCO_8MHZ , CALDCO_8MHZ_)
    #define CALBC1_8MHZ_ (0x10FDu) /* BCSCTL1 Calibration Data for 8MHz */
    READ_ONLY DEFC( CALBC1_8MHZ , CALBC1_8MHZ_)
    #define CALDCO_1MHZ_ (0x10FEu) /* DCOCTL Calibration Data for 1MHz */
    READ_ONLY DEFC( CALDCO_1MHZ , CALDCO_1MHZ_)
    #define CALBC1_1MHZ_ (0x10FFu) /* BCSCTL1 Calibration Data for 1MHz */
    READ_ONLY DEFC( CALBC1_1MHZ , CALBC1_1MHZ_)
    
    
    
    
    Following values are given in errata sheet (PAGE3)

    CURRENT RSEL TARGET RSEL RECOMMENDED TRANSITION SEQUENCE
    15 14 Switch directly to target RSEL
    14 or 15 13 Switch directly to target RSEL
    14 or 15 0 to 12 Switch to 13 first, and then to
    target RSEL (two step sequence)
    0 to 13 0 to 12 Switch directly to target RSEL
    According to values given in errata sheet, no way to go back to 1MHz  :(  In other words , there is no TARGET SEL =15 in the errata sheet
    
    
    am i right?
  • Hmm no what I meant are the actual values in the information memory of the devices where you got that hangup.

    The defines are only the memory addresses where the calibration is stored. You will have to read out the memory (using JTAG, SBW or BSL) of the device and look at the values at the addresses given by these defines - then you will see the real calibration data.

  • Ushan Karunathilaka said:
    According to values given in errata sheet, no way to go back to 1MHz

    Why that?

    No way back in one single step. but the datasheet clearly states how to do it:

    Ushan Karunathilaka said:
    14 or 15 0 to 12 Switch to 13 first, and then to
    target RSEL (two step sequence)

    Of course you'll need to check the current and target RSEL and not just copy over the calibration values unseen.

  • Ushan Karunathilaka said:
    According to values given in errata sheet, no way to go back to 1MHz

    Why that?

    No way back in one single step. but the datasheet clearly states how to do it:

    Ushan Karunathilaka said:
    14 or 15 0 to 12 Switch to 13 first, and then to
    target RSEL (two step sequence)

    Of course you'll need to check the current and target RSEL and not just copy over the calibration values unseen.

  • okey... i will let you know the calibration values.

    but my question is that given workaround does not indicate RSEL to go back to  15. it has target RSEL from 0 to 14.

    that means i cant go back to some frequency...isnt it?

    Ushan

  • Ushan Karunathilaka said:
    but my question is that given workaround does not indicate RSEL to go back to  15. it has target RSEL from 0 to 14.

    This is because the workaround is only needed when going down. You cannot go down to RSEL_15 from anywhere (as there is no RSEL > 15)

    When going up, the intermediate step is not necessary, but you need to ensure that you do not exceed maximum frequency when doing so (by setting DCOx first, or settign it to 0, then raising RSEL and then setting DCOx to the final value)

  • Hello,

    I have written a new code to apply the workaround for this errata. however still the situation is same

    am i doing anything wrong!

    void changeFreq2(enum eFrequency freq)
    {
    uint8 src, dest, calibDest, calibDCO;
    uint16 i;

    src = BCSCTL1 & 0x0f;

    switch(freq)
    {
    case F_1MHZ: calibDest = CALBC1_1MHZ; calibDCO = CALDCO_1MHZ; runningFrequency = 1; break;
    case F_8MHZ: calibDest = CALBC1_8MHZ; calibDCO = CALDCO_8MHZ; runningFrequency = 8; break;
    case F_12MHZ: calibDest = CALBC1_12MHZ; calibDCO = CALDCO_12MHZ; runningFrequency = 12; break;
    case F_16MHZ: calibDest = CALBC1_16MHZ; calibDCO = CALDCO_16MHZ; runningFrequency = 16; break;
    }

    dest = calibDest & 0x0f;

    if(src == 15 && dest == 14)
    {
    BCSCTL1 = calibDest;
    }
    else if((src > 13) && (dest == 13))
    {
    BCSCTL1 = calibDest;
    }
    else if((src > 13) && (dest < 13))
    {
    BCSCTL1 = (calibDest & 0xf0) | 0x0d; // first set rsel to 13
    BCSCTL1 = calibDest; // then to target
    }
    else if((src < 14) && (dest < 13))
    {
    BCSCTL1 = calibDest;
    }
    else if((src < 12) && (dest > 13))
    {
    DCOCTL &= 0x1f;
    BCSCTL1 = calibDest;
    }
    else
    {
    BCSCTL1 = calibDest;
    }
    DCOCTL = calibDCO;

    while (IFG1 & OFIFG)
    {
    // Clear oscillator fault flag
    IFG1 &= ~OFIFG;
    for (i = 0x4800; i > 0; i--) asm("NOP");
    }
    }
    
    
    
    
    Ushan Karunathilaka
  • Hello, 

    Further i have noticed the the MSP got stuck at following line.

    BCSCTL1 = (calibDest & 0xf0) | 0x0d; // first set rsel to 13
    BCSCTL1 = calibDest; // then to target
    
    
    any Idea?
    
    
    Thanking You,
    Ushan
  • Hello,

    This is rare issue and cannot be easily duplicated.

    however i have added following line before above two, now it seems that system is working properly. BUT this is NOT the exact workaround mentioned in the errata sheet

    Please help me!

    DCOCTL &= 0x1f;
    BCSCTL1 = (calibDest & 0xf0) | 0x0d; // first set rsel to 13
    BCSCTL1 = calibDest; // then to target
    
    
    
    
    Thanks,
    Ushan
  •  Hi Ushan, as suggested from Jeans please read and post calibration data, are you sure 1MHz calibration carry a valid value? What is the silicon die code?

     To read calibration set a break point then read memory from 0x10f0 to 0x10ff and post here.

     Use a scope or frequency meter, set smclk to an output pin then write a routine that after clocking cpu from external  exercise all DCO frequency and see what happen.

     Backup calibration data to a file, then run calibration routine, retry code, if work restore old calibration and see if it hang. If it work with new calibration and hang with old then calibration can be corrupted.

     Regards

     Roberto

  • Hi Roberto and Jeans,

    please find the values in the flash

    i m not sure the silicone die code, this is what printed on MSP430 ,

    OCAJ8ZTG4

    MSP430F2418T

    REV H

    Thanking You,

    Ushan

  • Ushan Karunathilaka said:
    BCSCTL1 = (calibDest & 0xf0) | 0x0d; // first set rsel to 13

    This doesn't really make sense.
    Either assign a fixed value (0x8d) or use
    BCSCTL1 = (BCSCTL1 & 0xf0) | 0x0d;
    to keep the upper bits of BCSCTL1.
    But that has no impact on the problem itself.

    Ushan Karunathilaka said:
    DCOCTL &= 0x1f;

    It also makes no sense to clear the DCOx bits but keep the MODx bits. You can just assign 0 here.

    However, independently of the DCO RSEL switch issue, with RSELx=13, there might be an issue with switching RSEL at all. It may be that at the moment of switching RSEL, a fractional DCO clock cycle is executed until DCOCLK has settled to the new frequency.

    It is recommended to set DIVMx to a value >1 before changing RSEL. Especially if lowering RSEL (as this significantly increases the chance that the fractional clock cycle is a fraction of the high frequency, while on changing up, it will be a fraction of the low frequency and therefore most likely still below the maximum clock speed).

    Clearing DCOx to 0 reduces the DCO frequency and therefore increases the chance that any spike will still be below the maximum (but not ensure it). However, setting DIVM_2 will ensure that any spike will only make 25% of an MCLK cycle, so it will always be a valid MCLK cycle.

    Note that this recommendation is based on 1x family experience and errata sheets (BCL5). It's possible that this has been addressed with the 2x family clock module. However, it won't hurt :)

    P.s.: your calibration values look, well, "healthy" :)

**Attention** This is a public forum