Запускаем внешний кварц, выдерживаем паузу на устаканивание и проверяем флаг. Если флаг сброшен, то все нормально - MCLK и SMCLK тактируются от кварца. В противном случае, делаем еще несколько попыток и переключаемся на тактирование от внутреннего DCO.
Частота сохраняется в глобальной переменной unsigned long xtal_freq; (модификация только в этом модуле)
Состояние в глобальном флаге g.bOscFault;
Полезно в главном цикле программы периодически проверять этот флаг и в случае возникновения сбоя обрабатывать (переинициализация периферии/сигнализация/журналирование)
/** * @file xtal.c * @brief XTAL Module * * @author Rustem Kalimullin * @par E-mail: * hellos@mail.ru * @par Copyright: * (c) Kurt, 2006 */ #include "common.h" #ifndef KR_EXT_XTAL_FREQ #define KR_EXT_XTAL_FREQ 4608000L #endif #ifndef KR_DCO_XTAL_FREQ #define KR_DCO_XTAL_FREQ 713200L #endif //--------------------------------------------------------- // Initialize HI-Speed XTAL int setup_XTAL2( void ) { IE1 &= ~OFIE; // disable OSC_Fault interrupt BCSCTL1 &= ~XT2OFF; // start XT2CLK unsigned int k = 0x10; // # try do { IFG1 &= ~OFIFG; // Clear OSCFault flag for(unsigned int i = 0xFFF; i; --i) __no_operation(); // Time for flag to set if( !(IFG1 & OFIFG) ) break; // OSCFault is clear? } while( --k ); if( k == 0 ) { g.bOscFault = 1; BCSCTL1 |= XT2OFF; // stop XT2CLK BCSCTL2 = SELM_0; // MCLK = SMCLK = DCOCLK xtal_freq = KR_DCO_XTAL_FREQ; return 0; } g.bOscFault = 0; BCSCTL2 = SELM_2+SELS; // MCLK Source Select 2: XT2CLK/LFXTCLK, SMCLK = XT2CLR xtal_freq = KR_EXT_XTAL_FREQ; IE1 |= OFIE; // enable OSC_Fault interrupt return 1; } //--------------------------------------------------------- // Oscill fault interrupt handler. Try to restore synchronization #pragma vector=NMI_VECTOR __interrupt void NMI_handler(void) { if ( IFG1 & OFIFG ) { IE1 &= ~OFIE; // disable OSC_Fault interrupt IFG1 &= ~OFIFG; // Clear OSCFault flag for(unsigned int i = 0xFF; i; --i) __no_operation(); if( (IFG1 & OFIFG) ) { BCSCTL1 |= XT2OFF; // stop XT2CLK BCSCTL2 = SELM_0; // MCLK = SMCLK = DCOCLK g.bOscFault = 1; } IFG1 &= ~OFIFG; IE1 |= OFIE; // enable OSC_Fault interrupt } else if( IFG1 & NMIIFG ) { IFG1 &= ~NMIIFG; // Reclear NMI flag in case bounce } else if( IFG1 & WDTIFG ) { IFG1 &= ~WDTIFG; } }