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.

MSP430 switching source of ACLK from REFO to external XIN

Other Parts Discussed in Thread: MSP430F5659

Hi Folks,

I'm using the MSP430F5659, and I want to dynamically switch the source of ACLK from REFO to an external clock signal applied to the XIN pin. When I do this, the UCS module appears to assert the XT1LFOFFG flag, and the changeover doesn't actually occur until later: much later.

To get to the bottom line first, is there any way to prevent XT1LFOFFG being set? Whether it's by careful attention to the sequence of operations, some (possibly undocumented) trick, or some other means, I don't really mind.

Now for a bit more background. We need to do some timing functions which are guaranteed to be synchronized to an external clock over a long period of time. The bomb-proof way to do that is to use the external clock to generate ACLK via XIN, and clock the timers from ACLK. The external clock has an open drain output, so it requires a pull-up, but we can not leave it enabled all the time because our system must be able to go into a deep sleep mode with the minimum possible power consumption. We can solve that by using REFO to source all clocks while we go into deep sleep, then switch the ACLK source to the external clock at XIN when the system wakes up. Everything else can continue to run from REFO, but that's not accurate enough for ACLK for what we need.

When we make the switch, the UCS asserts XT1LFOFFG, and it stays that way for 8192 cycles at XIN, as documented in the User Guide. Nothing I've tried seems to change that, and during that time ACLK continues to be derived from REFO. The kicker is that our precision external clock is 16384Hz; this is within spec for external input at XIN (10kHz to 50kHz), but nowhere near REFO at 32+kHz, so for half a second all our "precision" timing functions are off by a factor of two - a disaster. By monitoring ACLK/N at the external pin I can confirm that the frequency change is coincident with XT1LFOFFG being cleared. Once the 8192 cycle time expires everything works beautifully, but by then it's too late.

Can we avoid this 8192 cycle penalty period? The external 16384kHz input at XIN is absolutely rock solid; 50% duty cycle, nice sharp rail-to-rail square wave, and the frequency is spot on immediately with no settling delay. (The source oscillator is actually running all the time, all we really do is enable the pull-up resistor which is needed). I would be 100% comfortable with zero delay when we switch to XIN from REFO - but I can't seem to avoid those 8192 cycles.

[ As a curious aside, we sometimes see a changeover delay of about 820ms instead of 500ms. My guess is that would be 8192 cycles of the nominal 10kHz VLO clock; is that possible? Is VLO used by the fault detector as some kind of fail-safe clock in some situations, instead of XIN itself? When? This is interesting, but academic: whether 500ms or 820ms, it's WAY too long. ]

Here's our code which sets up the clock system, with everything initially running from REFO:

/*--------------------------------------------------------------------------*/
void clock_init_REFO( void )
{

// set default/initial settings: XT2 off, XT1 off (to be enabled later)
// XT2=12MHz is used only for the USB module.
// XT2DRIVE 1 8MHz < XT2 < 16MHz
// XT2BYPASS 0 XT2 sourced internally
// XT2OFF 1 XT2 is off if not used for ACLK,MCLK,SMCLK or FLL.
// XT1DRIVE 0 Lowest current consumption for XT1 LF mode.
// XTS 0 Low-frequency mode. XCAP bits in use.
// XT1BYPASS 1 XT1 sourced externally from pin.
// XCAP 0 2pF (from datasheet), irrelevant if bypassed.
// SMCLKOFF 1 SMCLK off for now.
// XT1OFF 1 XT1 is off if not used for ACLK,MCLK,SMCLK or FLL.
UCSCTL6 = XT2DRIVE|XT2OFF|XT1DRIVE|XT1OFF|XT1BYPASS|SMCLKOFF;

// set up frequency range
// DCORSEL_5 6.00-23.70 MHz (target is 14.7456MHz).
UCSCTL1 = DCORSEL_5; // set frequency range, modulation disabled

// Set up multipliers for MCLK/SMCLK.
// FLLD 0 DCOCLKDIV = DCOCLK divide by 1.
// FLLN 449 (14745600/32768 = 450).
UCSCTL2 = FLLD__1|(MCLK_REFO_DIVISOR - 1);

// Select REFOCLK (enabled automatically) as reference for the FLL.
// SELREF 2 Select REFOCLK.
// FLLREFDIV 0 DCOCLK/1.
UCSCTL3 = FLLREFDIV__1|SELREF__REFOCLK;

// Set up multipliers.
// DIVPA 5 /32, ACLK/N = 2048/32 = 64Hz.
// DIVA 4 /16, ACLK = 32768/16 = 2048Hz.
// DIVS 0 /1, SMCLK = MCLK/1.
// DIVM 0 /1, MCLK = FLL/1.
UCSCTL5 = DIVM__1|DIVS__1|DIVA__16|DIVPA__32;

// Select REFO as source for ACLK.
// SELA 2 REFO sources ACLK.
// SELS 4 DCOCLKDIV sources SMCLK
// SELM 3 DCOCLK sources MCLK.
UCSCTL4 = SELS__DCOCLKDIV|SELM__DCOCLK|SELA__REFOCLK;

// Ensure XT1,XIN not used: disable XT1 bypass and ensure SMCLK is on.
UCSCTL6 |= XT1OFF;
UCSCTL6 &= ~(SMCLKOFF|XT1BYPASS);

// Set DCO to mid tap, clear modulation counter
UCSCTL0 = DCO4;

// Wait in 32x32-cycle chunks until DCO has stabilized.
do
{
UCSCTL7 &= ~(DCOFFG);
SFRIFG1 &= ~OFIFG;
__delay_cycles(32*32);

} while (UCSCTL7 & DCOFFG);

// One last time, ensure OSC-fault interrupt flag is clear.
SFRIFG1 &= ~OFIFG;

} // clock_init_REFO()
/*--------------------------------------------------------------------------*/

Then, when we're ready to source ACLK from XIN:

/*--------------------------------------------------------------------------*/
void clock_switch_REFO_to_XIN_source( void )
{

// Enable external XT1 input and SMCLK.
ENABLE_16KHZ_PULLUP;
UCSCTL6 |= XT1BYPASS; // allow signal to get through.
UCSCTL6 &= ~(SMCLKOFF); // ensure SMCLK on.

// Reset divisors to maintain ACLK=2048Hz from 16384Hz source.
UCSCTL5 = DIVM__1|DIVS__1|DIVA__8|DIVPA__32;

// Ensure fault flag clear before selecting XIN as source of ACLK.
if (UCSCTL7 & XT1LFOFFG)
{
UCSCTL7 &= ~XT1LFOFFG;
SFRIFG1 &= ~OFIFG;
}
UCSCTL4 = SELS__DCOCLKDIV|SELM__DCOCLK|SELA__XT1CLK;

// so we can see what's going on...
DEBUG_EXPOSE_ACLK_N();

} // clock_switch_REFO_to_XIN_source()
/*--------------------------------------------------------------------------*/

Any help at all would be much appreciated.

Thanks - Graham Jones

  • Is it possible for you to source the Timer(s) directly from your external clock?
  • Interesting thought - funny how you can get stuck in a rut. Unfortunately all the TXnCLK input pins are already used for other functions, so it would require changing the PCB layout. Worse, this is an in-Production design, so firmware updates would have to cope with existing PCB versions as well as revised ones: possible, but messy if we have to move several pin functions around.

    Good idea for a new design, but in our current situation not really practical: we'd obviously like to avoid a hardware revision, but if we did have to re-spin the board there are other changes we could make which would be less painful. Thanks anyway.
  • I don’t know if this helps you but Timer B can be Mapped to any Port 2 pins.

    The clock frequency isn’t that high, if you have any IO pin left (preferable P1-P4) you can (parallel) connect this to XIN and use this to synchronize the timers during XIN setup.
  • Alas, all Port-2 pins are in use for other functions.

    I'm not sure I understand your second suggestion; would you be able to expand or rephrase it please?

    However, it did get me thinking. I'll have to check this, but I think that the REALLY critical timer is TA1. Presently we clock it directly from ACLK for modest delays (up to 2^16 * 1/2048 = 32 seconds), but if we want something longer we have ACLK/N (P1.0) connected to TA1CLK (P3.0) in tandem with the input divider, which can stretch delays by a factor of up to (32*8). If we added a shorting link between XIN and TA1CLK, being very careful to always keep P1.0 as either an input (either GPIO or TA0CLK), we could still get a 2048Hz clock for TA1: 16384/8. To generate delays longer than 32 seconds we'd have to handle the timer overflow in firmware, but at least the hardware change would be relatively easy, and not require a PCB revision or track cuts. Hmm - I'll think about that some more.

    By the way, I'm assuming you're making these suggestions because you don't know of a way to stop XT1LFOFFG from being set for 8192 cycles? Could you see anything dubious about our setup code?

    Thanks again for the ideas.
  • I’m nearly sure it’s not possible to stop the XT1LFOFFG and his counting, it’s a failsafe feature and normally not a problem. I wrote software how takes this into account but was never focused to go surround this, and I can’t remember there was a way to.

    The idea to connect your clock to a Port pin is to generate interrupts and count the amount and compare and correct this with a Timer counter clocked by REFO.
    But to clock the Timer directly is a better way and for both you have to make a jumper wire.
  • XT1LFOFFG: I'm not surprised, what you say makes perfect sense. It was a faint hope, but worth a shot.

    Thanks for clarifying your suggestion, I see what you mean now. In principle it could be done, but I'd be really nervous about having an interrupt clattering away at 16+kHz; this can be a busy system, and we have trouble coping with serial input interrupts at 11520 characters/second.

    So I agree: direct clocking seems better, and we're considering the implications of that as a solution, but I suspect that's what we'll do. I'll leave this post open a bit longer in case anybody comes up with a silver bullet.
  • Initial tests suggest that routing XIN to TA1CLK and using it to run TA1 directly will work, so that's what we'll do.

    Thanks again Leo for your thought-provoking suggestions; most helpful.

  • Good to hear I could help to solve your problem. My pleasure!

**Attention** This is a public forum