We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello,
I am having two problems which I think are pretty much related to each other:
Problem 1: passing parameters to function called from ISR
I am invoking a function from ISR. To this function, I pass a variable (unsigned char). When the function is invoked, the value received in the function is zero! If the same function is called from main (), then the value received = the value passed. What am I missing ? How to rectify this problem, besides use of global variables to pass the data (this work around I am already using).
Problem 2: function called from ISR does not behave as intended
There is a delay function that I invoke from the ISR (void delay_6ms()). I have simulated the code on KEIL, which shows that the delay introduced by this function should be to the tune of 6 msec. When I invoke it from ISR, the delay is about 320 usec, however, when I invoke it from main (), the delay is about 4 msec. Why the difference ? Why main() does not give 6 msec delay ?
If I declare the variable inside the function as static (i and j), the delay in ISR changes to 1.4 msec. I tried to declare the function reentrant to see the effect, but there was no change.
--------------------------------------------------- void delay_ms() { unsigned char xdata i; unsigned char xdata j;
i = 0;
while(i++ < 25) { j++; }
i = 0; }
void delay_6ms () { delay_ms(); delay_ms(); delay_ms(); delay_ms(); delay_ms(); delay_ms(); } ---------------------------------------------------
This function should give 1 msec delay, and if called multiple times, then should give a delay in proximity to the number of times it is called.
Regards Aman
When the function is invoked, the value received in the function is zero!
Are you using a different register bank for the ISR (i.e. is it declared with "using X") ? Functions calling each other are expected to use the same register bank by the compiler. If they do not follow this convention, the program will misbehave.
I have simulated the code on KEIL, which shows that the delay introduced by this function should be to the tune of 6 msec.
1. Writing delay functions in C is not a wise idea. There is absolutely no guarantee that they will produce the same delay if anything (compiler, compiler revision, optimization settings, etc) changes.
If you need a fixed delay, write the function in assembly or use a timer.
2. About the difference in run-time:
Again, this might be a register bank issue. Is your ISR using the same register bank as the rest of the program ? If it is not, then calling functions that expect it to will result in problems.
There might be another reason for the time difference: Does your chip have a feature that lets it execute ISRs at the maximum CPU frequency even if the clock is set to a lower frequency ? Some chips can do this (for example some of the Analog Devices ADuC chips).
Calling pure time delays from an ISR is generally a bad idea - as this means that your entire system will be stalled for the duration.
In fact, calling any function from an ISR is generally best avoided - the ISR should just do the absolute minimum necessary to capture the event and signal it to the rest of the code; any other processing should be done outside the ISR.
Of course, all of the above is In General; you may have specific reasons to do this - if you do, it would be best to fully explain them, so that people can give relevant suggestions!
Hi guys!
I am using a Teridian 6521 EM IC. Some data needs to be written into EEPROM. There has to be EEPROM write delay in between. This answers the "why delay in ISR" question. The ISR is a "sag" ISR, which means that the system is going down. I have to save data and sleep before power is below the operating voltage.
The ISR is using "using 1", but the function is not using any "using X". Should not the compiler handle this; switch the register bank before invoking the function and pass variables in the appropriate register bank ?
Please believe me that it is absolutely necessary to do this in ISR. I cannot use another timer, because they are already busy with other stuff. I have to write into EEPROM in main() also, therefore I need to keep the functions same for both. This chip does not support a faster speed for ISR (or if it does, please let me know).
Lets say that the compiler version, optimisation, bla bla are kept constant. Then why the difference ?
What do you suggest now ? I want to know the suggestions for a possible cause, so I can rectify it. If the simulator is saying this function will take "x" msec, why doesnot the actual execution take the same time ?
you cannt acuretely simulate writing to EEPROM because the time you need to write is variabible so you must look at datashit for worst timing for a write so you can see how long it will take for the ISR lag but how long have you got for the ISR lag becoz if it is not long enough you will not have time to write all of youre data to the EEPROM and you will not have good data if you caal function from ISR you might use 'dont use absolute register accesses' option in compiler options bcoz else compiler assumes register bank for direct access to register but might be wrong register if ISR has using something else
Are the delay called from main() slowed down because you have a high-speed interrupt constantly stealing time from the loop?
By the way - you say that you don't have any timers available. That means that you are using your timers. Any timer having a frequency suitable for polling by the delay function?
"There has to be EEPROM write delay in between. This answers the "why delay in ISR" question"
Actually, it doesn't! ;-) It answers why you need a delay, but not why it needs to be in the ISR.
"The ISR is a "sag" ISR, which means that the system is going down"
Now that does answer the question!
"Should not the compiler handle this; switch the register bank before invoking the function"
It does - but you have to tell it which Register Bank to use! If you don't state a Register Bank with the using qualifier, the compiler, as always, will use its default - which is, I think, Zero.
"If the simulator is saying this function will take "x" msec, why doesnot the actual execution take the same time ?"
Presumably because there's some vital information that you haven't (correctly) supplied to the simulator...
The ISR is a "sag" ISR, which means that the system is going down.
Ah, ok. That is a good example for an exception to the rule.
No, it does not and should not handle this (because doing so would mean that it switches banks at every function call, which adds unnecessary overhead). Register bank switches are taken care of by the called function, not by the calling function.
A simple solution would be adding a "using X" to the function that is called. Another solution would be having two copies of the same function, one for each register bank (assuming that you're not running out of program space). Refer to the chapter "Register banks" in the compiler manual to find out under which circumstances the compiler will generate a register bank switch.
In that case, I would assume it's the register bank mixup. Solve this issue first and check if the behavior changes.
What do you suggest now ?
Write the delay function in assembly. Then you can count exactly how many processor cycles it will use, giving you an exact delay.
Calling the same function from Main and and ISR alone can be an issue. The function would need to be reentrant. What happens if main is using the function when the ISR calls it. On a PC it works. With the 51 and Keil it the variable can be corrupted. Not that calling functions from and ISR can have a lot of overhead.