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.

MSP430FR5969 hardware problem at 16MHz

Other Parts Discussed in Thread: MSP430FR5969

I think I have found a hardware issue with the MSP430FR5969 launchpad/processor. If I run it in 16MHz, applying appropriate FRAM wait states and the steps to adjust clock and initializing MCLK/SMCLK, it still runs very unstable. Small changes to code can result in run/crash. Some more details here. In this code if you increase the wait by one cycle from 0xE to 0xF before changing the MCLK from 2 divider to 1, the processor will then crash. Also if you move the clock adjust line to the end of the init() function, it will crash.

#include "driverlib.h"

#define TIMER_PERIOD  2
#define DUTY_CYCLE  1

void init(void);

void main(void)
{
    //Stop WDT
    WDT_A_hold(WDT_A_BASE);


    /*
     * Disable the GPIO power-on default high-impedance mode to activate
     * previously configured port settings
     */


    init();
    __delay_cycles(0xE);
    CS_initClockSignal(CS_MCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);
    //Enter LPM0
    __bis_SR_register(LPM0_bits);

    //For debugger
    __no_operation();

}

void init(void){
	FRAMCtl_configureWaitStateControl(1);
    //Set DCO frequency to 1 MHz
    CS_setDCOFreq(CS_DCORSEL_1,CS_DCOFSEL_0);
    __delay_cycles(0xFF);
    CS_initClockSignal(CS_MCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_2);
    //Set SMCLK = DCO with frequency divider of 32 = 500kHz
    CS_initClockSignal(CS_SMCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_32);

	uint16_t tempCSCTL3 = 0;
	CSCTL0_H = CSKEY_H; // Unlock CS registers
	// Assuming SMCLK and MCLK are sourced from DCO
	// Store CSCTL3 settings to recover later
	tempCSCTL3 = CSCTL3;
	/* Keep overshoot transient within specification by setting clk sources
	to divide by 4*/
	// Clear the DIVS & DIVM masks (~0x77)and set both fields to 4 divider
	CSCTL3 = CSCTL3 & (~(0x77)) | DIVS__4 | DIVM__4;
	CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz
	/* Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer +
	(10us / (1/4MHz))*/
	__delay_cycles(0x60);
	CSCTL3 = tempCSCTL3; // Set all dividers
	CSCTL0_H = 0; // Lock CS registers

    //P1.4 as PWM output
    GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P1,
        GPIO_PIN4,
        GPIO_PRIMARY_MODULE_FUNCTION
        );
    //P2.6 as PWM output
    GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P2,
        GPIO_PIN6,
        GPIO_PRIMARY_MODULE_FUNCTION
        );
    PMM_unlockLPM5();

    //Generate PWM - Timer runs in Up mode
    Timer_B_outputPWMParam param = {0};
    param.clockSource = TIMER_B_CLOCKSOURCE_SMCLK;
    //PWM = 25kHz
    param.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_32;
    param.timerPeriod = TIMER_PERIOD;
    param.compareRegister = TIMER_B_CAPTURECOMPARE_REGISTER_1;
    param.compareOutputMode = TIMER_B_OUTPUTMODE_RESET_SET;
    param.dutyCycle = DUTY_CYCLE;
    Timer_B_outputPWM(TIMER_B0_BASE, &param);


}

  • The steps I mention are documented in the errata SLAZ473Q issues CS3 and CS12.

  • Olli,

    It seems your symptom are described within the errata you pointed out. Thanks for the add investigation for this issue.
  • Yes, it's described there but the problem is that the workaround provided does not seem to work. If you check my code you can see that the clock init is copied from your errata. Could you verify on your side it still fails and ideally provide a workaround?

    Also cranking up FRAM wait states to maximum has no effect. 

  • Olli,

    I'm not understanding your clocking situation here. First you set the DCO to 1MHz then do MCLCK/2 and SMCLK/32. Then you do the 16MHz workaround and come out as MCLCK=16MHz/2 and SMCLK=16MHz/32. Then after your Init loop, you reset all dividers to 1, which makes MCLK =SMCLK=16MHz.

    I would suggest cutting out the middle exercises and set your clocks appropriately from the beginning. This will allow you to avoid triggering the errata and potential resets.

    Also for your PWM to work properly, you need to set the GIE bit to allow interrupts the PWM API uses. You can do this when you go to LPM0.

  • It will crash if I do that. That back an forth was reached by trial and error which allowed this simple test program to run. Hence the comment in OP that moving the clock change to the init() routine will fail.  I'm actually not (intentionally at least) changing SMLK to 16MHz, it stays at 8MHz as far as I know.

    For the sake of argument, here's adjusted code which will die consistently before it gets to the 2nd port setup line. In fact it will run away from the debugger when it crashes i.e. it'll revert back to free run state by itself. 1st time the init routine is executed it'll get to the 1st port setup line and will crash, on 2nd round it will not get past the 1st initclocksignal line.

    #include "driverlib.h"
    // 1KHz 50/50
    #define TIMER_PERIOD  31
    #define DUTY_CYCLE  15
    
    void init(void);
    
    void main(void)
    {
        //Stop WDT
        WDT_A_hold(WDT_A_BASE);
    
    
        /*
         * Disable the GPIO power-on default high-impedance mode to activate
         * previously configured port settings
         */
    
    
        init();
    /*    __delay_cycles(0xE);
        CS_initClockSignal(CS_MCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);
    */
        //Enter LPM0
        __bis_SR_register(LPM0_bits);
    
        //For debugger
        __no_operation();
    
    }
    
    void init(void){
    	FRAMCtl_configureWaitStateControl(1);
        CS_initClockSignal(CS_MCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);
        __delay_cycles(0xFF);
        //Set SMCLK = DCO with frequency divider of 32 = 500kHz
        CS_initClockSignal(CS_SMCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_32);
        __delay_cycles(0xFF);
    	uint16_t tempCSCTL3 = 0;
    	CSCTL0_H = CSKEY_H; // Unlock CS registers
    	// Assuming SMCLK and MCLK are sourced from DCO
    	// Store CSCTL3 settings to recover later
    	tempCSCTL3 = CSCTL3;
    	/* Keep overshoot transient within specification by setting clk sources
    	to divide by 4*/
    	// Clear the DIVS & DIVM masks (~0x77)and set both fields to 4 divider
    	CSCTL3 = CSCTL3 & (~(0x77)) | DIVS__4 | DIVM__4;
    	CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz
    	/* Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer +
    	(10us / (1/4MHz))*/
    	__delay_cycles(0x60);
    	CSCTL3 = tempCSCTL3; // Set all dividers
    	CSCTL0_H = 0; // Lock CS registers
    
        //P1.4 as PWM output
        GPIO_setAsPeripheralModuleFunctionOutputPin(
            GPIO_PORT_P1,
            GPIO_PIN4,
            GPIO_PRIMARY_MODULE_FUNCTION
            );
        //P2.6 as PWM output
        GPIO_setAsPeripheralModuleFunctionOutputPin(
            GPIO_PORT_P2,
            GPIO_PIN6,
            GPIO_PRIMARY_MODULE_FUNCTION
            );
        PMM_unlockLPM5();
    
        //Generate PWM - Timer runs in Up mode
        Timer_B_outputPWMParam param = {0};
        param.clockSource = TIMER_B_CLOCKSOURCE_SMCLK;
        //PWM clock = 31.25kHz
        param.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_16;
        param.timerPeriod = TIMER_PERIOD;
        param.compareRegister = TIMER_B_CAPTURECOMPARE_REGISTER_1;
        param.compareOutputMode = TIMER_B_OUTPUTMODE_RESET_SET;
        param.dutyCycle = DUTY_CYCLE;
        Timer_B_outputPWM(TIMER_B0_BASE, &param);
    
    
    }
    

  • Olli,

    I'm able to reproduce your issue reliably and have narrowed down the issue to the CS_initClockSignal(). Strangely, if you step through the function its ok, but trying to run even at debug speed causes a PUC. I am unable to get the PUC to occur with register level code (no DriverLib function) however. This means to me we have a bug within this DriverLib function. My workaround for you would be to not use the CS_initClockSignal() and to set your MCLK and SMCLK initial values via register level code like so.

        CSCTL0 = CSKEY;
        CSCTL2 |= SELM__DCOCLK + SELS__DCOCLK;
        CSCTL3 |= DIVM__1 + DIVS__32;

    I'll report this issue to the DriverLib team in the mean time. Thanks for your detailed investigation.

  • Hei,

    Ok, that did it. Looks like there are a fair few snags with the 16MHz clock. I wonder what's the library doing to make the processor reset since it's just a matter of setting those couple of registers.

    I presume there's no problem using an external 16MHz crystal.

    Regards, Olli
  • Hello,

    Well this is embarassing. I was working on my code today and checking various CPU registers. Until I realized FRAM wait state is 0. "Hey, but I set it to 1 there" I go.. Nope. I only thought I do:

    FRAMCtl_configureWaitStateControl(1);

    That's not the correct format. Library function expects "FRAMCTL_ACCESS_TIME_CYCLES_1" macro instead which in turn is a macro for NWAITS_1 which equals 0x10. Ouch. Basically I've been overclocking my MSP430FR5969.. I'm sure the workaround in datasheet errata would work fine as long as you set the FRAM waitstate correctly 1st. 

    Regards, Olli

**Attention** This is a public forum