Setup is:
MSP430F1101A
Internal DCO at wakeup then switch to external 4.096MHz crystal.
AQ430 C compiler/IDE
MSP-FET430UIF
This processor keeps getting locked up. I've added all kinds of pin wiggles to watch whats happening, because it doesnt happen while connected to the debugger. As far as I can tell, it appears that a Timer A interrupt sometimes starts to repeatedly occur, and since originally there was no TimerA ISR, the code jumps to FFFF, executes the nonsense opode (actually the reset vector address) and goes off into la-la land.... The mystery is that as far as I can tell by breaking in the simulator and my own analysis of the code, I never enable TAIE. Note: there is now a Timer A ISR, but only for debuggin this problem. It is not normally there and as far as I can tell should not need to be there since I never enable TAIE.
To prove this, I added interrupt handler functions for every vector, and when any of them are activated (interrupt occurs), I wiggle a pin as many times as that vector. So if vector 8 occurs, I wiggle a pin 8 times so I can tell. Since it appeared Timer A interrupt was occuring, I added another debug feature that leaves the pin high if TAIE is enabled. And it is. How can this be?
The way this processor is used is:
Initial power on.
Setup hardware in a typical way, go to sleep LPM4.
Get awoken every 1000ms by a port 1 interrupt, switch oscillators, use timer A capture to measure something (without interrupt), go back to sleep.
The code is (not including cstart.asm):
// --------------
// Include Files
// --------------
#include <msp430x11X1.h>
// ---------------------
// Function Prototypes
// ---------------------
void main( void );
void init_hardware( void );
void check_cha_frequency( void );
void check_chb_frequency( void );
void isr(void);
unsigned char vect;
// ------------
// Definitions
// ------------
// To make the program easier to understand.
#define TRUE 1
#define FALSE 0
// For Time Delay Loops
#define HS_OSC_DELAY 0xFF
#define INTERRUPT_DELAY_TIME 100
// Define Window Limits
#define SMCLK_FREQ 4096000
#define SMCLK_FREQ_ERROR 40 // Allowable deviation.
#define MAX_BAD_COUNTS 100 // Used for filtering bad counts.
#define CHA_HIGH_LIMIT ( SMCLK_FREQ / 4000 ) + SMCLK_FREQ_ERROR
#define CHA_LOW_LIMIT ( SMCLK_FREQ / 4000 ) - SMCLK_FREQ_ERROR
#define CHB_HIGH_LIMIT ( SMCLK_FREQ / 4000 ) + SMCLK_FREQ_ERROR
#define CHB_LOW_LIMIT ( SMCLK_FREQ / 4150 ) - SMCLK_FREQ_ERROR
// Inputs
#define HV_ACTIVE BIT3
#define CHA_HV_DETECT BIT2
#define CHB_HV_DETECT BIT1
#define CHA_AND_CHB ( BIT1+BIT2 )
// Outputs
#define CHA_HV_GOOD BIT2
#define CHB_HV_GOOD BIT1
#define TEST_OUT BIT0
// -------------
// Define Enums
// -------------
// ----------------------
// Structure Definitions
// ----------------------
// ------------------
// Global Variables
// ------------------
// ----------------
// Local Variables
// ----------------
// Channel A Related Variables
unsigned char ucChAError;
unsigned int uiChAFrequency;
unsigned int uiPrevChAFrequency;
unsigned int uiCurrentChAFrequency;
unsigned char ucChAHVPresentFlag;
// Channel B Related Variables
unsigned char ucChBError;
unsigned int uiChBFrequency;
unsigned int uiPrevChBFrequency;
unsigned int uiCurrentChBFrequency;
unsigned char ucChBHVPresentFlag;
// Diagnostics Related Variables
unsigned int ucNumberWdResets = 0;
// Store Version Number
unsigned int uiVersionNumber = 101; // Can only be seen with a debugger.
void main( void )
{
init_hardware();
while( TRUE )
{
WDTCTL = WDT_ARST_1000; // Set Watchdog Timer interval.
// So we can tell that a watchdog reset occured.
if(( IFG1 & WDTIFG ) == WDTIFG )
{
// Set the flag.
ucNumberWdResets = 0xFF;
P1OUT &= ~BIT0;
P1OUT |= BIT0;
P1OUT &= ~BIT0;
IFG1 &= ~WDTIFG;
}
// Start monitoring the frequency for channels A and B.
check_cha_frequency(); // CHA_HV_GOOD HIGH = LOW, HV OK.
// -----------------
// ENTER SLEEP MODE
// -----------------
// If HV_ACTIVE input is low, SLEEEEEPPPP.....
if(( P1IN & HV_ACTIVE ) == 0 )
{
P2OUT |= CHA_HV_GOOD; // Set output high so we are in a known state.
P2OUT |= CHB_HV_GOOD; // Set output high so we are in a known state.
_DINT(); // Momentarily disable interrupts.
P1IE |= HV_ACTIVE; // Enable HV_ACTIVE interrupts (disabled in ISR).
P1IFG = 0; // Clear HV interrupt flag.
_EINT(); // Re-enable interrupts
LPM4; // Enter LPM4.
}
}
}
void init_hardware( void )
{
unsigned int i;
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 |= ( XTS+XT2OFF+DIVA_3 ); // ACLK = LFXT1 = HF XTAL ACKL / 8.
BCSCTL2 |= ( SELS+SELM_2 ); // Switch SMCLK, MCLK to HS Crystal.
// If there is a problem with the HS Oscillator we will hang up here.
do
{
IFG1 &= ~OFIFG; // Clear OSC Fault flag
for( i = HS_OSC_DELAY; i>0; i-- ); // Time for flag to set
}
while (( IFG1 & OFIFG ) != 0 ); // OSC Fault flag still set?
// Setup Port 1 Inputs
P1SEL |= CHA_HV_DETECT; // Setup CCR1 - Capture mode.
P1SEL |= CHB_HV_DETECT; // Setup CCR0 - Capture mode.
P1DIR |= BIT0; // Make unused I/O pins outputs.
P1OUT &= ~BIT0; // And set unused I/O pins Low.
P1IES = 0; // Interrupt on Rising Edge
P1IE |= HV_ACTIVE; // Enable HV_ACTIVE interrupts.
P1IFG = 0; // Clear HV_ACTIVE interrupt flag.
// Setup Capture Compare Rregisters
TACTL = ( TASSEL_2+MC1+TACLR ); // SMCLK - Clear TAR, Continuous Up mode.
TACCTL0 = ( CM_2+SCS+CAP ); // Falling edge, capture mode.
TACCTL1 = ( CM_2+SCS+CAP ); // Falling edge, capture mode.
// Setup Port 2 outputs
P2DIR |= 0x3F; // Set P2.0 - P2.6 to outputs.
P2OUT = 0x06; // Start CH A and CH B Good lines high.
// Initialize global variables.
ucChAError = 0;
uiChAFrequency = 0;
uiPrevChAFrequency = 0;
uiCurrentChAFrequency = 0;
ucChAHVPresentFlag = FALSE;
ucChBError = 0;
uiChBFrequency = 0;
uiPrevChBFrequency = 0;
uiCurrentChBFrequency = 0;
ucChBHVPresentFlag = FALSE;
IE1 |= WDTIE; // Enable WDT interrupt
//---------------------------
// Get ready. Get set. Go!!!
// --------------------------
_EINT(); // Enable interrupts
}
void check_cha_frequency( void )
{
unsigned int i, n;
// See if electrical stimulation is being produced on Channel A.
// This loop is so that we can get a specified number of errors in a row
// before concluding that the frequency is off.
ucChAError = 0;
for( i=0; i<MAX_BAD_COUNTS; i++ )
{
TACCTL1 &= ~CCIFG; // Clear the CCR1 interrupt flag.
n=0; // Intialize delay loop counter.
while( TRUE )
{
// This loop is so that we don't get hung up forever waiting for an
// interrupt to occur. If it has not occured after n times through the
// loop we just return.
if(( TACCTL1 & CCIFG ) == CCIFG ) // CCR1 Interruptflag set?
{
uiCurrentChAFrequency = TACCR1; // Yes, Save the TAR count.
uiChAFrequency = uiCurrentChAFrequency - uiPrevChAFrequency;
// Is the TAR count within prescribed limits?
if(( uiChAFrequency < CHA_LOW_LIMIT ) || ( uiChAFrequency > CHA_HIGH_LIMIT ))
{
ucChAError++; // Out of limits. Increment the error count.
}
uiPrevChAFrequency = TACCR1; // Read current TAR for next iteration.
break;
}
else
{
n++; // Increment delay loop counter.
if( n > INTERRUPT_DELAY_TIME )
{
// Set output high because no frequency was detected.
P2OUT |= CHA_HV_GOOD;
return; // Bail out.
}
}
}
}
// Evaluate results of frequency test for Channel A
if( ucChAError < MAX_BAD_COUNTS )
{
P2OUT &= ~CHA_HV_GOOD; // Set output LOW because frequency is within limits.
}
else
{
P2OUT |= CHA_HV_GOOD; // Set output high because frequency is out of bounds.
}
}
interrupt[ PORT1_VECTOR ] void hv_active_int( void )
{
unsigned int i;
// Wake up if HV Active goes high. We should be running off the DCO
// Clock at first.
LPM4_EXIT; // Resume normal operation.
WDTCTL = WDT_ARST_1000; // Start Watchdog Timer interval
// Switch to HS Osillator.
BCSCTL1 |= ( XTS+XT2OFF+DIVA_3 ); // ACLK = LFXT1 = HF XTAL ACKL / 8.
BCSCTL2 |= ( SELS+SELM_2 ); // Switch SMCLK, MCLK to HS Crystal.
// Wait for HS Oscillator to stablize.
do
{
IFG1 &= ~OFIFG; // Clear OSC Fault flag
for( i = HS_OSC_DELAY; i>0; i-- ); // Time for flag to set
}
while (( IFG1 & OFIFG ) != 0 ); // OSC Fault flag still set?
P1IFG = 0; // Clear interrupt flag.
}
void isr(void)
{
unsigned char count;
P1DIR |= BIT0;
for(count = 0; count < vect; count++)
{
P1OUT &= ~BIT0;
P1OUT |= BIT0;
P1OUT &= ~BIT0;
}
if(TACTL |= 0x0002)
{
P1OUT &= ~BIT0;
P1OUT |= BIT0;
}
}
/*
interrupt [0] void int0(void)
{
isr();
}
*/
interrupt [2] void int1(void)
{
vect = 1;
isr();
}
interrupt [6] void int3(void)
{
vect = 3;
isr();
}
interrupt [8] void int4(void)
{
vect = 4;
isr();
}
interrupt [10] void int5(void)
{
vect = 5;
isr();
}
interrupt [12] void int6(void)
{
vect = 6;
isr();
}
interrupt [14] void int7(void)
{
vect = 7;
isr();
}
interrupt [16] void int8(void)
{
vect = 8;
isr();
}
interrupt [18] void int9(void)
{
vect = 9;
isr();
}
interrupt [20] void int10(void)
{
vect = 10;
isr();
}
interrupt [22] void int11(void)
{
vect = 11;
isr();
}
interrupt [24] void int12(void)
{
vect = 12;
isr();
}
interrupt [26] void int13(void)
{
vect = 13;
isr();
}
interrupt [28] void int14(void)
{
vect = 14;
isr();
}