interrupt void timerhandler(void){/* clear the timer flag *//* do stuff */}
Message Edited by Steve on 01-31-2006 11:02 AM
unsigned int count;void main(void) { TSCR1 = 0x80; /* Turn on timer */ TCTL3 = 0x04; /* Capture on rising edge CH5 */ TIE = 0x20; /* Enable timer overflow interrupt, CH5*/ TSCR2 = 0x80; /* Enable toi set prs 0 */ TFLG2 = 0x80; /* Clear timer interrupt flag */ asm cli /* Enable interrupts (clear I bit) */ while (1); /* Do nothing */ }interrupt void toi_isr(void){ TFLG2 = 0x80; /* Clear timer interrupt flag */ count = count + 1; /* Increment count */ }The vector table is included in vector.cvoid toi_isr();void (* const _vectab[])() = { /* 0x0B10 */ 0, /* BDLC */ 0, /* ATD */ 0, /* reserved */ 0, /* SCI0 */ 0, /* SPI */ 0, /* Pulse acc input */ 0, /* Pulse acc overf */ toi_isr, /* Timer overf */ 0, /* Timer channel 7 */ 0, /* Timer channel 6 */ 0, /* Timer channel 5 */ 0, /* Timer channel 4 */ 0, /* Timer channel 3 */ 0, /* Timer channel 2 */ 0, /* Timer channel 1 */ 0, /* Timer channel 0 */ 0, /* Real time */ 0, /* IRQ */ 0, /* XIRQ */ 0, /* SWI */ 0, /* illegal */ 0, /* cop fail */ 0, /* cop clock fail */ (void *)0xff80, /* RESET */ };
void toi_isr();
Message Edited by Alban on 02-02-2006 11:09 AM
Martin,
In principle what you are doing is correct (I haven't checked all the bit settings) and you say you are getting an interrupt so you seem to be close to getting it working. Two things arise:
1/ You have enabled the input capture interrupt (TIE) but haven't declared an interrupt service routine for it so that interrupt would cause code to run away on the MCU and would probably cause the simulator to stop.
2/ You say the simulator takes the interrupt and then stops - can you see where it stops & how it got there? That will help work out the problem.
If your vector table is set up correctly there is no need to modify the VECTOR values in the PRM file so that won't be an issue. You should use the table or the PRM file.
Steve,
Thanks for the advice I managed to set up the vectors I needed in the PRM file and the interrupts seem to work ok. Is there a way I can structure the interrupts to operate consecutively. I want to detect a rising edge on channel 5 then start the count of overflows until the next edge is detected on channel 6, I can then use this to calculate frequency.
The code I have at the moment is detecting edges and counting in no sort of order and hence the results are changing. Code below.
Martin
Code:
volatile unsigned int first, second, count;volatile long time;void main(){ for(;;){ asm cli /* Turn on timer subsystem */ TSCR1 = 0x80; TSCR2 = 0x80; TFLG2 = 0x80; /* Setup for IC5 */ TIOS = TIOS & ~0x20; /* Configure PT5 as IC */ TCTL3 = 0x08; /* Capture Rising Edge */ TFLG1 = 0x20; /* Clear IC5 Flag */ TIE = 0x20; /* Enable IC5 Interrupt */ /* Setup for IC6 */ TIOS = TIOS & ~0x40; /* Configure PT2 as IC */ TCTL3 = 0x10; /* Capture Rising Edge */ TFLG1 = 0x40; TIE = 0x40; /* Clear IC2 Flag */ time = ((65536*count)+second) - first; /* Calculate total count */ } } interrupt void tim0_ch5_isr(void){ time = 0; count = 0; first = TC5; TFLG1 = 0x20; } interrupt void tim0_overflow_isr(void){ count++; TFLG2 = 0x80; } interrupt void tim0_ch6_isr(void){ second = TC6; TFLG1 = 0x40; }
Message Edited by Alban on 02-02-2006 11:10 AM
Message Edited by Steve on 02-02-2006 10:54 AM
Steve,
Thanks for the tips I will give it a try. This is for my final year project at university so you have saved me some valuable time.
Thanks again
Marti
David,
Thanks for you input, I managed to occasionaly get the count I required when performing the calculation in the second interrupt. As you suggested I got unstable results due to the count changing whilst doing the calculation. I want to use this to monitor frequency as part of a larger program, I therefore don't want to spend lots of time doing this calculation.
I understand what you mentioned about interrupt priority so have attempted to produce code to compensate. I am using codwarrier so have no problems with the maths library. The code is below if you could give me any hints I have not yet tested this version so don't know if it works. This is my first microcontroller project and I am learning 'C' as I go so I appologise for my, probably, not very efficient code.
Confused and Fustrated
Martin
#define TRUE 1
#define FALSE 0
volatile unsigned int first, second, count, count1, count2, a, b;
volatile float time;
void main()
{
volatile unsigned int countstart, countend;
for(;{
if(b == TRUE){
asm SEI /* Disable interrupt */
countend = count2; /* Save globals as locals */
countstart = count1; /* Save globals as locals */
time = ((65536*(countend-countstart))+second) - first; /* Calculate total count */
}
/* Turn on timer subsystem */
TSCR1 = 0x80; /* Enable */
TFLG2 = 0x80; /* Enable timer overflow interrupt */
/* Setup for IC5 */
TIOS = TIOS & ~0x20; /* Configure PT5 as IC */
TCTL3 = 0x04; /* Capture Rising Edge */
TFLG1 = 0x20; /* Clear IC5 Flag */
TIE = 0x20; /* Enable IC5 Interrupt */
/* Setup for IC6 */
TIOS = TIOS & ~0x40; /* Configure PT6 as IC */
TCTL3 = 0x20; /* Capture falling Edge */
TFLG1 = 0x40; /* Clear IC6 Flag */
TIE = 0x40; /* Enable IC6 Interrupt */
asm CLI
}
}
interrupt void tim0_ch5_isr(void)
{
first = 0;
second = 0;
count = 0;
first = TC5;
TSCR2 = 0x80; /* Enable counter */
TFLG1 = 0x20;
a = TRUE; /* bit set to ensure overflow and ch6 interrupt occur after ch5 interrupt */
}
interrupt void tim0_overflow_isr(void)
{
if(a == TRUE){
TFLG2 = 0x80; /* Clear overflow flag ch5 */
if(first == 0){ /* code to conteract interrupt priority */
count1 = count - 1;
count1++;
}else{
count1 = count;
count1++;
}
}
}
interrupt void tim0_ch6_isr(void)
{
if(a == TRUE){ /* Operate only after ch5 interrupt has occurred */
TFLG1 = 0x40; /* Clear overflow flag ch6 */
second = TC6;
count2 = count; /* Store final count */
b == TRUE; /* bit set when both ch interrupts have occured */
}
}
Hi Marti,
Couple of things.
1) You don't want to turn on the timer system in you main for loop, once should be sufficient.
2) You should re-enable interrupts before you calculate frequency, just after you save the globals to locals. The idea is to have interrupts disabled for a short a time as possible. You should also save second and first locally.
3) Even though you have declared time as a float, countend, countstart, second and first are unsigned ints. You will discover that C will calculate the line
time = ((65536*(countend-countstart))+second) - first; /* Calculate total count */
as an unsigned int, and then promote the result to float. This will probably result in truncation. Read you C book for how it handles promotion of types.
4) In you code
interrupt void tim0_overflow_isr(void)
{
if(a == TRUE){
TFLG2 = 0x80; /* Clear overflow flag ch5 */
....
If 'a' is not true, TFLG2 will never be cleared, and the interrupt will never be cleared, and the interrupt routine will keep being called for ever and ever. You must clear the flag allways.
5) Your code to check for interrupt priority is probably not going to work. Firstly the example I gave when TC5 was zero, was only one case. It may be, depending on other interrupts in you system, and how long you disable interrupts for, that TC5 may be three or four. I generally check the other interrupts flags to see if we have a priority problem.
I generally do this by checking if the value of TC5 was between 0 and 0x7fff (simple branch on negative will work in assembler), and if so, then check to see the Timer Over Flag is set. If the Timer Over Flow flag is set, then timer overlow interrupt has not executed, so I increment the timer overflow count (in the TC5 interrupt) and clear the Timer OverFlow flag.
6) If you are measuring 50 Hz, you really don't need two interrupts. One interrupt set for either rising or falling edge will work fine. You need to measure the time between two rising edges, or two falling edges, not the time between rising and falling edges, if you want to measure the frequency. If you measure between a rising and falling edge, the frequency will change with the duty cycle.
Don't give up. Once you get your head around the interrupts its pretty easy to measure the frequency with and HC12.
Cheers
David
David,
Thanks for the advice, I seem to be getting closer to solving the problem. I hopefuly want to use the timer to both monitor frequency and to measure the phase angle between a voltage and current signal, from the output of a small generator. This is why I have been using the two interrupts, I thought if I could, figure this out I could easily implement frquency measurement using one interrupt. I realise I am measuring duty cycle but until I connect to the test generator I do not have a method of generating a two synchronised but out of phase signals.
I feel the problem I having is counting the timer overflow interrupts, I thought I would be able to enable the overflow interrupt during the interrupt for the first edge. and set the counter to zero and then count until the second edge occurs.
interrupt void tim0_ch5_isr(void)
{
TFLG1 = 0x20;
first = TC5;
count = 0;
TSCR2 = 0x80
a = TRUE;
}
interrupt void tim0_overflow_isr(void)
{
TFLG2 = 0x80;
count++;
}
interrupt void tim0_ch6_isr(void)
{
TFLG1 = 0x40;
if(a == TRUE){
first1 = first;
second = TC6;
count1 = count;
b = TRUE;
}
}
It does catch the correct value occasionally but often over and under counts. I have used the a and b variables so that the second time isn't taken until the first has occured and the time isn't calculated until both have occured. I haven't been able to establish any priority problems, could be due to lack of debugging knowledge, but the documentation states that the input capture events have priority over the overflow, i.e. ch5, ch6 then overflow.
I have removed the timer setup instrunctions into a seperate function called from outside the main loop and put the time calculation into a IF statement, which should only operate if both interrupts have occured. I am using the asm SEI statement to disable interrupts while save the variables, is this correct? I then enable interrupts do the calculation and clear a and b variables.
void main()
{
unsigned int start, end, Tcount, time;
for(;{
timerset();
if((a == TRUE) && (b == TRUE)){
asm SEI
start = first1;
end = second;
asm CLI
time = ((65536*Tcount)+end) - start; /* Calculate total time */
a = FALSE;
b = FALSE;
}
}
}
For a 50Hz signal with the controller running in boot mode 24MHz, I calculated the timer overflow should occur 3 times (possibly 4 depending on timing of capture) . With the the interrupt timing problems you mentioned the overflow count should be no more than one count out from this value. I, however, am getting counts ranging from 0 to 12. Any ideas?
Thanks
Marti