I had written about hardware interrupts earlier. Now I’ll write about interrupts in general. How to write program to enable interrupts and handle those. Basically there are two types of interrupts.
- Hardware Interrupts
- Software Interrupts
As the name suggests hardware interrupts are given on the pins of the controller. An example of this can be found in by blog post.
Software interrupts on the other hand are made by using software. And these are vectored interrupts i.e. the program counter is loaded with the contents of vector address of the interrupt that occurred. In fact all interrupts are vectored. All peripherals can generate an interrupt specific to their operation.
I’ll be taking the example of TimerA interrupt . But lets see a little theory about how to handle interrupts.
First I’ll tell you what is maskable and non-maskable interrupt. Maskable interrupts can be disabled using software and non-maskable interrupt cannot be disabled. RST is a non-maskable interrupt. Now masking is done to avoid accidental triggering of the interrupt which can distort the program flow.
All the maskable interrupts have to be enabled. This is done by setting the GIE(General Interrupt Enable) bit of status register. So if you include the msp430.h file you can use the GIE macro defined in the header file and OR(bitwise) it with status register(SR), to enable the interrupts by setting that bit.
Now finally let’s see what happens when an interrupt occurs.
So when an interrupt occurs the PC and SR contents are pushed onto the stack after the current instruction is executed. This is known as context saving. Depending on priority the interrupt with highest priority is processed first. Thus the PC is loaded with the contents of the vector address and context switching takes place.
The image above shows how to return from an Interrupt Sub Routine (ISR). An ISR is nothing but the code you write for handling the interrupt. The address of this ISR is stored at the vector address of the interrupt you want to handle.
One has to use “RETI” instruction to return to the main program. What RETI does is it pops the PC and SR contents back from the stack. Thus original state of program is restored.
Interrupt Vector Addresses
Now these are device specific. So one has to refer datasheet of the required microcontroller for this. Since I’ll be using msp430g2553 for this I’ll post the vector address table for the device.
That is that.
Low Power Modes(LPM) of Operating modes of msp430
Now-a-days its all about reducing the power consumption. And Texas Instruments msp430 is a low power microcontroller. That means that there must be low power modes. Those are nothing but LPM. These are selected by setting or resetting the bits of SR. These modes are well explained in the user guide. I’ll post the page concerning these modes.
All the SCG1,SCG0,OSCOFF,CPUOFF are bits of the status register(SR). You can use the bits defined in the header file for setting these bits. I’ll explain more about this after the program.
Now when you enter a LPM. You can come out of it when there is an interrupt. Now we know that PC and SR are pushed onto the stack. So if you want to come out of the LPM on exit from ISR you need to change the SR contents pushed onto the stack. The process is given in the user guide.
The bic instruction is used to clear the corresponding bits of SR that are used for controlling LPM.
In LPM basically we shut the oscillators which consume the maximum power. Thus depending on your need you can shut down the ACLK,SMCLK,MCLK and DCO.
;Name : Manpreet Singh Minhas
;Date : 22 Nov 2013
;Website : https://learningmsp430.wordpress.com/
;Software : IAR Embedded Workbench
Aim : To blink an LED by using TimerA interrupt and use msp430 in LPM.
#include “msp430g2553.h” ; Include the header file
ORG 0FFFEH ; Power On Reset Vector address
DW MAIN ; Here MAIN is nothing but a macro for 0C000H
; memory location. You might as well write
; 0C000h. We try to make the code as reader
; friendly as possible, that is why MAIN macro.
ORG 0C000H ; Starting address of FLASH MEMORY in
; msp430g2553 where the program will be burnt.
MAIN: MOV.W #WDTPW|WDTHOLD,&WDTCTL ; Stop watchdog timer
MOV.W #03FFH,SP ; Initialize stack pointer to top of
MOV.B #BIT2,&P1DIR ; RAM. You’ll have to use device’s
MOV.W #08000H,&TA0CCR0 ; datasheet for finding this address.
MOV.W #TASSEL_1|ID_0|MC_1|TAIE,&TA0CTL ; Initialize timer
UP: MOV.W #LPM3|GIE,SR ; Enable interrupts and enter LPM3
TMR_ISR: XOR.B #BIT2,&P1OUT ; Toggle LED
BIC.W #TAIFG,&TA0CTL ; Clear the interrupt flag bit
The above code will make led connected P1.2 to blink after 1 sec delay. You can change the BIT2 to BIT0 or BIT6 if you don’t want to use an external LED. I’ve used TimerA in up mode. And I’m using ACLK for this part. I’ve connected a 32kHz crystal there. So you need to connect it there by soldering. Then it’s given in the user manual that when the count goes from TA0CCR0 value to 0, the TAIFG flag is set. I’ve enabled the interrupts in SR by setting the GIE bit, also you need to enable it in the peripheral’s control register. I’ve enabled the TimerA interrupt by setting TAIE bit of TA0CTL. Now it’s vital to clear the interrupt flag of the interrupt that you are handling. In this case the TAIFG flag in TA0CTL register. So that we can acknowledge the next interrupt. Its easy to forget this so just beware. And regarding the LPM3 macro that I’ve used it just sets the corresponding bits of SR. The definition is:
#define LPM3 (SCG1+SCG0+CPUOFF)
So either you can write LPM3 or the corresponding SR bits. And instead of using mov instruction you can use bis instruction as well.
p>If any doubts feel free to ask. Thank you for reading this. Hope this was useful and informative.