MSP430 Tutorial



MSP430 Interrupts and Low Power Mode


How do we define an Interrupt?
Interrupt is an exception from normal program flow. A program flow is interrupted when an event occur. Interrupts often neglected because its 'easier' to poll for an event than implement interrupts. So what are interrupts? They are really just a way for the hardware to signal the software that some event has occurred. Each event has an entry location in memory in what is called the interrupt vector table - a table of pointers to functions stored in memory (either flash or RAM). When an interrupt is enabled the CPU will jump to one of them automatically when the interrupt fires. These functions are called interrupt service routines (ISR), and though some may be included as part of the compiler libraries, most need to be implemented by the programmer. Interrupt service routines must be as quick and efficient as possible, so as to not stall the software which was executing.
One way of categorizing interrupts is by the effect they have on the system. The MSP430 generally categorizes interrupts as follows:

  • System Reset Interrupts - When triggered, these interrupts cause a reset of the system
  • Non Maskable Interrupts - These interrupts cannot be masked (or disabled). Typically these are fault handlers such as oscillator faults and flash access violation which indicate a critical condition
  • Maskable Interrupts - Most interrupts on the MSP430 fall into this category. GPIO, timers and peripherals all generate interrupts that can be masked by the GIE bit.

System Reset interrupts have no interrupt service routine.
The MSP430 has four possible reset sources: applying supply voltage to VCC pin, a low input to the, RST/NMI pin, a programmable watchdog timer time-out and a security key violation during write access to WDTCTL register.

All Non-Maskable Interrupts share the same NMI interrupt service routine. When configured in NMI mode, the RST/NMI pin will trigger the NMI interrupt handlers.

System Reset Functions

The MSP430 starts hardware initialization after applying VCC:

  • All I/O-pins are switched to the input direction.
  • The I/O-flags are cleared as described in the appropriate peripheral descriptions.
  • The address contained in the reset vector at word address 0FFFEh is placed into the Program Counter The CPU starts at the address contained in the power-up clear (PUC) vector.
  • The status register SR is reset.
  • All registers have to be initialized by the user's program (e.g., the Stack Pointer, the RAM, ....), except for PC and SR.
  • Registers located in the peripherals are handled as described in the appropriate section.
  • The frequency controlled system clock starts with the lowest frequency of the digital controlled oscillator. After the start of the crystal clock, the frequency is regulated to the target value. The, RST/NMI pin is configured with the reset function after applying VCC. It remains reset as long as the reset function is selected. When the pin is configured with the reset function, the MSP430 starts operation after the, RST/NMI pin is pulled down to Gnd and released as follows:
    • The address contained in the reset vector at word address 0FFFEh is placed into the Program Counter
    • The CPU starts at the address contained in the reset vector after the release of the, RST/NMI pin.
    • The status register SR is reset.
    • All registers have to be initialized by the user's program (e.g., the Stack Pointer, the RAM, ....), except for PC and SR.
    • Registers located in the peripherals are handled as described in the appropriate section.
    • The frequency controlled system clock starts with the lowest frequency of the DCO. After the start of the crystal clock the frequency is regulated to the target value.

As I have mentioned above, most interrupts generated by peripherals such as GPIO and timers fall into the maskable interrupt category in that they can be masked from the CPU by disabling the General Interrupt Enable (GIE) bit.

Functions to control global MSP430 interrupts:

__enable_interrupt(); // Enable Global Interrupts by GIE = 1
__disable_interrupt(); // Disable Global Interrupts by GIE = 0

In order for an ISR to trigger, all that's required is that the interrupt for the module be enabled, GIE is set and the condition for the interrupt is met.


MSP430 Interrupt Priority Scheme

The interrupt priority of the modules is defined by the arrangement of the modules in the connection chain: the nearer a module in the chain is towards the CPU/NMIRS, the higher is the priority.

Interrupt Priority Scheme

It is possible for multiple interrupts to occur at the same time. Which interrupt will the MSP430 handle first? The interrupts in the MSP430 and all microcontrollers have priorities. In the case of the MSP430 these are fixed and you must take care that your application does not depend on an order that is contrary to the priorities. For example, Timer_A and Timer_B have different priorities, and it might be necessary to choose one or the other when doing the hardware design or software implementation.

MSP430 Interrupt Vectors


Handling an Interrupt

MSP430 checks for the fired interrupts and selects the highest priority that is not masked.
The current state of the MSP430 need to be stored before it jumps go handle an interrupt so the processor can return successfully:

  • The Program Counter (PC) holds the address of the next instruction to be executed
  • The Status Register (SR) holds the status of CPU results, interrupts, and operation

The stack on the MSP430 is where processor places the PC (program counter) and SR (status register), push to the stack, both of which cause the Stack Pointer register to increment accordingly. When the processor is finished, it will "pop" the Status Register and the Program Counter from the stack to their respective registers and continue from the last location.

Functions to control MSP430 Low Power Modes:
__bis_SR_register_on_exit(x) // Disable Global Interrupts by GIE = 0
__bic_SR_register_on_exit(x) // Enable Global Interrupts by GIE = 1
__bic_SR_register_on_exit(LPM0_bits | GIE); // Exits LPM0 and disables GIE upon exit


#include <string.h>
#include "driverlib.h"
#include "hal.h"

void main(void)
{
	P1SEL &= (~BIT1);	// Set P1.1 SEL as GPIO
	P1DIR &= (~BIT1);	// Set P1.1 SEL as Input
	P1IES |= (BIT1);	// Falling Edge
	P1IFG &= (~BIT1);	// Clear interrupt flag for P1.1
	P1IE |= (BIT1);		// Enable interrupt for P1.1
	P1REN |= BIT1;		// Enable P1.4 internal resistance
	P1OUT |= BIT1;		// Set P1.4 as pull-Up resistance	
				
	while (1)
	{
		
		P1IE |= (BIT1);				// Re-enable interrupt for P1.1
		
		/*
		 * The following code causes that all maskable interrupts to be allowed (GIE=1) and 
		 * the chip is switched into LPM0 mode 
		 * (no further code execution untill an interrupt wakes up the chip again).
		 * The statement below: Enter LPM0 (low power mode 0) with the global
		 * interrrupt enabled - bis_SR, bit sets Special Function Register
		 * LPM0_bits to low power mode 0 + global interrupt bit set.
		 */
		__bis_SR_register(LPM0_bits + GIE); 
								 		
		// Whe CPU wakes up from the sleep it will run code entered here. So, your code goes here.
		......
		
		//Once code is completed, go back to sleep with __bis_SR_register(LPM0_bits + GIE); 
	
	}
	
}

// Port 1 ISR Interrupt (push button) ------------------------------------
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
#else
#error Compiler not supported!
#endif
{
	P1IFG &= ~BIT1;	// Clear P1.1 IFG
	P1IE &= ~ BIT1;	// Clear P1.1 IE
  
	// __bic_SR_register_on_exit: clears the bits specified in mask in the saved 
	// status register of an interrupt function 
	 	
	__bic_SR_register_on_exit(LPM0_bits + GIE);	// Exits LPM0 and disables GIE upon exit
}	

//******************************************************************************
// MSP430G2xx Demo - WDT, Low Power Mode, Interval Overflow ISR, DCO SMCLK
//
// Description: Go to LowPowerMode using software timed by the WDT ISR. The LED
// will turn off when sleeping, Port 1 interrupt will awake the mcu and turn on
// LED. The mcu will sleep at approximately 250 * 32ms based on default 
// DCO/SMCLK clock source used in this example for the WDT.
// ACLK = n/a, MCLK = SMCLK = default
//
// MSP430G2xxx
// -----------------
// /|\| XIN|-
// | | |
// --|RST XOUT|-
// | |
// | P1.0|-->LED
//
// Aldo Briano
// Texas Instruments Inc.
// July 2010
//******************************************************************************
#include <msp430g2231.h>

unsigned int wdtCounter = 0;
void main(void)
{
	WDTCTL = WDT_MDLY_32; // Set Watchdog Timer interval to ~32ms
	IE1 |= WDTIE; // Enable WDT interrupt
	P1DIR |= BIT0; // Set P1.0 to output direction
	P1OUT |= BIT0; // Turn on LED at 1.0
	P1IE |= BIT3; // enable P1.3 interrupt
	__enable_interrupt();

	for(;;)
	{

	}
}

// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
	if(wdtCounter == 249)
	{
		P1OUT = 0x00; // P1.0 turn off
		wdtCounter = 0;
		_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/interrupt enabled
	}
	else 
	{
		wdtCounter++;
	}

}
// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
	wdtCounter = 0; // reset watchdog timer counter
	P1OUT |= 0x01; // turn LED on 
	P1IFG = 0x0;
	_BIC_SR(LPM3_EXIT); // wake up from low power mode

}

MSP430 Low Power Modes

LPM0 - CPU and MCLK are shutoff. SMCLK and ACLK remain active.
LPM1 - CPU and MCLK are off, as in LPM1, but DCO and DC generator are disabled if the DCO is not used for SMCLK. ACLK is active.
LPM2 - CPU, MCLK, SMCLK and DCO are disabled, while DC generator is still enabled. ACLK is active.
LPM3 - CPU, MCLK, SMCLK, DCO and DC generator are disabled. ACLK is active.
LPM4 - CPU and all clocks disabled