Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Difference between normal function and ISR

Status
Not open for further replies.

bittware

Full Member level 4
Joined
Apr 3, 2004
Messages
208
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,296
Activity points
1,986
isr function

Hello experts,
Because I saw almost all ISR function definition as such void xxx(void). I wonder is if ISR(Interrupt Service Routine) can only share data structrue via globle defined variables and cant return value?
Could anyone out there explain it?
Thanks in advance.
:)
 

function and isr

When you have normal function you can call it in program, and can say
res= fun1(x);
But you do not call interrupt like res=ISR. It is made by some asynchronous event, like timmer overflow, pin change... Because of that interrupt does not return, or have parameters.

When you work with some asynchronous event, one way is to poll some flag and see if event happend. This is a full waste of time, because program cannot do anything else.
This was solved that with interrupt. When event occure, then your program go to ISR, execute its instructions, and after that goes on the next instruction in the main program.
 

difference between function and event

also your main program can call ISR routine whenever it is necessary by setting the corresponding interrupt flag
 

isr functions

A function is usually called in a very predictable way. When you call the function, the function itself modify some registers, for which it know the content must be saved, and restored before the function exit. But some other variables, like the one used mainly for temporary storage, are not saved. This way, the function can be called and returned from more quickly. The compiler define which registers are temporary, and make sure that the caller also is aware that when the function is called, that the content of those registers will be undefined after function call.

Also, a function, when called, already expect some registers to be pre-set, like the data segment for example.

However, an ISR is there to respond to an interrupt. An interrupt is an event which usually occur at an unpredictable moment. For example, when the user press a key. At this time, you wish your system to retrieve the key code from the keyboard register immediately. Similarely, if you specify a timer which occur, let's say, 100 times per seconds, it may be imperative that the event be trated immediately, and not a few milli-seconds later. So, instead of making your program check for those events continuously, you let your program run, unaware of those events. When those events occur, the idea is that your program stop whatever it's doing, then a special function is called (the interrupt service routine, or ISR). The ISR do whatever processing is needed, and then when it exit, your program continues to run, without even knowing it was briefly interrupted (in fact, the idea is that it doesn't even need to know of it). This is based on the principle that some event need to be processed as soon as it arrive, do so quickly, and have higher priority than any running process.

However, for the above 'magic' to take place, there is much more things involved than calling a simple function, like a regular function. First, since an ISR can be called at any time, while running any process, the ISR can not make any assumption about any of the registers content, when it's called. So, the data segment and any other processor state can be anything at that time. In particular, the ISR can not place anything at first hand on the stack (like local variables) since the stack pointer itself can also be anything. So, a thing that any ISR must do is set all those needed registers when it enter. So, setting those register is fine, and the ISR will be able to process normally, whatever the CPU state was before the ISR got called.

However, there's another *VERY* important thing (and I mention it in bold) that an ISR must do. As mentionned above, any running program can be interrupted at any time. The magic work in the fact that those programs must not see any evidence that it got interrupted. Now, an ISR, like any other functions, feed on CPU registers. The CPU also have only one big set of registers. Any registers used by the ISR are the same registers used by any programs running before the ISR got called. If you wish wour running programs to not see any glitches, the ISR *MUST* restore any registers it use to the exact same state as when it got called. If you forget to restore even a simple register, very unpredictable things can happen when your ISR return to the interrupted process. For example, if a process wish to calculate some equation, and send the result to some other variable, but get interrupted in mid way of evaluating the expression, and that a bad coded ISR forget to restore a register used by your program equation, then your program will result in a wrong result. This make very hard to track problems, as you'll suspect your program, when it doesn't have anything wrong. Moreover, problems usually will never occur twice at the same place. The end-result will be random program crash and system instability.

So, an ISR flow usually consist of:
- Save ALL registers and system states
- Set all registers needed by the ISR, including the data and stack pointers.
- Process the event
- Restore ALL registers
- Return to the interrupted process (isually with a IRET instruction instead of a simple RET instruction, which also restore the CPU flags).

Just when you taught that this may be complicated, here come a somewhat more substil concept, also as equally important to grasp. Some things must also be taken into account when working with ISR. This is what's usually called as 're-entrancy'. Some functions are not re-entrant. Meening that they must not be called from within an ISR. Those are generally functions that are written to be accessed by regular programs (non-ISR). For example, a function that set, and depend on, global variables, must not be called by an ISR. That was more evedent in the old DOS days, but still present in Windows.

Let's take an easy example. Let's say that a function (that we'll call 'Interest'):
- Store the parameter content to a global variable.
- Later on in the function, read back that value.
- Increment it by 1%
- Return the new value.

Now, let's say that the caller of such function call the function with a specific parameter. It will expect that the function will return that value plus 1%.

Example, let's say a banking program take the money from each client, and add the interest rate. Let's say some client (called 'Dummy') have 1000$ in his account:

- Get 'Dummy' client balance (1000)
- Call the 'Interest' function.
- Store the result to his account.

Clearly, the 'Interest' function, adding 1%, will return 1010. A value of 1010 will then be set into that client account.

Usually, at this moment, you start to wander whare I what to go with this... :) The fun part begin (well, as you'll see, not for our to-be-unhappy bank custommer)...

Let's say that an event is set to precess some transactions in real time. Let's say that at a specific moment in time, an event occur for which a specific account need to be treated. That account need his interest rate to be evaluated. It must occur fast, and so is coded in an ISR.

The ISR take that client (called 'VIP') account info and add the interest, save it back and return to whatever function was running. So, the ISR

- Take the client account info (let's say he have only 100$ left).
- Call 'Interest' function.
- Save the result back to the client account (101$).
- Return to the interrupted program.

Now, imagine that the above event occur at the same time that the first example was running:

- Take 'Dummy' client account ballance (1000$)
- Call the 'Interest' function.
> (From within 'Interest' function)
>- Store the parameter content to a global variable.
>-***INTERRUPT OCCUR HERE, 'VIP' client need interest calculation***
>- Later on in the function, read back that value.
>- Increment it by 1%
>- Return the new value.
- Store the result to his account.

Now, the VIP client, will get calculated at the point mentionned above. The following will occur:

- Take 'Dummy' client account ballance (1000$)
- Call the 'Interest' function.
> (From within 'Interest' function)
>- Store the parameter content to a global variable (Global = 1000).
>-***INTERRUPT OCCUR HERE, 'VIP' client need interest calculation***

---Switch to ISR---

- Take the 'VIP' client account info (let's say he have only 100$ left).
- Call 'Interest' function.
> (From within 'Interest' function)
>- Store the parameter content to a global variable (Global = 100).
>- Later on in the function, read back that value (Global = 100).
>- Increment it by 1%
>- Return the new value.
- Save the result back to the 'VIP' client account (101$).
- Return to the interrupted program.

---Switch back to program---
>- Later on in the function, read back that value (What is the global variable now?? It is 100, as the last value set to it, in this case, by the ISR!!)..
>- Increment it by 1%
>- Return the new value (101).
- Store the result to 'Dummy' client account. (poof, he now have 101$ instead of 1010$!)

The above issue occur because on 3 things:
- The 'Interest' function rely on a global variable.
- The 'Interest' function is called by an arbitrary program.
- The 'Interest' function is called back (said to be re-entered) by the ISR, which screw the global variable.

Havn't I said that ISR must save every register values before? Well, even though it saved every registers, it didn't (and can not) save every global variables. It can only save registers. It is also not expected that the ISR will know, when it enter, every memory locations used by any of it's called sub-functions. So, that 'Interest' function, by the way it is coded, is said to be 'non re-entrant', a thing that an ISR *MUST* avoid at all cost.

Had the program above be interrupted at any other places than from within 'Interest' function, there would have been no visible bug. In a big program, for which a problematic non re-entrant function get called only a fraction of the total running time, it is well forseable that such a potential bug not be seen before running for a few minutes/hours/... and even years. It also may never occur and then suddenly, you make a change to your program, and see a problem never before seen, occur twice daily, just because of good timing... So, sometime, in some case, this can be very hard to track.

There are ways to get out of all this mess, but the functions that an ISR call must be know in advance if they are re-entrant. For the functions to be re-entrant, it must be coded to be so. This involve much deeper programing and debugging knowledge. But as a rule of thumb, if you make an ISR, either call re-entrant functions, or functions that you know are called only withing that ISR (and not by other arbitrary programs). The exact same problem occur with multi-tasking program, and usually, some of the multitasking rules can be applied to ISR, to ensure program stability, but where a multitasking program can wait (a semaphore for example), an ISR can not wait for the program, or at least, must return and wait the next event to see if it can call specific functions.

Big Boy
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top