Here is the code involved, for the functions I'm calling, they're all found in DriverLib (http://dev.ti.com/tirex/content/msp/MSP430Ware_3_60_00_10/driverlib/doc/MSP430F5xx_6xx/html/index.html) (guide at http://dev.ti.com/tirex/content/msp430ware_3_80_07_00/driverlib/doc/MSP430FR5xx_6xx/MSP430FR5xx_6xx_DriverLib_Users_Guide-2_91_11_01.pdf)
To summarize the code blow: We successfully get into powermode 3, X2 always times out, then X1 times out, setting ACLK and FLLREF to REFO works just fine, then FLLSettle locks up due to DCOFFG fault.
Due to the fact that every clock fails, I expect I've done something wrong rather than there being such a terrible hardware fault in this custom board.
X2 is 19.2 MHz, X1 is the 32 and change kHz, and while I'll eventually want to try to make MCLK run at 20 via DCO, this was just my initial "do the oscillators work" test.
So, does anybody see what I'm missing here?
I'm gonna work on making a version of this that doesn't use DriverLib in the meantime.
int main(void) { WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer uint8_t working_crystals = init_crystals(); //The code for this is below, but in my actual project it's in another file that's included up top. while(1){ test_math(); test_freq(); } return 0; }
uint8_t init_crystals(){ uint8_t working_crystals = (BIT1 | BIT2); //Bit 1 is for X1, bit 2 is for X2 uint8_t VCore = 0; uint8_t core_set_counter = 17; //At outset, PMMVCore is 0, we want to move it to 3, that happens one at a time. while ((VCore < 3) && (core_set_counter > 0)){ //While we're below our desired VCore, and we've tried less than 16 times to change it core_set_counter--; //Mark off one try if(PMM_setVCoreUp(VCore + 1)){ //Try to bump it up one, and if you succeed VCore++; //Update your VCore tracker, and thus your target core_set_counter = 17; //And reset your number of tries } } //Note, due manufacturer errata, failing to use the driverlib version of this function could potentially cause malfunctions. //Test to see if this system can feasibly run at 16, 12, 8 MHz. //TODO: Use the following information to set the clocks better. uint8_t MaxCPU = 8 + (VCore << 2); //MaxCpu speed in MHz = 8 + VCore * 4 UCS_setExternalClockSource(32768, //X1 freq, 32.768 kHz 19200000); //X2 freq, 19.2MHz //UCS_turnOnXT2(UCS_XT2_DRIVE_16MHZ_24MHZ); int16_t outer; int16_t inner; _no_operation(); //Delay loop for(outer = 24000; outer > 0; outer--){ for(inner = 10; inner > 0; inner--){ _no_operation(); } } //~~~~~~~~~~~~~~~~~~~~~~~Everything above this line works~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //This if statement always fails (the Timeout always occurs) if (UCS_turnOnXT2WithTimeout(UCS_XT2_DRIVE_16MHZ_24MHZ,0xFFFF)){ //Sets up XT2 in the correct frequency range //But if some error bits take 65536 cycles to clear, fall back to another clock. //Anyway, this case is for it working and proceeding as normal. UCS_initClockSignal(UCS_MCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1); //Main clock runs at the basic 19.2MHz for now UCS_initClockSignal(UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1); //Submain runs at 19.2 for now but we might change this later if (UCS_turnOnLFXT1WithTimeout(UCS_XT1_DRIVE_3, UCS_XCAP_0, 0xFFFF)){ //DRIVE_3 is high stability high power, DRIVE_0 is low stability low power //Cap is 0 because we have our own external caps so we don't need to use the internal ones. That said, we could tune further with the internal ones if necessary. //And again, if some error bits take a full 65536 cycles and still haven't cleared, we'll fall back to a different timer. //But this is the case where it works and we proceed as normal. UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1); //And Aux clock runs at the 32.768 kHz standard for... reasons. } else{ //This is the case where X2 works fine but X1 does not. In this case, we use REFO for ACLK UCS_initClockSignal(UCS_ACLK, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1); //And also turn off X1 explicitly. UCS_turnOffXT1(); working_crystals &= !(BIT1); } } else{ //This is the case where X2 does not work (which right now always happens) //So first step, turn off X2 UCS_turnOffXT2(); working_crystals &= !(BIT2); //Then deal with X1 //Which right now always also times out if (UCS_turnOnLFXT1WithTimeout(UCS_XT1_DRIVE_3, UCS_XCAP_0, 0xFFFF)){ //DRIVE_3 is high stability high power, DRIVE_0 is low stability low power //Cap is 0 because we have our own external caps so we don't need to use the internal ones. That said, we could tune further with the internal ones if necessary. //And again, if some error bits take a full 65536 cycles and still haven't cleared, we'll fall back to a different timer. //But this is the case where it works and we proceed as normal. UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1); //And Aux clock runs at the 32.768 kHz standard for... reasons. //And now that we have X1 setup and running through ACLK, we also run it through FLL, UCS_initClockSignal(UCS_FLLREF, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1); } else{ //This is the case where X2 fails and X1 fails. In this case, we use REFO for ACLK //Right now this always occurs, and these to clock signal inits seem to work just fine UCS_initClockSignal(UCS_ACLK, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1); //And then run it through FLL UCS_initClockSignal(UCS_FLLREF, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1); //And turn off X1 explicitly UCS_turnOffXT1(); working_crystals &= !(BIT1); } //And now that one of those two has setup ACLK and FLL, we use our FLL to set up our DCO, which we use for our MCLK and SMCLK //But this FLLSettle always hangs at the DCOFFG compare loop UCS_initFLLSettle(19200, 59); UCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1); //Technically this one is redundant, as the initFLL sets MCLK and SCLK to DCO, but still we'll write it out here. while (HWREG8(UCS_BASE + OFS_UCSCTL7_L) & DCOFFG); UCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1); //Submain runs at 19.2 MHz for now, but we might change this later. //Also note that while we're using methods to measure the clock frequencies when we need to know them, rather than just assuming, this actually gives 19.33312 MHz } return working_crystals; }