View previous topic :: View next topic |
Author |
Message |
wynnet
Joined: 02 Dec 2003 Posts: 15
|
service the wrong interrupt |
Posted: Wed Apr 21, 2004 11:42 am |
|
|
I have a timer0 interrupt as a clock.
the program works ok
I also would like to generate a long pulse (2 seconds) on port A bit3 at different interval of times.
so I use timer3 for this task.
I have:
setup_timer_3(T3_INTERNAL,T3_DIV_BY_8);
enable_interrupts (GLOBAL);
When I want to make the long pulse:
output_low (PIN_A3);
set_timer3 (0x1111); // any 16 bit number
enable_interrupts(int_timer3);
when the interrupt timer3 overflow
#int_timer3
void timer3_isr()
{
output_high(PIN_A3);
disable_interrupts (int_TIMER3);
}
My problem is the pulse goes low as expected
However, it returns to high in about 60 microseconds. very short
I change the value in set_timer3 from 0x0000, 0x0001, 0xffff
there is no change in the pulse width/time.
The only thing I can think of right now is the timer3_isr () is called by the timer0 when it's overflow.
MY VERSION IS 3.18
and IC 18F452 it does have timer3 and timer0.
I need help with two Timer interrupts. |
|
![](templates/subSilver/images/spacer.gif) |
DragonPIC
Joined: 11 Nov 2003 Posts: 118
|
other interrupts |
Posted: Wed Apr 21, 2004 12:13 pm |
|
|
If you suspect other interrupts, disable them. Break your code down to the simplest form possible to test just the part of code you are having problems with. |
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
Timer |
Posted: Wed Apr 21, 2004 12:54 pm |
|
|
It sounds like to me you have a program logic issue. Post your code so we can see what you are doing that may be causing the problem. |
|
![](templates/subSilver/images/spacer.gif) |
RKnapp
Joined: 23 Feb 2004 Posts: 51
|
|
Posted: Wed Apr 21, 2004 2:24 pm |
|
|
I haven't tested this or consulted the data sheet to see how timer3 behaves, but is it possible that you don't need to disable the timer3 interrupt?
I'm thinking there could be an "extra" interrupt at time zero that fires, and that's why the value you load into the timer itself is irrelevant.
The plan could be, sure, load the timer, enable interrupts, then let the interrupt fire & go to the ISR (interrupt service routine), then reload the timer from within the ISR. But don't disable the interrupt from within the ISR. This way, you should get regularly timed interrupts.
Another plan, the timer0 interrupt is probably firing more often than 2 seconds. Why not put in a strobe inside it and skip timer3? E.g., if it is firing at 1Khz and you're traveling into its #int_rtcc isr every millisecond, why not use a counter in there, and once every 2000 trips, flip the state of your A3 pin? Inside my #int_rtcc ISR, I have lots of "stock" strobe intervals that are set up as little booleans that I use elsewhere in my program.
Just a thought, good luck,
Robert |
|
![](templates/subSilver/images/spacer.gif) |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: service the wrong interrupt |
Posted: Wed Apr 21, 2004 2:33 pm |
|
|
wynnet wrote: |
set_timer3 (0x1111); // any 16 bit number
enable_interrupts(int_timer3);
|
This is not good because you are not clearing the interupt before enabling it. The interupt flag is not cleared by enabling the interupt. The interupt flag is set when the timer overflows reguardless of if the interupt is enabled. The flag is probably already set when you load the timer and enable the interupt.
The latest versions of the compiler have a clear interupt function documented in the readme file. |
|
![](templates/subSilver/images/spacer.gif) |
wynnet
Joined: 02 Dec 2003 Posts: 15
|
service the wrong interrupt |
Posted: Wed Apr 21, 2004 6:46 pm |
|
|
somehow the answer from RKnapp is correct.
I comment out the disable interrupt inside the isr
and I get 100ms pulse. 1/10 of a second
I only need one single pulse (no repeat).
my crystal is 4.19Mhz
with div_by_8 and timer load with 0x0001,
the longest pulse I can get is 100msecond. Is this correct?
assuming I need longer (time) pulse, what should I do? beside xtal |
|
![](templates/subSilver/images/spacer.gif) |
RKnapp
Joined: 23 Feb 2004 Posts: 51
|
|
Posted: Wed Apr 21, 2004 11:40 pm |
|
|
Actually, I think that Neutone and I are saying the same thing in different words. Glad that you're making some progress.
But you say you only need one pulse... so it seems to me you'd want to use an ISR to give you "counts" and in the main thread, add up those counts until they reach some huge number that you like...
... then use this long pulse to increment another int32 main thread counter...
.. then cascade as many of these as you want until you're counting for many years... and when you've reached your target, set your pin!
Good luck,
Robert |
|
![](templates/subSilver/images/spacer.gif) |
wynnet
Joined: 02 Dec 2003 Posts: 15
|
service wrong interrupt |
Posted: Fri Apr 23, 2004 12:08 pm |
|
|
Thank you,
so after the timer overflow, I get an interrupt, and instead of set my pin high, I just increment a variable by one. and have an if statement to say if (variable == xinterrupts) { set pin high};
I would like be clear about this interrupt thing.
by coding:
set_timer3 (0x0001); // I load the timer with a number for it to count
// up to 0xffff generate an overflow.
you say I don't have to have enable_interrupts (timer3);
statement. to enable the interrupt and therefore I don't have to disable
the interrupt inside the isr function(); would you clarify this please
Another question: so in the isr function() do I reload the timer with a statement set_timer3 (0x0001); again |
|
![](templates/subSilver/images/spacer.gif) |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: service wrong interrupt |
Posted: Fri Apr 23, 2004 12:25 pm |
|
|
wynnet wrote: | Thank you,
so after the timer overflow, I get an interrupt, and instead of set my pin high, I just increment a variable by one. and have an if statement to say if (variable == xinterrupts) { set pin high};
I would like be clear about this interrupt thing.
by coding:
set_timer3 (0x0001); // I load the timer with a number for it to count
// up to 0xffff generate an overflow.
you say I don't have to have enable_interrupts (timer3);
statement. to enable the interrupt and therefore I don't have to disable
the interrupt inside the isr function(); would you clarify this please
Another question: so in the isr function() do I reload the timer with a statement set_timer3 (0x0001); again |
When the timer overflows the timer interupt flag will be set.
The timer never stops incrementing. It goes from 0xFFFF to 0
If both the timer interupt flag and timer interupt enable flag are set, the program will jump to the interupt code, run it, and jump back to main.
The compiler will cause the interupt flag to be cleared after the interupt code is run.
The time between interupts is a fixed value for a given timer setup. You can count these fixed intervals to time events.
Loading the timer with a value will change the interval time but also causes jitter in the interval time. |
|
![](templates/subSilver/images/spacer.gif) |
RKnapp
Joined: 23 Feb 2004 Posts: 51
|
|
Posted: Fri Apr 23, 2004 1:28 pm |
|
|
Neutone,
Causes jitter? Have you checked this? And if so, how do you avoid this?
Here's the top of my "clock" routine which is called when my 1Khz timer's interrupt fires. I wouldn't be getting 1KHz interrupts out except by virtue of preloading that timer.
Code: |
/* ===========================================================================
Function Name: ISRclock
Purpose: Timer0 ("RTCC") ISR.
Note: We're using a 20MHz clock, and this is divided by the
8720 into four "zones of quadrature" resulting in 5Mhz operation.
There is a possible pre-scale of the clock into the timer0
accumulator, and then the possibility of "pre-loading" the
accumulator so that it rolls over more quickly than 8 or 16
bits would normally roll over. Timer0 generates an interrupt
when its accumulator rolls over; servicing the interrupt via
this code somehow clears the interrupt unless NOCLEAR is used.
============================================================================*/
#int_rtcc
void ISRclock () // do not pass parameters to an ISR
{
// Local data:
// Macros:
// Begin Procedure ==========================================================
set_timer0 (TIMER0_PRELOAD); // decreases time to next interrupt
x_RTtime.t_frmticks ++; // increment the "fastest tick"
if ( x_RTtime.t_frmticks >= TICKS_IN_ONE_FRAME ) // => reached end of frame
{
x_RTtime.l_waiting = FALSE; // F: time to start the next frame
x_RTtime.t_frmticks = 0; // reset within-frame-tick counter
// 100Hz output:----------------------------------------------------------
x_RTtime.lTime2SendMsg = TRUE;
// -----------------------------------------------------------------------
... etc.
(and by just cascading a bunch of ifs & counting variables inside this ISR, I can count long intervals such as:)
// Count TOTAL minutes since chip startup: (will be summed on EEPROM):
x_RTtime.t_seconds0to59++;
if ( x_RTtime.t_seconds0to59 > 59 )
{
x_RTtime.t_seconds0to59 = 0; // 0..59
x_RTtime.t_minutes++; // is not reset; time since startup
}
}
|
Now in my case, though this will vary by clock speed, as far as I know, I have to have, in a header file:
Code: |
#use delay(clock=20000000)
// Timing Parameters:
// 1000 Hz interrupts (ticks): for ISRclock:
#define TICKS_IN_ONE_FRAME 10
#define TICKS_IN_ONE_SECOND 1000
#define TIMER0_PRELOAD 101
#define TIMER0_SETUP_BYTE ( RTCC_INTERNAL | RTCC_DIV_32 | RTCC_8_BIT)
// 100 Hz interrupts:
//#define TICKS_IN_ONE_FRAME 1
//#define TICKS_IN_ONE_SECOND 100
//#define TIMER0_PRELOAD 62
//#define TIMER0_SETUP_BYTE ( RTCC_INTERNAL | RTCC_DIV_256 | RTCC_8_BIT)
|
and in the main body of code, to get this baby cranked up:
Code: |
enable_interrupts ( INT_RTCC );
enable_interrupts ( GLOBAL );
|
Note that I'm always happening to use the 8-bit timer0, not its 16-bit capability. The datasheet explains this, if not quite as clearly as Neutone's comments above. As PCM often reminds us -- quite appropriately -- please see the datasheet.
So wynnet, YES, unless Neutone has a better way, I don't see how else other than preloading the timer (with a value you calculate) you can achieve timing pips at desired intervals. But once you've got that lovely heartbeat (1Khz in my case) you just say, well shucks, 1000 of those is a second, 60 secs is a minute, 60 of those are ... and you're off to the races.
Good luck,
Robert |
|
![](templates/subSilver/images/spacer.gif) |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Fri Apr 23, 2004 2:08 pm |
|
|
There are some functions that require the interupts disabled for a few instruction. If the interupts are disabled while in interupt occurs and then the interupts are then re-enabled the interupt will then fire a few instructions late. You also have the condition where another interupt is being run when the timer overflows. That causes an added delay before running the interupt routine. The best method I know of to suite your use would be to read the timer and add a fixed amount but this does not work as well when the timer has a prescaler. The amount of jitter is small but it does add over time. |
|
![](templates/subSilver/images/spacer.gif) |
|