Hi Folks,
I am trying to work on Timer Interrupts. I want to start an LED when a TIMER match occurs. I have called an Interrupt on match and the LED should glow when the match occurs. I am not able to perceive the output. I am not exactly getting where its going wrong. Can you please help me out on this. Below is the code, please review
#include<lpc21xx.h>
#define MR0I_FLAG 0X01 void led(void)__irq { long int regval; regval = T0IR;
if(T0IR & MR0I_FLAG) { T0MR0 = 0XFF; T0TC = 0X00; T0TCR = 0X00000001;
IO0CLR = 0X00000002; IO0SET = 0X00000008; }
T0IR = regval; VICVectAddr0 = 0X00000000; }
int main() { IO0DIR = 0X0000000A; T0TCR = 0X00000000; T0MCR = 0X00000003; //Reset and generate an interrupt on Match T0PC = 0X00000000; T0PR = 0X00000000;
VICIntEnable = 0X00000010; VICVectCntl0 = 0X00000024; VICVectAddr0 = (unsigned)led;
IO0SET = 0X00000002; }
1) You didn't seem to notice the posting instructions for how to post source code.
2) You didn't thought about mentioning which processor you are using - you leave it to people to look at the #include you are using.
3) There are a large number of threads on this forum about how to use LPC21xx timers with interrupts - I don't think you have spent much time looking.
4) You like to enable your interrupts _before_ you set an interrupt handler - any reason why you think that is a good idea?
5) You are using a very "interesting" prescaler value - exactly what is your plan?
6) You want an interrupt on "Match". Which match? What matching value have you specified?
7) You use a temporary variable "regval" to read out the value of T0IR in your interrupt handler - but then you immediately make use of T0IR again to check if you got a match. Shouldn't the interrupt flags you clear correspond with the interrupt flags you have processed?
8) You write a main() that just sets up a number of registers and then directly exits - what do you expect the processor to do after you leave main()?
9) Most compilers would even warn if you have a function returning type "int" and you leave the function without a return <val> statement - so are you making use of the warning functionality of the compiler?
10) You have one #define named "MR0I_FLAG". But what does that name actually say? That you have an interrupt? But when reading out the T0IR register you already know you have a timer 0 interrupt - shouldn't the #define at least mention either the meaning of the interrupt, or the timer condition that caused that specific interrupt? Named constants are only meaningful if their name actually tells the reader something meaningful - shouldn't the message be that you got a MR0 interrupt? Because it was match register 0 you enabled match interrupts for.
11) You peppered the code with lots of magic values - how would a reader know what this line actually means?
VICIntEnable = 0X00000010;
The term "magic value" is really quite appropriate - the above line looks mostly like a magic incantation. Without access to the processor manual, it's hard to know that the line enables interrupts for timer 0 - and at the same time disables interrupts for all other interrupt sources!
Would you be able to tell your teacher, line-by-line, what the individual lines in your code does - and exactly why you need them and why you have placed them in that specific order?
#include<lpc21xx.h> #define MR0I_FLAG 0X01 void led(void)__irq { long int regval; regval = T0IR; if(T0IR & MR0I_FLAG) { T0MR0 = 0XFF; T0TC = 0X00; T0TCR = 0X00000001; IO0CLR = 0X00000002; IO0SET = 0X00000008; } T0IR = regval; VICVectAddr0 = 0X00000000; } int main() { IO0DIR = 0X0000000A; T0TCR = 0X00000000; T0MCR = 0X00000003; //Reset and generate an interrupt on Match T0PC = 0X00000000; T0PR = 0X00000000; VICIntEnable = 0X00000010; VICVectCntl0 = 0X00000024; VICVectAddr0 = (unsigned)led; IO0SET = 0X00000002; }
So in short - are you sure you have really done enough homework to give a reason to start this thread? Your teacher really expects _you_ to do a bit of work too...
Hi Per,
Thanks for your valuable feedback. I'll take your comments positively as I am a beginner in Embedded C programming and also in ARM, so comments like these are always welcome!
In reply to your mentioned points,
1.I saw the posting instructions about source code. 2.I am using NXP's - LPC2129
4.I incorporated this change. 5.I wanted to tick the Timer Counter on every PR+1 clock, hence I used T0PR = 0X00000000 6.Yes, I want an Interrupt when match occurs. Hence I have mentioned this "T0MCR = 0X00000003; //Reset and generate an interrupt on Match" in the code. I have specified the Match value in the IRQ as "T0MR0 = 0XFF" 7.Got your point.
10.#define MR0I_Flag 0X01 //I am AND'ing the value which I specified in the Match Control register with T0IR register and now comparing it with 0X01
Why the compiler is not entering into the IRQ?
I have updated the code as shown below. I debugged the code and noticed, that the VICVectAddr0 is updated with an address where its handler (void Timer0_IRQ(void)__irq) is located. Still the compiler is not jumping into the IRQ.
Need help!!
#include <LPC21xx.H> void Timer0_IRQ(void)__irq; int main() { IO0DIR = 0X0000000A; T0TCR = 0X00000000; //Disable Timer T0MCR = 0X00000003; //Reset and generate an interrupt on Match T0PC = 0X00000000; T0PR = 0X00000000; //T0TC should increment on PR+1 clk T0MR0 = 0XFF; //Value in Match Register T0TC = 0X00; //Reset Value in Timer Counter T0TCR = 0X00000001; // Enable Timer VICVectAddr0 = (unsigned)Timer0_IRQ; VICVectCntl0 = 0X00000024; //Assigning Timer0 Interrupt to an IRQ Slot VICIntEnable = 0X00000010; //Enabling the vector IO0SET = 0X00000002; } void Timer0_IRQ(void)__irq { IO0CLR = 0X00000002; IO0SET = 0X00000008; T0IR = 0X01; //Clear Timer Match0 interrupt flag VICVectAddr = 0X00000000; // End of Interrupt execution }
Your program is still running out of main() instantly. So - do you expect there to be a cozy command line or GUI to pick up the processor after your program decides to quickly end? This was point 8 in my previous post.
And you have configured the timer at an extremely high interrupt frequency - it isn't meaningful to try to configure for a frequency higher than what the processor is fast enough to be able to service. Why don't you tell us what timer frequency you plan for - and why you think you need to run timer interrupts at such a wild frequency. Remember that all CPU time spent in an interrupt handler is CPU time lost from the main loop (assuming that your program actually had a main loop...) I covered short delay times in a different thread. Think about how many clock cycles it may take to handle one timer interrupt. Think about how many clock cycles there will be between two interrupts. That gives you an idea how much time you leave for the CPU to do other stuff.
"//Enabling the vector" Enabling what vector? Why not write that it's specifically the timer 0 interrupt you are enabling?
And you shouldn't enable the timer until _after_ you have registered the interrupt handler. Normal code is the clear the counter value and enable the timer as the last two steps - when everything else has already been prepared and ready. If you enable it early, and have a very short timer period, then it could have time to perform the match before you had the time to actually enable the interrupt in the VIC.
Are you aware that there is no need to write a 32-bit hexadecimal number using 8 digits.
0x00000000 is the same value as 0x00 or 0. The first form is just taking longer time for you to write.
True, but it is certainly a habit I'm guilty of exhibiting (though guilty may not really be the right word).
The reason I do it is simple: it emphasizes the size of those numerous SFRs etc when glancing back at the code.
I am using VPBCLK = CPU Clock (12Mhz) and expecting a 1 Sec delay. Means an ISR should be called after this delay.Can you please tell, how to configure the interrupt frequency?
So - what frequency do you get? The difference between expected and actual frequency is normally a good hint at what is incorrectly configured - debugging is all about picking up the available clues and evaluate them.
If you have 12 MHz, then you somehow have to divide that down to 1 Hz for your expected interrupt frequency. I haven't seen you try any values that would be even close to such attempt - on the first code post you ignored the match control register despite requesting an interrupt on match. In the second post, you made a bit of a random assignment for the match control register - and arbitrary values tends to give arbitrary results.
Wouldn't it be an idea to fix the things that have already been mentioned?
Like making some reasonable attempt at setting a value for the match control register?
Or making sure the program doesn't exit main() before the processor have time to produce the first interrupt?
The processor will not ignore details, even if you do.