I'm troubleshooting a group of boards that contain an MSP430F5342 micro on them. It appears that on some boards (not all), when a UART interrupt occurs, it's possible that the board resets (sometimes, not always).
I've distilled the source down to just enough to show the problem. I configure the clocks (external 32768 crystal), configure the UART, enable interrupts, and enable the receive interrupt for the UART. I then drop into an infinite loop - so, nothing is really happening except the UART interrupt should be triggered when a byte is received.
The receive interrupt just checks to see if UCRXIE and UCRXIFG are set, and if so, read the byte from UCA1RXBUF and discards it.
On some boards, I power them up, then send characters (slowly, by hand using a terminal program) to the UART. The micro will occasionally reset at the same instant a byte is received. On other boards, nothing happens - the byte is received properly.
I have an MSP-FET430UIF and CCS, and I've set a breakpoint on the very first line of my interrupt handler. After sending a character, if the micro resets, the breakpoint is never even hit. If the micro doesn't reset, the breakpoint is hit, and I can continue. I then repeat the process, and eventually get a reset.
Here is my code at the moment (not very clean, though, since it was distilled out from the "real" project):
#include <MSP430F5342.h> /*lint -save -e957 -e970 */ #pragma CHECK_MISRA("none") extern "C" int _system_pre_init(void) { WDTCTL = WDTPW | WDTHOLD; return 1; } #pragma RESET_MISRA("all") /*lint -restore */ typedef unsigned char uint8_t; typedef unsigned long int uint32_t; #define OSC_STABILIZE_WAIT_TIME (170000u) #define OSC_STABILIZE_CHECK_TIME (5u) #define OSC_STABILIZE_FAIL_BLINK_TIME (10000u) #define CLOCK_CYCLES_PER_MICROSECOND (24ul) #define CLOCK_DELAY_US(x) _delay_cycles(((uint32_t) (x)) * CLOCK_CYCLES_PER_MICROSECOND) void configure_uart() { UCA1CTL1 = UCSWRST; // reset uart UCA1CTL0 = 0; // no parity /* Select SMCLK as clock source, disable Rx error and Rx break interrupts, USCI module is not dormant, next frame is normal data, keep module in reset */ UCA1CTL1 = UCSSEL__SMCLK | UCSWRST; /* Disable auto baud rate detection. */ UCA1ABCTL = 0u; // Disable irda mode UCA1IRRCTL = 0u; UCA1IRTCTL = 0u; // set 115200 baud UCA1BRW = 11u; UCA1MCTL = (0u * UCBRF0) | UCOS16; } void open_uart() { /* Reset module */ UCA1CTL1 = UCA1CTL1 | UCSWRST; // Configure pins P4DS = P4DS & 0xcf; // drive strength default P4OUT = P4OUT & 0xcf; // Output low. P4OUT = P4OUT | 0x10; // Output high for the TX pin. P4DIR = P4DIR | 0x10; // P4.4 output P4DIR = P4DIR & ~(0x20); // P4.5 input P4SEL = P4SEL | 0x30; // Both are peripheral function. /* Release module from reset */ UCA1CTL1 = UCA1CTL1 & ((uint8_t) ~(UCSWRST)); } void enable_receive() { /* Dummy read of receive register to flush any extra bytes received previously and to clear receive interrupt. */ uint8_t junkByte = UCA1RXBUF; // enable rx interrupt UCA1IE = UCA1IE | UCRXIE; } void enable_oscillator() { P5DS = P5DS & 0xcf; // Default drive strength on crystal pins. P5OUT = P5OUT & 0xcf; // Low or don't care. P5DIR = P5DIR | 0x20; // Output on P5.5. P5DIR = P5DIR & 0x70; // Input on P5.4. P5SEL = P5SEL | 0x30; // Both are peripheral function. } #pragma vector=USCI_A1_VECTOR __interrupt void UartA1Isr_Steve(void) { uint8_t interruptEnabledFlags = UCA1IE; uint8_t interruptFlags = UCA1IFG; if (((interruptEnabledFlags & UCRXIE) > 0u) && ((interruptFlags & UCRXIFG) > 0u)) { uint8_t junk_byte = UCA1RXBUF; } else { P6DIR = P6DIR | 0x02; // Set P6.1 as an output. P6SEL = P6SEL & 0xFD; // Select IO function for P6.1. /* infinite loop, blink orange LED */ for(;;) { P6OUT = P6OUT | 0x02; // Set P6.1. CLOCK_DELAY_US(100000); P6OUT = P6OUT & 0xFD; // Clear P6.1. CLOCK_DELAY_US(100000); P6OUT = P6OUT | 0x02; // Set P6.1. CLOCK_DELAY_US(100000); P6OUT = P6OUT & 0xFD; // Clear P6.1. CLOCK_DELAY_US(200000); } } } void configure_clock() { /* Turn off FLL. Locks DCO at current frequency. */ _bis_SR_register(SCG0); /* Crystal oscillator settings: Turn off XT2. Drive strength level 3 for XT1. Low frequency mode for XT1. No bypass for XT1. Highest capacitance (about 12.0 pF) for XT1. SMCLK on. XT1 on. */ UCSCTL6 = XT2OFF | XT1DRIVE_3 | XCAP_3; /* Enable XT1 oscillator pins. */ enable_oscillator(); // Wait for the oscillator input to stabilize. CLOCK_DELAY_US(OSC_STABILIZE_WAIT_TIME); /* Clear oscillator fault flag and wait. */ UCSCTL7 &= ~(XT1LFOFFG); CLOCK_DELAY_US(OSC_STABILIZE_CHECK_TIME); P6DIR = P6DIR | 0x02; // Set P6.1 as an output. P6SEL = P6SEL & 0xFD; // Select IO function for P6.1. if ((UCSCTL7 & XT1LFOFFG) > 0u) { // If the oscillator hasn't stabilized by now, something must be very wrong. // Therefore we'll blink the standby light forever to let the operator know. while (true) { P6OUT = P6OUT | 0x02; // Set P6.1. CLOCK_DELAY_US(OSC_STABILIZE_FAIL_BLINK_TIME); P6OUT = P6OUT & 0xFD; // Clear P6.1. CLOCK_DELAY_US(OSC_STABILIZE_FAIL_BLINK_TIME); } } else { // If the clock did stabilize, blink the standby LED once and continue on. P6OUT = P6OUT | 0x02; // Set P6.1. CLOCK_DELAY_US(OSC_STABILIZE_FAIL_BLINK_TIME); P6OUT = P6OUT & 0xFD; // Clear P6.1. } /* Set DCO to correct range (2.5-23.7 MHz min, 6.0-54.1 MHx max) and enable modulation. */ UCSCTL1 = DCORSEL_5; /* FLL settings: FLL loop divider (D) = 2 FLL multiplier (N) = 610 Use XT1CLK as reference. FLL reference divider (n) = 2 DCOCLK = D * (N+1) * ref / n DCOCLKDIV = (N+1) * ref / n */ UCSCTL2 = FLLD__2 | 610u; UCSCTL3 = SELREF__XT1CLK | FLLREFDIV__2; /* Clock source settings: Ext ACLK = XT1CLK / 32 ACLK = XT1CLK / 1 SMCLK = DCOCLK / 1 MCLK = DCOCLK / 1 */ UCSCTL4 = SELA__XT1CLK | SELS__DCOCLK | SELM__DCOCLK; UCSCTL5 = DIVPA__32 | DIVA__1 | DIVS__1 | DIVM__1; /* Turn on FLL */ _bic_SR_register(SCG0); /* Wait for FLL and DCO to stabilize (select the correct DCO tap and modulator settings). Settling time for the tap has a worst case of (n * 32 * 32) FLLREFCLK cycles (n is defined above), or about 31.25 ms. (n * 32 * 32) FLLREFCLK cycles = (D * (N+1) * n * 32 * 32) DCOCLK cycles */ /* Wait 626688 MCLK (DCOCLK) cycles */ _delay_cycles(208896ul); //WATCHDOG_RESET(); _delay_cycles(208896ul); //WATCHDOG_RESET(); _delay_cycles(208896ul); //WATCHDOG_RESET(); /* Enable conditional requests for SMCLK, MCLK, and ACLK. */ UCSCTL8 = SMCLKREQEN | MCLKREQEN | ACLKREQEN; /* Clear DCO and all oscillator fault flags. */ /* After FLL stabilizes, the DCO tap should not be at its maximum or minimum value, so a fault should not occur. If a fault does occur, it will be caught by the ASSERT in the user NMI interrupt. */ UCSCTL7 = 0u; /* Clear, then enable oscillator fault interrupt. */ SFRIFG1 &= ~(OFIFG); SFRIE1 |= OFIE; } int main( void ) { configure_clock(); configure_uart(); open_uart(); _enable_interrupts(); enable_receive(); for (;;) { #if 0 if (uart.AreBytesAvailable(port)) { P6DIR = P6DIR | 0x02; // Set P6.1 as an output. P6SEL = P6SEL & 0xFD; // Select IO function for P6.1. P6OUT = P6OUT | 0x02; // Set P6.1. } #endif } }