 News

Contact Us

 Reviews

 Guides & Tutorials

 More



LPC2148 Interrupt Tutorial

Search ...


Like Page

Be the first of your friends to like this

Email Address


Introduction to Interrupts
This is a Basic Tutorial on Interrupts for LPC214x MCUs and how to program them for those who are
new to interrupts. To start with , †rst lets see : what interrupts, IRQs and ISRs are. As per wiki : “An
interrupt is a signal sent to the CPU which indicates that a system event has a occurred which
needs immediate attention“. An ‘Interrupt ReQuest‘ i.e an ‘IRQ‘ can be thought of as a special request
to the CPU to execute a function(small piece of code) when an interrupt occurs. This function or ‘small
piece of code’ is technically called an ‘Interrupt Service Routine‘ or ‘ISR‘. So when an IRQ arrives to the
CPU , it stops executing the code current code and start executing the ISR. After the ISR execution has
†nished the CPU gets back to where it had stopped.
Interrupts in LPC214x are handled by Vectored Interrupt Controller(VIC) and are classi†ed into 3 types
based on the priority levels.(Though Interrupts can classi†ed in many di†erent ways as well)
1. Fast Interrupt Request i.e FIQ : which has highest priority
2. Vectored Interrupt Request i.e Vectored IRQ : which has ‘middle’ or priority between FIQ and
Non-Vectored IRQ.
3. Non-Vectored IRQ : which has the lowest priority.

But I’d like to Classify them as 2 types :
1. Fast IRQs or FIQs
2. Normal IRQs or IRQs which can be further classi†ed as : Vectored IRQ and Non-Vectored IRQ.
Okay .. so what does Vectored mean ?
In computing the term ‘Vectored‘ means that the CPU is aware of the address of the ISR when the
interrupt occurs and Non-Vectored means that CPU doesnt know the address of the ISR nor the source
of the IRQ when the interrupt occurs and it needs to be supplied by the ISR address. For the Vectored
Stu† , the System internally maintains a table called IVT or Interrupt Vector Table which contains the
information about Interrupts sources and their corresponding ISR address.
Well , in my opinion you can literally use the meaning of the term ‘Vector‘ which comes from
mathematics & physics which indicates a quantity having direction and magnitude. In our case
we can consider the ‘magnitude‘ as the ID of the interrupt source i.e the processor knows what
is ‘source’ of the interrupt request (IRQ). Similarly for direction you can consider that Vectored
IRQ ‘Points to'(which is like direction) its own unique ISR. On the other hand each Non-Vectored
ISRs doesn’t point to a unique ISR and instead the CPU needs to be supplied with the address of
the ‘default’ or say.. a ‘common’ ISR that needs to be executed when the interrupt occurs. In
LPC214x this is facilitated by a register called ‘VICDefVectAddr‘. The user must assign the
address of the default ISR to this register for handling Non-Vectored IRQs.
If you are still confused than here it is in a nutshell : The di†erence between Vectored IRQ(VIRQ) and
Non-Vectored IRQ(NVIRQ) is that VIRQ has dedicated IRQ service routine for each interrupt source

Posted By Umang Gajera Posted date: August 09, 2013 in: Embedded, LPC2148 Tutorials


. This is similar to VICIntEnable expect writing a 1 here will disabled the corresponding Interrupt. 15 having lowest priority. Most of the registers that are used to con†gure interrupts or read status have each bit corresponding to a particular interrupt source and this mapping is same for all of these registers. [Refer Table 1] 6) VICSoftInt : This register is used to generate interrupts using software i.e. What I mean is that bit 0 in these registers corresponds to Watch dog timer interrupt . 0 having highest priority and slot no. Writing a 1 will release(or clear) the forcing of the corresponding interrupt. Writing 0’s has no e†ect. it forces the interrupt to occur. Writing 0’s has no e†ect. This has an e†ect on VICIntEnable since writing at bit given location will clear the corresponding bit in the VICIntEnable Register. Note than by default all interrupts are selected as IRQ.. then assign TIMER0 interrupt a lower number slot than UART0 Like . can take 32 interrupt request inputs but only 16 requests can be assigned to Vectored IRQ interrupts in its LCP214x Implementation. [Refer Table 1] 5) VICFIQStatus (R) : Same as VICIRQStatus except it applies for FIQ. Writing a 1 at a given bit location will make the corresponding interrupt Enabled.g if you make Bit 4 as 0 then the corresponding interrupt source i. LPC2148 Interrupt Related Registers Now we will have a look at some of the important Registers that are used to implement interrupts in lpc214x: 1) VICIntSelect (R/W) : This register is used to select an interrupt as IRQ or as FIQ.. We are given a set of 16 vectored IRQ slots to which we can assign any of the 22 requests that are available in LPC2148. Note : VIC .. Writing 0 here has no e†ect. Reading a 0 is unless here lol. For e. as per its design . and so on. Now if you want to give TIMER0 a higher priority than UART0 . bit 4 corresponds to TIMER0 interrupt . Example: For example if you working with 2 interrupt sources say. ARMC1 = ARMCore1 . If this register is read then 1’s will indicated enabled interrupts and 0’s as disabled interrupts. The slot numbering goes from 0 to 15 with slot no. The number of the slot doesn’t matter as long TIMER0 slot is lower than UART0 slot.e manually generating interrupts using code i. UART0 and TIMER0. TIMR1 = TIMER1 . hook up TIMER0 to slot 0 and UART0 to slot 1 or TIMER0 to slot 4 and UART to slot 9 or whatever slots you like.Non-Vectored IRQ(NVIRQ) is that VIRQ has dedicated IRQ service routine for each interrupt source which while NVIRQ has the same IRQ service routine for all Non-Vectored Interrupts.e the program itself. If a bit location is read as 1 then it means that the corresponding interrupt is enabled and active. [Refer Table 1] 3) VICIntEnClr (R/W) : This register is used to disable interrupts. Here is the complete table which says which bit corresponds to which interrupt source as given in Datasheet: Table 1: Bit# 22 IRQ 20 USB AD1 BOD Bit# 10 IRQ 21 9 8 19 18 17 16 15 14 13 12 I2C1 AD0 EINT3 EINT2 EINT1 EINT0 RTC PLL 7 6 5 4 3 2 1 11 SPI1/SSP 0 SPI0 I2C0 PWM UART1 UART0 TIMR1 TIMR0 ARMC1 ARMC0 N/A WDT Note : TIMR0 = TIMER0 . VIC has plenty of registers. bit 6 corresponds to UART0 interrupt .. [Refer Table 1] 2) VICIntEnable (R/W) : This is used to enable interrupts. [Refer Table 1] .e TIMER0 will be IRQ else if you make Bit 4 as 1 it will be FIQ instead. [Refer Table 1] 7) VICSoftIntClear : This register is used to clear the interrupt request that was triggered(forced) using VICSoftInt. Writing a 0 at a given bit location(as given in Table 1) will make the corresponding interrupt as IRQ and writing a 1 will make it FIQ. You will get a clear picture when I cover some examples in examples section. ARMC2 = ARMCore2. Note that here IRQ applies for both Vectored and Non-Vectored IRQs. [Refer Table 1] 4) VICIRQStatus (R) : This register is used for reading the current status of the enabled IRQ interrupts. If you write a 1 at any bit location then the correspoding interrupt is triggered i.

{Bit 5} . In this tutorial the only place we’ll use this register . These are used to assign a particular interrupt source to a particular slot.. UART0 and PWM IRQs are setup as Non-Vectored IRQs. Note : The Interrupt Source Number is also called as VIC Channel Mask. {and rest of the bits}. Enabling the slot here means that it can generate the address of the ‘dedicated Interrupt handling function (ISR)’ and disabling it will generate the address of the ‘common/default Interrupt handling function (ISR)’ which is for Non-Vectored ISR. TIMER0 and SPI0 are con†gured as Vectored IRQs with TIMER0 having Highest Priority. The interrupt source numbers are given in the table below : Table 2: Interrupt Source Source number Interrupt Source Source number In Decimal In Decimal WDT 0 PLL 12 N/A 1 RTC 13 ARMCore0 2 EINT0 14 ARMCore1 3 EINT1 15 TIMER0 4 EINT2 16 TIMER1 5 EINT3 17 UART0 6 ADC0 18 UART1 7 I2C1 19 PWM 8 BOD 20 I2C0 9 ADC1 21 SPI0 10 USB 22 SPI1 11 The 5th bit is used to enable the vectored IRQ slot by writing a 1. (^_^) The rest of the bits are reserved.e dummy write to this register indicates to the VIC that current Interrupt has †nished execution. [Refer Table 1] 8) VICVectCntl0 to VICVectCntl15 (16 registers in all) : These are the Vector Control registers.e VICVectAddr3 in this example. For this tutorial I’ll be calling it as “Interrupt Source Number” to keep things simple and clear..e the one which is currently active. As mentioned before slot 0 i. Now . 10) VICVectAddr : This must not be confused with the above set of 16 VICVecAddrX registers. is at the end of the ISR to signal end of ISR execution. This will get more clear as we do some examples. The whole setup is as given below: . Attention! : Note that if the vectored IRQ slot is disabled it will not disable the interrupt but will change the corresponding interrupt to Non-Vectored IRQ. 11) VICDefVectAddr : This register stores the address of the “default/common” ISR that must be called when a NonVectored IRQ occurs.e VICVectCntl0 has highest priority and VICVectCntl15 has the lowest. i. lets consider another Example with a Simple Diagram : Here we have 4 IRQs Con†gured. Each of this registers can be divided into 3 parts : {Bit0 to bit4} . that we’ve seen all the Registers . 9) VICVectAddr0 to VICVectAddr15 (16 registers in all) : For Vectored IRQs these register store the address of the function that must be called when an interrupt occurs. In simple words if the slot is enabled it points to ‘speci†c and dedicated interrupt handling function’ and if its disable it will point to the ‘default function’.Writing a 1 will release(or clear) the forcing of the corresponding interrupt. The †rst 5 bits i. When an interrupt is Triggered this register holds the address of the associated ISR i.e Bit 0 to Bit 4 contain the number of the interrupt request which is assigned to this slot. Note – If you assign slot 3 for TIMER0 IRQ then care must be taken that you assign the address of the interrupt function to corresponding address register . Writing a value i.

Now lets see how to actually setup the interrupt. If you use this keyword with the function de†nition then compiler will automatically treat it as an ISR. Here is an example on how to de†ne an ISR in Keil : __irq void myISR (void)  {   .  }  //====OR Equivalently====  void myISR (void) __irq  {   . Next assign the address of the related ISR to VICVectAddrX.. 2.  }  Note that both are perfectly valid ways of de†ning the ISR. // Enable TIMER0 IRQ  VICVectCntl0 = (1<<5) | 4 . 3. I prefer to use __irq before the function name. First we need to enable the TIMER0 IRQ itself! Hence . First lets see how to de†ne the ISR so that compiler handles it carefully. For this we’ll use a special keyword called “__irq” which is a function quali†er. Consider we wanna assign TIMER0 IRQ and ISR to slot X...  VICVectAddrX = (unsigned) myISR. from Table 1 we get the bit number to Enable TIMER0 Interrupt which is Bit number 4..  //Vectored‐IRQ for TIMER0 has been configured  . Hence we must make bit 4 in VICIntEnable to ‘1’...Con†guring and Programming Interrupts (ISR) To explain How to con†gure Interrupts and de†ne ISRs I’ll use Timers as an example . from Table 2 we get the interrupt source number for TIMER0 which is decimal 4 and OR it with (1<<5) [i. Here is a simple Template to do it: Replace X by the slot number you want . I Assume you are comfortable with using timers with LPC214x .. Here is a simple procedure like thing to do that : A Simple 3 Step Process to Setup / Enable a Vectored IRQ 1.   VICVectCntlX = (1<<5) | Y . 0 as follows : VICIntEnable |= (1<<4) .e 5th bit=1 which enables the slot] and assign it to VICVectCntlX. since this Timers are easy to play. Hence . For this we need to explicitly tell the compiler that the function is not a normal function but an ISR. Next . then Replace Y by the Interrupt Source Number as given in Table 2 and †nally replace myISR with your own ISR’s function Name .. //5th bit must 1 to enable the slot (see the register definition above) VICVectAddr0 = (unsigned) myISR.).  Using above steps we can Assign TIMER0 Interrupt to Slot number say. and you’r Done! VICIntEnable |= (1<<Y) .

e. Case #2) And when we have multiple ‘internal’ source of interrupt in TIMER0 i.  //Vectored‐IRQ for TIMER0 has been configured  Attention! : Note the Correspondence between the Bit number in Table 1 and the Source Number in Table 2. // write back to clear the interrupt flag    VICVectAddr = 0x0. : Case #2 actually provides a general method of using Timers as PWM generators! You can use any one of the match registers as PWM Cycle generator and then use other 3 match registers to generate 3 PWM signals! Since LPC214x already has PWM generator blocks on chip I don’t see any use of Timers being used as PWM generators.e the particular bit) in the device’s interrupt register and then by writing a zero to VICVectAddr register which signi†es that interrupt has ISR has †nished execution successfully. do something here        T0IR = regval.. when the ISR is called †rst we need to identify the actual source of the interrupt using the Interrupt Register and then proceed accordingly. This is done by clearing the the †ag(i. // The ISR has finished!  }  Even in case #2 things are simple except we need to identify the ‘actual’ source of interrupt. Having done that now its time to write the code for the ISR. More Attention plz! : First thing to note here is that each device(or block) in lpc214x has only 1 IRQ associated with it. Soo . Like the TIMER0 block(or device) has 4 match + 4 capture registers and any one or more of them can be con†gured to trigger an interrupt. So . // Acknowledge that ISR has finished execution  }  Okay… Did you Notice a Second use of Case #2 ? If not then here it is . MR1 & MR2 which raise an IRQ.. Since we know only one source is triggering an interrupt we don’t need to identify it – though its a good practice to explicitly identify it.. The Bit Number now becomes the Source Number in decimal. say a match event for MR0 . // read the current value in T0's Interrupt Register        if( T0IR & MR0I_FLAG )    {      //do something for MR0 match    }    else if ( T0IR & MR1I_FLAG )    {      //do something for MR1 match    }    else if ( T0IR & MR2I_FLAG )    {      //do something for MR2 match    }        T0IR = regVal. Now its time to go one step further and pop-out Case #3 and Case #4 out of the blue :P. But for MCUs which don’t have PWM generator blocks this is very useful.    regVal = T0IR. #define MR0I_FLAG (1<<0)  #define MR1I_FLAG (1<<1)  #define MR2I_FLAG (1<<2)  __irq void myISR(void)  {    long int regVal. MR0 match event has occured .VICVectAddr0 = (unsigned) myISR..e an MR0 match event which raises an IRQ. Also just before . // write back to clear the interrupt flag    VICVectAddr = 0x0. when the main ISR code is †nished we also need to acknowledge or signal that the ISR has †nished executing for the current IRQ which triggered it. The ISR then will be something like : __irq void myISR(void)  {    long int regVal. But inside each device there may be di†erent sources which can raise an interrupt (or an IRQ). // read the current value in T0's Interrupt Register        //. Programming the Interrupt Service Routine (ISR) : Okay to keep things keep simple lets consider two simple cases for coding an ISR (I’ll use TIMER0 for generating IRQs since its easy to understand and play with) : Case #1) First when we have only one ‘internal’ source of interrupt in TIMER0 i. Hence such devices have a dedicated interrupt register which contains a †ag bit for each of these source(For Timer block its ‘T0IR‘). Both of .    regVal = T0IR. In case #1 things are pretty straight forward.

TIMER0 and UART0. Case #3) When we have Multiple Vectored IRQs from di†erent Devices. In Case Interrupts are Not working in Keil UV4 / Crossworks : For those of you who are using Keil UV Version4(or higher) you’ll need to edit Target Option settings and those who are using Crossworks for ARM etc . But here both of them are NonVectored and hence will be serviced by a common Non-Vectored ISR. Hence Priority comes into picture here. Hence. Consider we have TIMER0 and UART0 generating interrupts with TIMER0 having higher priority. [Refer Table 1] Also Note that its recommended that you only have one FIQ in your system. Now its time to go one step further and pop-out Case #3 and Case #4 out of the blue :P. I’ve posted a solution for this @ http://www. FIQs have low latency than VIRQs and usually used in System Critical Interrupt Handling. The ISRs will be something as given below : __irq void myTimer0_ISR(void)  {    //Same as in case #1  }  __irq void myUart0_ISR(void)  {    long int regVal. I’ll be Posting a Tutorial on UART with LPC214x shortly – Its in the pipeline :). To keep things simple lets assume that we have only 1 internal source inside both TIMER0 and UART0 which generates an interrupt. Case #4) Lastly when we have Multiple Non-Vectored IRQs from di†erent Devices. To promote or covert a Vectored IRQ to FIQ just make the bit for corresponding IRQ in VICIntSelect register to 1 and it will be become an FIQ. // The ISR has finished!  } Attention Plz!: Note than UART0’s Interrupt Register is a lot di†erent than TIMER0’s. U0RegVal. For Case #3 . // write back to clear the interrupt flag for T0    }        if( ! (U0RegVal & 0x1) )     {      //do something for UART0 Interrupt      //No need to write back to U0IIR since reading it clears it    }         VICVectAddr = 0x0. Please go through that post to make Interrupts work. This is quite similar to Case #2.    regVal = U0IIR. But Wait! What about FIQ ? Well .    T0RegVal = T0IR. The default ISR in this case will be something like : __irq void myDefault_ISR(void)  {    long int T0RegVal . // The ISR has finished!  }  For Case #4 too we have TIMER0 and UART0 generating interrupts. you need to manually enable global interrupt.ocfreaks. you can think FIQ as a promoted version of a Vectored†x. Don’t worry if your not acquianted with with UARTs .e device which triggered the interrupt and proceed accordingly. There is more to it which I’ll explain in detail in Upcoming Dedicated Tutorial on Uarts and Interrupt Programming related to it. The †rst Bit in U0IIR indicates whether any interrupt is pending or not and its Active LOW! The next 3 bits give the Identi†cation for any of the 4 Interrupts if enabled.Soo . // read the current value in U0's Interrupt Register          // which also clears it!        //Something inside UART0 has raised an IRQ        VICVectAddr = 0x0. Both of them deal with IRQs from di†erent blocks viz. Example Source for all Cases: Example 1 – for Case #1: For 1st example I’ll cover an interrupt driven ‘blinky’ using timers which I’ve also use in the LPC214x .. // read the current value in U0's(Uart 0) Interrupt Identification Register       if( T0IR )    {      //do something for TIMER0 Interrupt            T0IR = T0RegVal. So in this case we’ll need to write 2 di†erent Vectored ISRs – one for TIMER0 and one for UART0. // read the current value in T0's Interrupt Register    U0RegVal = U0IIR. here we will need to check the actual source i.

 //Infinite Idle Loop    }  //return 0. //Toggle all pins in Port 0      }  T0IR = regVal. MR0 is used for PIN0 i.e for second and thrid LED respectively.70a] Example 2 – for Case #2: This is an extended version of blinky which uses 3 Match Registers i.e 3 Interrupts sources within TIMER0 2011‐13. //Reset Timer  __irq void T0ISR(void)  {    long int regVal.  */  #include <lpc214x. PIN1 and PIN2 of PORT0 of LPC2148. MR0 has been con†gured to Trigger an Interrupt when 500ms have elapsed after TC is .ocfreaks. //Enable timer    while(1). Here is a snippet of the code for Case #1: /*  (C) Umang Gajera | Power_user_EX ‐ www.com_LPC214x_TimerIRQ_Tutorial.e bit5 = 1) ‐> to enable Vectored IRQ slot          //0x4 (bit[4:0]) ‐> this the source number ‐ here its timer0 which has VIC channel mask # as 4         //You can get the VIC Channel number from Lpc214x manual R2 ‐ pg 58 / sec 5.*/         //‐‐‐‐‐‐‐‐‐‐Configure Timer0‐‐‐‐‐‐‐‐‐‐‐‐‐    T0CTCR = 0x0.5   VICIntEnable = 0x10.                              T0PR = PRESCALE‐1. //Initialize Timer0    IO0DIR = 0xFFFFFFFF.        T0TCR = 0x01. //Read current IR value          IO0PIN = ~IO0PIN.Timer Tutorial which can be found here : http://www. //(Value in Decimal!) Zero Indexed Count ‐ hence subtracting 1       T0MCR = MR0I | MR0R. Each Match register Interrupt is used to Turn on and o† an LED which is connected to a particular GPIO Pin. //0x20 (i. //normally this wont execute ever  :P  void initTimer0(void)  {    /*Assuming that PLL0 has been setup with CCLK = 60Mhz and PCLK also = 60Mhz.h>  #define MR0I (1<<0) //Interrupt When TC matches MR0  #define MR0R (1<<1) //Reset TC when TC matches MR0  #define DELAY_MS 500 //0.e †rst LED .ocfreaks. //Initialize CPU and Peripheral Clocks @ 60Mhz    initTimer0().  void initTimer0(void). //This is to signal end of interrupt execution  void initClocks(void)  {    // This function is used to config PPL0 and setup both    // CPU and Peripheral clock @ 60Mhz    // You can find its definition in the attached files or case #2 source    }  Download Project Source for Case #1 @ You can get the Complete Source and KeilUV4 Project †les from the given link itself. //Set bit0 & bit1 to High which is to : Interrupt & Reset TC on MR0     //‐‐‐‐‐‐‐‐‐‐Setup Timer0 Interrupt‐‐‐‐‐‐‐‐‐‐‐‐‐    VICVectAddr4 = (unsigned )T0ISR. similarly MR2 and MR3 for PIN1 and PIN2 i. //Pointer Interrupt Function (ISR)                }  VICVectCntl4 = 0x20 | 4.    regVal = T0IR.  More Embedded tutorials @ www.  void initClocks(void).5 Second(s) Delay  #define PRESCALE 60000 //60000 PCLK clock cycles to increment TC by 1   void initClocks(void). Here we have 3 LEDs connected to PIN0 .  License :  Soruce for Interrupt Tutorial Case #1. //Configure all pins on Port 0 as Output    IO0PIN = 0x0. //(Value in Decimal!) ‐ Increment T0TC at every 60000 clock cycles                      //Count begins from zero hence subtracting 1                       //60000 clock cycles @60Mhz = 1 mS        T0MR0 = DELAY_MS‐1.  int main(void)  {    initClocks(). //Write back to IR to clear Interrupt Flag  VICVectAddr = 0x0. //Enable timer0 int    T0TCR = 0x02.  __irq void T0ISR(void).zip [Successfully tested on Keil UV4.ocfreaks.

 //60000 clock cycles @60Mhz = 1 mS    T0MR0 = MR0_DELAY_MS‐1. // 1.    regVal = T0IR.*/         //‐‐‐‐‐‐‐‐‐‐Configure Timer0‐‐‐‐‐‐‐‐‐‐‐‐‐            T0CTCR = 0x0. P0. MR1 has been con†gured to Trigger an Interrupt when 1000ms have elapsed after TC is reset.h>  #define PLOCK 0x00000400  #define MR0I (1<<0) //Interrupt When TC matches MR0  #define MR1I (1<<3) //Interrupt When TC matches MR1  #define MR2I (1<<6) //Interrupt When TC matches MR2  #define MR2R (1<<7) //Reset TC when TC matches MR2   #define MR0I_FLAG (1<<0) //Interrupt Flag for MR0  #define MR1I_FLAG (1<<1) //Interrupt Flag for MR1  #define MR2I_FLAG (1<<2) //Interrupt Flag for MR2  #define MR0_DELAY_MS 500 //0.  void initClocks(void). // 0.5sec (Value in Decimal!) Zero Indexed Count ‐ hence subtracting 1   T0MR1 = MR1_DELAY_MS‐1.ocfreaks.  void connectPLL0(void).  License : GPL.  void initTimer0(void).e 1500ms here is what happens : 1) MR0 Toggles PIN0 of PORT0 i. //Reset Timer  __irq void myTimer0_ISR(void)  {    long int regVal. //Enable timer    while(1).e P0. //Configure all pins on Port 0 as Output    IO0PIN = 0x0. //Enable timer0 int    T0TCR = 0x02.  int main(void)  {    initClocks().      T0PR = PRESCALE‐1.  void setupPLL0(void). MR0 has been con†gured to Trigger an Interrupt when 500ms have elapsed after TC is reset. //Set the Match control register     //‐‐‐‐‐‐‐‐‐‐Setup Timer0 Interrupt‐‐‐‐‐‐‐‐‐‐‐‐‐    //I've just randomly picked‐up slot 4    VICVectAddr4 = (unsigned)myTimer0_ISR.e P0.0     }  else if ( T0IR & MR1I_FLAG )  .  More Embedded tutorials @ www. // 1sec        T0MR2 = MR2_DELAY_MS‐1. Given a period of  LPC2148 Interrupt Example.        T0TCR = 0x01. MR2 has been con†gured to Trigger an Interrupt when 1500ms have elapsed at it Resets the TC so the cycle starts 2011‐13. //Initialize CPU and Peripheral Clocks @ 60Mhz    initTimer0().5 seconds i.e P0.0 at 500ms 2) MR1 Toggles PIN1 of PORT0 i.5secs    T0MCR = MR0I | MR1I | MR2I | MR2R. //normally this wont execute ever  :P  void initTimer0(void)  {    /*Assuming that PLL0 has been setup with CCLK = 60Mhz and PCLK also = 60Mhz. //Initialize Timer0    IO0DIR = 0xFFFFFFFF.ocfreaks.respectively.         }  VICIntEnable = 0x10. //Infinite Idle Loop    }  //return 0.  __irq void myTimer0_ISR(void). //Pointer Interrupt Function (ISR)    VICVectCntl4 = 0x20 | 4.5 Second(s) Delay  #define MR1_DELAY_MS 1000 //1 Second Delay  #define MR2_DELAY_MS 1500 //1.1 at 1000ms 3) MR2 Toggles PIN2 of PORT0 i.5 Second(s) Delay  #define PRESCALE 60000 //60000 PCLK clock cycles to increment TC by 1   void delayMS(unsigned int milliseconds)..2 at 1500ms and also Resets the TC *) This cycle of Toggling each of the LEDs one by one keeps on repeating… /*  (C) Umang Gajera | Power_user_EX ‐ www. // Toggle GPIO0 PIN0 . // read the current value in T0's Interrupt Register        if( T0IR & MR0I_FLAG )  {    //do something for MR0 match            IO0PIN ^= (1<<0).  void feedSeq(void).  */  #include <lpc214x.

but since the Simulation seems to work perfect I assume both will work as expected if you try them out.  }  Note: TC is reset only when MR2 matches TC. Hence when TIMER0 interrupt occurs and at the same time UART0 interrupt occurs .    feedSeq().// Toggle GPIO0 PIN1 .   VICIntEnable |= (1<<4). //Pointer Interrupt Function (ISR)  VICVectCntl0 = 0x20 | 4. //sequence for locking PLL to desired freq. // Acknowledge that ISR has finished execution   void initClocks(void)  {    setupPLL0().1    }  else if ( T0IR & MR2I_FLAG )                    }  {    //do something for MR0 match        IO0PIN ^= (1<<2). I haven’t tried them out on my Development Board yet . †rst TIMER0 ISR will be serviced and then UART0.e 60Mhz    }  //PLL0 Now configured!  //‐‐‐‐‐‐‐‐‐PLL Related Functions :‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐  //Using PLL settings as shown in : http://www. If any doesn’t work please let me know. 4th bit=1  //‐‐‐‐‐‐‐‐‐‐Setup UART0 Interrupt‐‐‐‐‐‐‐‐‐‐‐‐‐  //Any Slot with Lower Priority than TIMER0's slot will suffice  . Though this can be used using simple delay but the example presented here does this by purely using Interrupts! Download Project Source for Case #2 @ OCFreaks. Code for Con†guring Both TIMER0 and UART0 Interrupts is as given Below: //‐‐‐‐‐‐‐‐‐‐Setup TIMER0 Interrupt‐‐‐‐‐‐‐‐‐‐‐‐‐  //Using Slot 0 for TIMER0  VICVectAddr0 = (unsigned)myTimer0_ISR.2    }    T0IR = regVal.2 and UART0 ISR will Toggle P0.com_LPC214x_Interrupt_Tutorial_Case2.   }  void feedSeq(void)  {    PLL0FEED = 0xAA.e when you press a key in the terminal.    feedSeq().        PLL0CON =‐pll‐tutorial‐for‐cpu‐and‐peripheral‐clock/ void setupPLL0(void)  {    //Note : Assuming 12Mhz Xtal is connected to LPC2148..     PLL0CFG = 0x24. P0.  }  void connectPLL0(void)  {    while( !( PLL0STAT & PLOCK )). // PCLK is same as CCLK i. // write back to clear the interrupt flag  VICVectAddr = 0x0. //sequence for connecting the PLL as system clock         //SysClock is now ticking @ 60Mhz!             VPBDIV = [Successfully tested on Keil UV4.ocfreaks.    PLL0FEED = 0x55.                else if ( T0IR & MR1I_FLAG )  {    //do something for MR1 match        IO0PIN ^= (1<<1). TIMER0 ISR will Toggle P0. Here TIMER0 ISR will have a higher priority over UART0 ISR. //Enable timer0 int .    connectPLL0().70a] Example 3 – for Case #3: Note that Case #3 and Case #4 are just some Fictitious-Typo cases which I’ve randomly made to Explain Multiple Vectored and Non-Vectored IRQs.// Toggle GPIO0 PIN2 .3. You can †nd the complete code in †les attached below. Here I’m only giving the code to Enable both the Interrupts and its ISR.. Consider we have TIMER0 generating interrupt every 500ms and UART0 generates an interrupt when some data arrives i.    PLL0CON = 0x03. P0.

 P0.3    }        VICVectAddr = 0x0. 4th bit=1  //‐‐‐‐‐‐‐‐‐‐Enable (Non‐Vectored) UART0 Interrupt‐‐‐‐‐‐‐‐‐‐‐‐‐  VICIntEnable |= (1<<6). P0. // Acknowledge that ISR has finished execution  __irq void myUart0_ISR(void)  {    long int regVal..2      T0IR = T0RegVal. // write back to clear the interrupt flag    }        if( !(U0RegVal & 0x1) )    {      //Recieve Data Available Interrupt has occured      U0RegVal = U0RBR. // Reading U0IIR also clears it!        //Recieve Data Available Interrupt has occured    regVal = U0RBR. // dummy read    IO0PIN ^= (1<<3).    T0RegVal = T0IR.. // write back to clear the interrupt flag  VICVectAddr = 0x0..70a] FINAL Attention Plz! : When you play with Multiple Interrupts . //Enable timer0 int . P0.. // Acknowledge that ISR has finished execution  } Download Project Source for Case #4 @ OCFreaks. Please take care of all the situations that may arise else in most cases Weird System Behavior might creep in giving you Debugging Nightmares.2      }  T0IR = regVal. // dummy read      IO0PIN ^= (1<<3) [Successfully tested on Keil UV4. U0RegVal. // Acknowledge that ISR has finished execution  Download Project Source for Case #3 @ OCFreaks.    regVal = T0IR. //Enable Uart0 interrupt .zip [Successfully tested on Keil UV4. In the Non-Vectored Case the con†guration code will be as shown below: VICDefVectAddr = (unsigned)myDefault_ISR. // Toggle 3rd Pin in GPIO0 . P0.. //Pointer Interrupt Function (ISR)  VICVectCntl1 = 0x20 | 6. I’d say keep on experimenting with Interrupts . // Toggle 3rd Pin in GPIO0 . // Toggle 4th Pin in GPIO0 . // Toggle 4th Pin in GPIO0 . // read the current value in T0's Interrupt Register    U0RegVal = U0IIR. the more you’ll do the more you’ll learn and the more clear it will become!  . //Pointer to Default ISR  //‐‐‐‐‐‐‐‐‐‐Enable (Non‐Vectored) TIMER0 Interrupt‐‐‐‐‐‐‐‐‐‐‐‐‐  VICIntEnable |= (1<<4).//Any Slot with Lower Priority than TIMER0's slot will suffice  VICVectAddr1 = (unsigned)myUart0_ISR.        if( T0IR )    {      IO0PIN ^= (1<<2). 6th bit=1 And the code for the Non-Vectored ISR is as given Below: __irq void myDefault_ISR(void)  {    long int T0RegVal . 6th bit=1 Both the ISRs will be as follows : __irq void myTimer0_ISR(void)  {    long int regVal. //Enable Uart0 interrupt . // read the current value in T0's Interrupt Register        IO0PIN ^= (1<<2).3    } VICVectAddr = 0x0.70a] Example 4 – for Case #4: Even Here I’ll give the main code and as with above you can †nd the complete code in the attached †les.com_LPC214x_Interrupt_Tutorial_Case4.    VICIntEnable |= (1<<6).    regVal = U0IIR.

http://infocenter. the probability of occurrence of Spurious Interrupts is high when Watch Dog Timer or UART is used.pdf Share this:  Share Tags:  Like embedded lpc2148  Tweet programming  Share  Share tutorial  Share  Previous Roccat Kone Pure Color edition Mouse review  ABOUT THE AUTHOR Umang Gajera   Next  Pulse Width Modulation (PWM) Tutorial   .doc. Here are some useful documents which will surely help you out with interrupt Spurious Interrupts: I like to call “Spurious Interrupt” as “Zombie Interrupts” – in my opinion that suits it more.0 2. I’d like to share one of the best guide I’ve found for Understanding the general Architecture of VIC in detail . which is the following document from ARM itself : 1. Covering the “handling of Spurious Interrupts” is too not in the scope of this article. The datasheet(manual) has special note on Spurious interrupts on page 61..ddi0181e/DDI0181. Normally speaking its an interrupt that was not required in the †rst place. When a nested interrupt has †nished execution we must get back to the correct context. Page 61 of LPC214x Usermanul Rev 2. For more on Nested Interrupts you can refer the following documents : 1.Advanced Interrupt Handling: Nested Interrupts: Interrupts too can be nested. For more information on handling of spurious interrupts I would like my readers to go through the following documents : 1. Covering Nested interrupt is not within the scope of this tutorial. But we need to take some special care when dealing with nested interrupts since in this case the “context” and the “stack” come into picture. These can happen in virtually any interrupt driven system and must be identi†ed and handled properly else unde†ned system behaviour may occur. NXP Application Note : AN10381 2.). http://www. Such interrupts happen when an IRQ is generated out of no where (Magic! lol. Here the IRQ comes into exsistence even when none of the conditions for triggering that IRQ have been met. Similarly too much of nesting and the stack will get overloaded. There are many reasons as to why it can happen : 1) Inherent bug/†aw in system design 2) Electrical Interference / Noise 3) Software Bug 4) Signal glitches on Level Sensitive interrupts 5) Faulty components 6) Miscon†gured Hardware 7) etc… (You’ll get plently of info just by googling the term) In respect to LPC214x(also LPC2000) MCUs . NXP Application Note : AN10414 Understanding VIC in Detail: Finally

...12 Comments OCFreaks!   Recommend ⤤ Share Join the discussion… onkar karle • 22 days ago sir actually we have to take interrupt from rtc to adjust brightness  level of leds according to real time...can u help us with programming  tutorial • 6 months ago Very good and helpful  God bless you :) △   ▽ • Reply • Share › Dinu • 2 years ago Simple explanations. △   ▽ • Reply • Share › vikas vikeee • 3 months ago it is 1<<4 i think for 5th bit to enable △   ▽ • Reply • Share › Mahdi... Its too gud for the beginners like me. △   ▽ • Reply • Share › 1   Login Sort by Newest  .

de Register Contact Us . Community  Server Monitoring with Livewatch. these things are really helpful to me. △   ▽ • Reply • Share › OMKAR • 3 years ago thanks for post. I've fixed the link.. △   ▽ • Reply • Share › ✉ Subscribe d Add Disqus to your site Add Disqus Add ὑ Privacy (c) OCFreaks! 2014. :) △   ▽ • Reply • Share › Amar More • 3 years ago Thanks a lot for a detailed and understandable tutorial. △   ▽ • Reply • Share › lalit • 3 years ago very good △   ▽ • Reply • Share › B ananda • 3 years ago A very good tutorial indeed! Thanks a lot for uploading this tutorial.. △   ▽ • Reply • Share › nilesh pathak • 3 years ago thanks for post .△   ▽ • Reply • Share › Pratik • 2 years ago Hi... Thanks for nice tutorial. △   ▽ • Reply • Share › rijan shrestha • 3 years ago this is the post i am searching for a while. A very good tutorial indeed! please post RTC (REAL TIME CLOCK) USING INTERRUPT. thanks once again. △   ▽ • Reply • Share › Umang Gajera > Pratik • 2 years ago You're most Welcome Pratik.. Thank to you In Spurious Interrupts section link to NXP Application Note : AN10414 is invalid....