Other Parts Discussed in Thread: MSP430F5342
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
}
}