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.
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, ¶m); }
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, ¶m); }
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.
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