Is that possible to use interrupts for both USART (Rx) AND TMR0 at the same time? If yes, how can I distinguish who invoked the interrupt handler?
Although my question is a generic one, I'm using a 16F877A in my development board. I'll probably use a 18F452 in production, but I suspect the concept will be the same for both of them.
The application of this: I have to send commands from a PC to the PIC using RS232, and in this commands I'm sending time intervals to create a PWM signal. It's for controlling a R/C servo. I've read somewhere that some PIC's already have a PWM feature, but for this type of application, a timer would be better (is that so?)
I've already created one test app that does that but has a few limitations, first it relies on delaying the main loop of the app. The obvious disadvantage is that I won't have time for much else, and I need to control more than 1 servo simultaneously (2 to 4). My idea then is to create 4 timeslots of 5ms each, one timeslot for each servo. This way, for each 5ms, timeslot, I spend 1-2ms with a delay and I'll probably have plenty of cpu time to do other stuff. Am I going the right direction?
I'm sure others will chime in with a better response. Here is my super
tired, on the way to bed answer.
When you get an interrupt, you check the flags of the interrupts you
are interested in. look for the xxxIF flags. Remember, you have to
clear those flags too.
Josh
--
A common mistake that people make when trying to design something
completely foolproof is to underestimate the ingenuity of complete
fools.
-Douglas Adams
On Sun, 30 Jan 2005 17:01:24 -0800, Padu <spam_OUTpaduTakeThisOuTmerlotti.com> wrote:
> Is that possible to use interrupts for both USART (Rx) AND TMR0 at the same time? If yes, how can I distinguish who invoked the interrupt handler?
> Although my question is a generic one, I'm using a 16F877A in my development board. I'll probably use a 18F452 in production, but I suspect the concept will be the same for both of them.
> I'm sure others will chime in with a better response. Here is my super
> tired, on the way to bed answer.
>
> When you get an interrupt, you check the flags of the interrupts you
> are interested in. look for the xxxIF flags. Remember, you have to
> clear those flags too.
>
> Josh
Note that this allows for (something like) priority in interrupt
handling, even in 12- and 14-bit core chips. Multiple simultaneous
interrupts will be serviced in the order they are checked. Any
interrupt NOT serviced will cause an immediate return to the interrupt
vector upon RETFIE. This doesn't mean that a lower priority interrupt
can be interrupted by a higher priority interrupt, just that more time
critical ones can be allowed to finish their business before less time
critical ones.
Also remember that not all interrupt flags are cleared by clearing
their respective flag; for example, USART interrupt flags are cleared
by taking the appropriate action on the involved register (writing
TXREG, reading RCREG).
On Sun, 30 Jan 2005 22:13:40 -0700, Robert Rolf wrote:
> In my application I have a half dozen interrupts going
> at once, so I have to poll the receive flag multiple
> places in the ISR to ensure I don't miss any characters.
In "multiple places" ??
Are you saying that you have some part of your IST taking
to long time to finish, so you have to check other flags and,
if needed, "call" another part of the ISR temporarily ?
Or, in other words, you are normaly (when not inside the ISR)
letting the interrupt system do it's stuff, but while inside
the ISR, you are actualy polling the receive flag ?
I'm sure you have thought of moving some of the larger
parts of the ISR out of the ISR, right ? (So it could be
"interrupted" the normal way by the receive interrupt...)
Why didn't that work ?
> Note that this allows for (something like) priority in interrupt
> handling, even in 12- and 14-bit core chips. Multiple simultaneous
> interrupts will be serviced in the order they are checked. Any
> interrupt NOT serviced will cause an immediate return to the interrupt
> vector upon RETFIE. This doesn't mean that a lower priority interrupt
> can be interrupted by a higher priority interrupt, just that more time
> critical ones can be allowed to finish their business before less time
> critical ones.
I am not sure this is a good idea. It will reduce the *average*
interrupt latency for the higher priority serivice code, but it might
not reduce the *worst case* latency. This will make latency-related
problems harder to reproduce. As a user, I (grudgingly) prefer a program
that misbehaves only once an day. As a tester I much prefer a program
that misbehaves each second!
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> > Note that this allows for (something like) priority in interrupt
> > handling, even in 12- and 14-bit core chips. Multiple simultaneous
> > interrupts will be serviced in the order they are checked. Any
> > interrupt NOT serviced will cause an immediate return to the interrupt
> > vector upon RETFIE. This doesn't mean that a lower priority interrupt
> > can be interrupted by a higher priority interrupt, just that more time
> > critical ones can be allowed to finish their business before less time
> > critical ones.
>
> I am not sure this is a good idea. It will reduce the *average*
> interrupt latency for the higher priority serivice code, but it might
> not reduce the *worst case* latency. This will make latency-related
> problems harder to reproduce. As a user, I (grudgingly) prefer a program
> that misbehaves only once an day. As a tester I much prefer a program
> that misbehaves each second!
So what's the solution? The intuitive method for dealing with
multiple interrupts is to check the most important interrupt first,
deal with it, check another, deal with it, check another, etc. until
all interrupts have been serviced, the RETFIE. If we only check one
interrupt, then RETFIE, the possibility exists that if that interrupt
recurs before the RETFIE, it could block all other interrupts from
being serviced. Another possibility is checking different interrupts
at different places within the ISR; I'm not sure I like that. So
what's your candidate for best solution, Wouter?
> So what's the solution? The intuitive method for dealing with
> multiple interrupts is to check the most important interrupt first,
> deal with it, check another, deal with it, check another, etc. until
> all interrupts have been serviced, the RETFIE. If we only check one
> interrupt, then RETFIE, the possibility exists that if that interrupt
> recurs before the RETFIE, it could block all other interrupts from
> being serviced.
So you have one specific interrupt with a shorter interrupt
intervall then it takes to process *one* of them ? How
do you expect that to work, no matter what else the PIC
is doing ?
> Another possibility is checking different interrupts
> at different places within the ISR; I'm not sure I like that.
It's signal to you that you have some design problem.
> So what's your candidate for best solution, anyone ?
Make sure that the longest ISR take a shorter time then the
fastest intervall for a single interrupt. Then you will
always have cycles to run your application. There's no magic
in that...
Mike wrote:
> So what's the solution? The intuitive method for dealing with
> multiple interrupts is to check the most important interrupt first,
> deal with it, check another, deal with it, check another, etc. until
> all interrupts have been serviced, the RETFIE. If we only check one
> interrupt, then RETFIE, the possibility exists that if that interrupt
> recurs before the RETFIE, it could block all other interrupts from
> being serviced. Another possibility is checking different interrupts
> at different places within the ISR; I'm not sure I like that. So
> what's your candidate for best solution, Wouter?
Humnn, never thought about this. The nice thing about this list is that you
ask something and end with answers to questions you actually never asked...
=^)
> > So what's the solution? The intuitive method for dealing with
> > multiple interrupts is to check the most important interrupt first,
> > deal with it, check another, deal with it, check another, etc. until
> > all interrupts have been serviced, the RETFIE. If we only check one
> > interrupt, then RETFIE, the possibility exists that if that interrupt
> > recurs before the RETFIE, it could block all other interrupts from
> > being serviced.
>
> So you have one specific interrupt with a shorter interrupt
> intervall then it takes to process *one* of them ? How
> do you expect that to work, no matter what else the PIC
> is doing ?
No, see below.
> > Another possibility is checking different interrupts
> > at different places within the ISR; I'm not sure I like that.
>
> It's signal to you that you have some design problem.
Agreed.
> > So what's your candidate for best solution, anyone ?
>
> Make sure that the longest ISR take a shorter time then the
> fastest intervall for a single interrupt. Then you will
> always have cycles to run your application. There's no magic
> in that...
Agreed. But you're still assigning a priority to the interrupts in
your system by the fact of the order in which you check them.
Wouter was suggesting that prioritization is a mistake. I'm
asking how to avoid it, since my limited experience leads me
to the solution of check one, deal with it, check the next, etc.,
and make certain that the worst case latency for dealing with
all of them won't cause another one to be missed.
>
>So what's the solution? The intuitive method for dealing with
>multiple interrupts is to check the most important interrupt first,
>deal with it, check another, deal with it, check another, etc. until
>all interrupts have been serviced, the RETFIE. If we only check one
>interrupt, then RETFIE, the possibility exists that if that interrupt
>recurs before the RETFIE, it could block all other interrupts from
>being serviced. Another possibility is checking different interrupts
>at different places within the ISR; I'm not sure I like that. So
>what's your candidate for best solution, Wouter?
The answer depends on how fast the ints come, and how critical they are.
If you're connecting to something that needs very tight coupling, high
priority, and short interval between hits, then maybe an int isn't the best
mechanism.
Serial ports are a good example of something that works well under ints.
They happen relatively infrequently (even at 115200) and generally don't
have a lot of logic attached.
It would be a mistake to do a lot of processing in any ISR, you're far
better off to stuff the data in a buffer, signal that it's arrived, and
carry on, and let a non-int task figure out what to do with it. Same goes
for the outbound side, the ISR should just pump bytes.
In the AVR, we don't have this flexibility, but the ints are vectored, and
I don't HAVE to push/pop anything for some ints.
What we have is fixed priority, and a guarantee of at least one non-int
instruction executing between ints, even if several are stacked up.
> On Sun, 30 Jan 2005 22:13:40 -0700, Robert Rolf wrote:
>
> > In my application I have a half dozen interrupts going
> > at once, so I have to poll the receive flag multiple
> > places in the ISR to ensure I don't miss any characters.
>
> In "multiple places" ??
>
> Are you saying that you have some part of your IST taking
> to long time to finish, so you have to check other flags and,
> if needed, "call" another part of the ISR temporarily ?
>
> Or, in other words, you are normaly (when not inside the ISR)
> letting the interrupt system do it's stuff, but while inside
> the ISR, you are actualy polling the receive flag ?
>
> I'm sure you have thought of moving some of the larger
> parts of the ISR out of the ISR, right ? (So it could be
> "interrupted" the normal way by the receive interrupt...)
> Why didn't that work ?
I have an application like that. There are 2 sources of
interrupt, an incoming RS232 message at 115,200 baud and
a PID control loop at 2Khz.
The PID calculations MUST be in the ISR to reduce timing
jitter as much as possible (the code originally had the TMR1
interrupt setting a flag that was used in the main loop to start
the PID calculations, but the timing jitter was too noticable,
and so the calculations were moved into the ISR).
And more than 2 characters can come in during the PID
calculations, so characters could be lost. The solution
was to check the RCIF flag in several places in the ISR
and buffer the incoming queue. The extra microsecond
or two in strategic locations did not give significant timing
jitter in the PID calculations, and no characters were lost.
Mike Hord wrote:
> So what's the solution? The intuitive method for dealing with
> multiple interrupts is to check the most important interrupt first,
> deal with it, check another, deal with it, check another, etc. until
> all interrupts have been serviced, the RETFIE. If we only check one
> interrupt, then RETFIE, the possibility exists that if that interrupt
> recurs before the RETFIE, it could block all other interrupts from
> being serviced. Another possibility is checking different interrupts
> at different places within the ISR; I'm not sure I like that. So
> what's your candidate for best solution, Wouter?
I'm not Wouter, but I check interrupt conditions in priority order, handle
the first one I find, then get out as quickly as possible. If there are
multiple interrupt conditions, then a new interrupt will be taken
immediately after RETFIE. This takes the least number of cycles to handle
the most important interrupt. Most of the time, interrupts do not overlap
anyway, so the extra cycles that optimize for that case usually pessimize
the overall system. If your highest priority interrupt occurs so frequently
that you have another interrupt immediately after finishing the previous,
you're processor is overloaded and you've got other problems anyway.
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
I see nothing wrong with an architecture that checks (polls) for higher
priority interrupts while in the middle of processing a lower priority
interrupt. It is effectively no different than an implementation that
supports multiple priority levels in hardware.
You do have to be sure you have enough processing power to get everything
done in time, but that is again no different than the hardware supported
case.
Also, there is really nothing intrinsically wrong with doing significant
processing in an interrupt handler. It can often simplify coding because the
interrupt handler code doesn't have to worry about task level code changes
things out from under it, whereas task level code must constantly be
concerned about interrupt level code changing things.
I have written applications where interrupt level code occupies over 85% of
the CPU (but with a guarantee that it will not exceed a fixed number <
100%).
You can look at my multiple UAR(no T) code stored on PICLIST.COM for a
program that does a lot at interrupt level.
The 'virtual peripherals' championed by Ubicom on the SX processors are also
high-cpu interrupt handlers.
William Couture wrote:
> The PID calculations MUST be in the ISR to reduce timing
> jitter as much as possible
No, only the measurement of the inputs and the writing of the output. The
computation only needs to be done between these and can jitter all it wants
as long as the results are computed in time to write them to the outputs.
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
On Mon, 31 Jan 2005 14:51:45 -0500, Olin Lathrop
<olin_piclistKILLspamembedinc.com> wrote:
> William Couture wrote:
> > The PID calculations MUST be in the ISR to reduce timing
> > jitter as much as possible
>
> No, only the measurement of the inputs and the writing of the output. The
> computation only needs to be done between these and can jitter all it wants
> as long as the results are computed in time to write them to the outputs.
No, I meant what I wrote.
If the PID calculation was done in the background loop, there would be
a variable number of instructions between the setting of the DO_IT_NOW
flag and the start of the PID update. The effect of this is that, while in the
long run the PID was updated at 2Khz, there would be a considerable
jitter in the timing, which showed up in the accuracy of position hold.
If the PID calculation was done in the ISR, the jitter was much smaller,
and the accuracy of the position hold was much better.
As for the idea of "read inputs in ISR, set outputs in ISR, do calculations
in background" that doesn't always work very well.
In our application, phase lag was a serious problem. There can also
be a problem with when interrupts occur. Since there are a limited
number of timers to play with and we have to keep things on schedule,
the "best" solutions are:
1) interrupt is at 2Khz, read current inputs and set outputs based on
previous interrupt. Unacceptable due to phase lag.
2) interrupt is at 4Khz, alternating interrupts read inputs and set
outputs. Better (though not very good) phase lag, but interrrupt
overhead is getting significant.
3) interrupt is a higher multiple of 2Khz, reading inputs and setting
outputs on appropriate interrupts. Good resolution on phase
lag, but interrupt overhead has changed timing (increased phase
lag) with respect to just doing the entire PID in the isr.
So, though it does not appeal to you, the entire PID was done in
the ISR. If you want to debate it, I'll pass you over to our control
systems engineer.
> So what's the solution? The intuitive method for dealing with
> multiple interrupts is to check the most important interrupt first,
My approach is to start using no interrupts at all. In an awfull lot of
cases where interrupts are used they are not needed. Just a big loop,
maybe synchronised to a counter overflow, can do a lot. We had a class
last year where six groups of ~5 students had to build and program a
remote controlled robot using stepper motors. 5 groups used interrupts
(often they used interrupts for everything). None of these groups got a
reliably working system. The 6th group used a 1ms main loop polling a
number of state machines. Worked flawlessly...
If you have one time-criticall issue that must be served faster than
your mainloop can cycle you might use an interrupt. This will often be
the receiving part of some communication, maybe the sending part too.
If you need multiple interrupts that can each tolerate a latency equal
to the execution time of the longest interrupt use a 'serve one
interrupt source' approach. Is does not matter which one you serve
first. (But also take the frequency of the interrupt into account!).
If each interrupt can tolerate a latency equal to the total interrupt
handlers time you can (but need not) use a 'serve all sources' approach.
If you feel you need more than one interrupt and they are all critical
(can't tolerate much latency) you are in trouble. Maybe solvable
trouble.
> If we only check one
> interrupt, then RETFIE, the possibility exists that if that interrupt
> recurs before the RETFIE, it could block all other interrupts from
> being serviced.
But only if it would consume >100% CPU time, which indicates some design
problem.
> So what's your candidate for best solution, Wouter?
Definitely the 'no interrupts' approach. Second place: if interrupts are
used, be prepared to think them over very very well, not just the code
but also the timing. If you can't prove to your pet or spouse that it
will work (not just functionally, but also with respect to timing) you
probably should not use interrupts.
Examples of interrupt use that I do like (when needed):
- wakeup from sleep on pin change
- (serial) communication buffer
- virtual peripherals (SX-style)
BTW I often use an interrupt flag (for instance the timer interrupt
flag) without interrupts. Just poll the interrupt flag in the main loop.
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> In our application, phase lag was a serious problem. There can also
> be a problem with when interrupts occur. Since there are a limited
> number of timers to play with and we have to keep things on schedule,
> the "best" solutions are:
> 1) interrupt is at 2Khz, read current inputs and set outputs based on
> previous interrupt. Unacceptable due to phase lag.
>
> 2) interrupt is at 4Khz, alternating interrupts read inputs and set
> outputs. Better (though not very good) phase lag, but interrrupt
> overhead is getting significant.
>
> 3) interrupt is a higher multiple of 2Khz, reading inputs and setting
> outputs on appropriate interrupts. Good resolution on phase
> lag, but interrupt overhead has changed timing (increased phase
> lag) with respect to just doing the entire PID in the isr.
>
save/restore etc omitted for clarity of exposition
> > So what's the solution? The intuitive method for dealing with
> > multiple interrupts is to check the most important interrupt first,
>
> My approach is to start using no interrupts at all. In an awfull lot of
> cases where interrupts are used they are not needed. Just a big loop,
> maybe synchronised to a counter overflow, can do a lot. We had a class
> last year where six groups of ~5 students had to build and program a
> remote controlled robot using stepper motors. 5 groups used interrupts
> (often they used interrupts for everything). None of these groups got a
> reliably working system. The 6th group used a 1ms main loop polling a
> number of state machines. Worked flawlessly...
<details snipped>
That's very interesting, Wouter. Goes against what I was taught- interrupts
are the "easy" way to do it. Although I suppose it's pretty similar to what
I've been doing lately.
I usually evaluate what I'm doing before deciding what to do. Anything which
does something periodic is a candidate for interrupts; I find it far easier to
setup a timer interrupt for every 200 ms or 4 s or whatever than to muck
about with waitloops and such.
> No, I meant what I wrote.
>
> If the PID calculation was done in the background loop, there would be
> a variable number of instructions between the setting of the DO_IT_NOW
> flag and the start of the PID update.
I don't grok this. Which instructions would be inbetween? There are
techniques to re-start a loop at fixed intervals, with zero jitter.
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> That's very interesting, Wouter. Goes against what I was
> taught- interrupts are the "easy" way to do it.
I am trying to teach the opposite - interrupts are like assembler (as
alternative to a HLL like C): in nearly all cases you won't need it, but
in the remaining case you will need it badly. But it is by no means
easy.
> I usually evaluate what I'm doing before deciding what to do.
> Anything which
> does something periodic is a candidate for interrupts; I find
> it far easier to
> setup a timer interrupt for every 200 ms or 4 s or whatever
> than to muck
> about with waitloops and such.
It might be easier to code, but is it also easier to
- test
- debug
- prove correct
Or rephrase: can you realy understand the (logic and timing) properties
of a program with 3 or more interrupt sources? Can you calculate the
worst case response time for each interrupt? Are you sure the interrupts
will never interfere (in timing or in logic) in a bad way with the main
code or with each other?
I think I might be able to do that (in fact I did such work for space
and defense projects) but I'd rather not if I can avoid it :)
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> Or rephrase: can you realy understand the (logic and timing) properties
> of a program with 3 or more interrupt sources? Can you calculate the
> worst case response time for each interrupt? Are you sure the interrupts
> will never interfere (in timing or in logic) in a bad way with the main
> code or with each other?
Nope. Not easily, anyway. But then, the only time I knee-jerk hands-down
use an interrupt is if the entire system is based on regularly occuring events.
A rarity, at best. But it happens. Once or twice I've had a system which
did nothing but interrupts. Again, a rarity. But it happens. Those are almost
always what someone with many more years experience than I would call
"trivial". I don't yet consider very many things at all trivial. ;-)
On Mon, 31 Jan 2005 23:14:01 +0100, Wouter van Ooijen <.....wouterKILLspam.....voti.nl> wrote:
> > No, I meant what I wrote.
> >
> > If the PID calculation was done in the background loop, there would be
> > a variable number of instructions between the setting of the DO_IT_NOW
> > flag and the start of the PID update.
>
> I don't grok this. Which instructions would be inbetween? There are
> techniques to re-start a loop at fixed intervals, with zero jitter.
while (TRUE)
{
if (DO_IT_NOW)
pid_calculations();
code_a();
code_b();
code_c();
code_d();
}
since the DO_IT_NOW flag could be set at any time by
the interrupt (or the TMR1IF flag), the PID code could run
immediately, or after all the other routines, or...
> while (TRUE)
> {
> if (DO_IT_NOW)
> pid_calculations();
> code_a();
> code_b();
> code_c();
> code_d();
> }
>
> since the DO_IT_NOW flag could be set at any time by the interrupt
> (or the TMR1IF flag), the PID code could run immediately, or after
> all the other routines
... and the only alternative to that code is to do everything
inside the ISR?
Your issues, Bill, seem to be with a particular(ly bad)
IMPLEMENTATION of an architecture, not with the architecture
itself. It isn't impossible to make your pid_calculations() code
run always at a fixed time after the DO_IT_NOW flag was set; it
just takes a little more creativity or experience or whatever.
-Andy
=== Andrew Warren -- aiwspam_OUTcypress.com
=== Principal Design Engineer
=== Cypress Semiconductor Corporation
=== (but open to offers)
===
=== Opinions expressed above do not
=== necessarily represent those of
=== Cypress Semiconductor Corporation
> It isn't impossible to make your pid_calculations() code
>run always at a fixed time after the DO_IT_NOW flag was set; it
>just takes a little more creativity or experience or whatever.
Feel free to enlighten us with your splendid code.
> while (TRUE)
> {
> if (DO_IT_NOW)
> pid_calculations();
> code_a();
> code_b();
> code_c();
> code_d();
> }
>
> since the DO_IT_NOW flag could be set at any time by
> the interrupt (or the TMR1IF flag), the PID code could run
> immediately, or after all the other routines, or...
But that's because you want your code to do too much. If sum of your pid
+ code_a + code_b etc execuation times takes more time than the timer
interval you should not execute all code_a + code_b + code_c + code_d,
but for intsnace only one of them (round robin fashion), or transform
one or more to a state machine that speads the execution time over more
than one call.
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> > while (TRUE)
> > {
> > if (DO_IT_NOW)
> > pid_calculations();
> > code_a();
> > code_b();
> > code_c();
> > code_d();
> > }
> >
> > since the DO_IT_NOW flag could be set at any time by
> > the interrupt (or the TMR1IF flag), the PID code could run
> > immediately, or after all the other routines, or...
>
> But that's because you want your code to do too much. If sum of your pid
> + code_a + code_b etc execuation times takes more time than the timer
> interval you should not execute all code_a + code_b + code_c + code_d,
> but for intsnace only one of them (round robin fashion), or transform
> one or more to a state machine that speads the execution time over more
> than one call.
Now you're saying I need to change the requirements. That's something
you need to take up with my employer.
for (;;)
{
if (task1())
continue;
if (task2())
continue;
if (task3())
continue;
}
Where the tasks are listed in order of priority. Each task is typically
written as a state machine. Each state starts with code that quickly
determines if the task has any significant work to do. If not the function
returns false. Otherwise the task performs a 'step' in its operation and
returns true.
I agree with Olin's view: do as little as possible during the interrupt
itself. Except
for serial characters being received (I stuff those immediately), just
set up flags
so that they can be serviced in the main code in a prioritized manner.
>>while (TRUE)
>> {
>> if (DO_IT_NOW)
>> pid_calculations();
>> code_a();
>> code_b();
>> code_c();
>> code_d();
>> }
>>
>>
>
>Sorry, I did not look at your code long enough. The standard 'fixed
>interval loop' looks more like this:
>
>while( TRUE ){
> while( ! DO_IT_NOW ){}
> pid_calculations();
> code_a();
> code_b();
> code_c();
> code_d();
>}
>
>Of course the total excution time must be less than the timer interval.
>If not read my previous post.
>
>Wouter van Ooijen
>
>-- -------------------------------------------
>Van Ooijen Technische Informatica: http://www.voti.nl
>consultancy, development, PICmicro products
>docent Hogeschool van Utrecht: http://www.voti.nl/hvu
>
>
>
>
On Tue, 2005-02-01 at 12:26 -0700, Bob Axtell wrote:
> General note, my thoughts:
>
> I agree with Olin's view: do as little as possible during the interrupt
> itself. Except
> for serial characters being received (I stuff those immediately), just
> set up flags
> so that they can be serviced in the main code in a prioritized manner.
Really it depends on the app, how the programmer thinks, and what feels
most "natural".
There are cases where doing "heavy stuff" in the interrupt MIGHT be a
good idea. Heck I've had cases where doing EVERYTHING in the ISR and
having the main program consist of just "goto start" all the time made
sense.
A good example outside of the embedded world is windows programs, most
are pretty much completely "interrupt" driven.
However, in general, an ISR is meant to be a "quick" thing, something
that needs to be done at a certain time quickly so that it doesn't
interfere with the "main" program. But I see NO reason that if you
understand the implications doing heavy stuff in the ISR is "wrong".
TTYL
Herbert Graf wrote:
> There are cases where doing "heavy stuff" in the interrupt MIGHT be a
> good idea. Heck I've had cases where doing EVERYTHING in the ISR and
> having the main program consist of just "goto start" all the time made
> sense.
I had a case once where I needed to convert a single serial data stream
(sortof like Manchester) into synchronous clock and data. There were only
something like 5 instructions per half-bit on a 20MHz PIC. I did this by
using the interrupt input like a "GOTO 4" input pin. There was no main code
after initialization. There was no RETFIE instruction and the stack just
overflowed, but that didn't matter because there were no calls.
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
Good example! - as without question Microsoft makes the
world's worst software, too.
Here's why I think this way:
1. Significant problems can occur when the INSIDE INT code
runs longer than the routine timer event. For example, if you
interrupt every 1ms, and your interrupt code exceeds that
frequently, the attempt to "catch up" can be a problem.
2. Detecting interrupt overruns can be difficult to do. It is much
safer to set flags and execute the needed code in the main loop.
3. INT adds a lot of overhead. If all you need to do is set a few flags
in global registers, there is no need to save W, status, FSR, or PClath
if all you need to do is set a few flags.
>On Tue, 2005-02-01 at 12:26 -0700, Bob Axtell wrote:
>
>
>>General note, my thoughts:
>>
>>I agree with Olin's view: do as little as possible during the interrupt
>>itself. Except
>>for serial characters being received (I stuff those immediately), just
>>set up flags
>>so that they can be serviced in the main code in a prioritized manner.
>>
>>
>
>Really it depends on the app, how the programmer thinks, and what feels
>most "natural".
>
>There are cases where doing "heavy stuff" in the interrupt MIGHT be a
>good idea. Heck I've had cases where doing EVERYTHING in the ISR and
>having the main program consist of just "goto start" all the time made
>sense.
>
>A good example outside of the embedded world is windows programs, most
>are pretty much completely "interrupt" driven.
>
>However, in general, an ISR is meant to be a "quick" thing, something
>that needs to be done at a certain time quickly so that it doesn't
>interfere with the "main" program. But I see NO reason that if you
>understand the implications doing heavy stuff in the ISR is "wrong".
>TTYL
>
>
>-----------------------------
>Herbert's PIC Stuff:
>http://repatch.dyndns.org:8383/pic_stuff/
>
>
>
> 3. INT adds a lot of overhead. If all you need to do is set a
> few flags in global registers, there is no need to save W,
> status, FSR, or PClath if all you need to do is set a few flags.
And, on the PIC18-line, that (saving of the "important" regs)
is done on the fly without any extra cycles. So *very* short
ISR's can be much faster on the 18's then on the 16's (if you
need the context saving).
And, yes, this doesn't work well (or at all) if you use both
interrupt priority levels, since there is only one set of
shadow context registers... Well, you can't get everything,
can you ? :-) :-)
> I had a case once where I needed to convert a single serial
> data stream
> (sortof like Manchester) into synchronous clock and data.
> There were only
> something like 5 instructions per half-bit on a 20MHz PIC. I
> did this by
> using the interrupt input like a "GOTO 4" input pin. There
> was no main code
> after initialization. There was no RETFIE instruction and
> the stack just
> overflowed, but that didn't matter because there were no calls.
IMHO this is a typical case (of the virtual peripheral type) where using
interrupts (or in fact using *any* obscure feature that gets the work
done) is appropriate.
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> Now you're saying I need to change the requirements. That's something
> you need to take up with my employer.
You did not state your requirements, so I could not take them into
account. If your requirements are that you should code your program in
the way you did I have to rest my case, but chaning your boss might be a
good idea. But if your requirements were stated in a
functional/performance way I don't see how changing the program struture
forces you to talk to your boss.
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> A good example outside of the embedded world is windows programs, most
> are pretty much completely "interrupt" driven.
Probably counterintuitive again, a lot of my objections to interrupts do
not apply to using threads in interactive programs. For an interactive
program responsiveness is a 'level of effort' goal, not a real-time
requirement. Hence it makes sense to make good use of every CPU cycle
available, yet there is no need to prove a certain time requirement. For
real-time program it's often the opposite: you must be very sure that
the timing requirement(s) are met, but it does often not make much sense
to do better.
Wouter van Ooijen
-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu