This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problem passing variable to function in ISR

So, I have a problem sending a value to a function at different parts of my code. Here is my code:

void LongRightShift(unsigned char NumBitsShift)
{
// My Code Here
     NumBitsShift = NumBitsShift; // So you can place a breakpoint here and read NumBitsShift
}

Now, when I call

LongRightShift(2);

in the main part of my program, NumBitsShift = 2. When I call it in the Decimator2_ISR, NumBitsShift = 1;

Does this have to do with the way I'm passing it or is there a conflict with running other functions in an ISR?

Any help you can give me would be appreciated. Thanks!

  • or is there a conflict with running other functions in an ISR?

    Yes, there is a conflict with running the same function from both the main code and an ISR. There is also a conflict with calling a function from any other one (including an ISR) that's running off a different register bank.

    If you need more help than that, you'll have to show more of your actual source code. Try to find the smallest possible example source that still shows the problem. And don't be to ashamed if halfway through this reduction process you have one of those "DOH! What was I tinking?" moments --- that's happened to everyone.

  • Could the problem for this be related to another problem I'm having? I have the following code:

    void AverageOutput(void)
    {
            unsigned char tempvar = 0;
            unsigned char NumOutSamples = 0;
            unsigned char Pressure1 = 500;
    
            if(Pressure1<600)
            {
                    NumOutSamples = 0;
                    AveragedPressureOut=Pressure1;
            }
            else
            {
                    //More code here
            }
            tempvar+=1; // Place breakpoint on this line
    }
    

    The trouble I'm having is that the code I run never makes it to the breakpoint (tempvar+=1). For whatever reason, it finishes the if statement and then completely exits the routine.

    My if statement used to read:

    if(((Pressure1-AveragedPressureOut)>410)||((Pressure1-AveragedPressureOut)<-410))
    

    But even when Pressure1 was equal to AveragedPressure, it would still enter that loop and then would exit prematurely as you are seeing in the simplified code I have above it. Something funny is going on but I don't really know what it is.

    I am calling this function from within another function, which you had mentioned could be a problem, but it is being called from the same .C file. I have this function defined in my VARS.H file using this line:

    void AverageOutput(void);
    

    Am I doing something wrong here that might be causing this problem? Codewise, I'm at 7000 or so so I still have available codespace and I'm not overflowing in my Data, IData, or Xdata registers.

    I hesitate to blame this on Keil and realize it's probably something I'm doing wrong but for the life of me, I don't really know what's going on and it's hard to write code when the compiler itself begins to develop logic errors, my fault or not. I need to resolve this issue or I can't move any further.

    Any help would be GREATLY appreciated. Thanks a lot!

  • Two things to consider.

    One is that if you have code that gets called using different register banks or can be called asynchronously from different places, then you fool the compiler/linker. The compiler/linker converts auto variables into nameless global variables where each of these global variables may represent one or more auto variables. The flow control of the compiler/linker looks at what auto variables that may exist at the same time and matches them to different global variables. While auto variables that may not exist at the same time can reuse the same global variable.

    The above is very complicated, and only done because the 8051 has such a lousy support for a real hardware stack.

    If you mix register banks when calling a function, then the compiler/linker assumptions will break.
    If both main loop and an ISR calls the same function, then the compiler/linker assumptions will break.

    But there is another thing to consider too - the compiler/linker looks for common code. So quite often, a function may run the initial source lines, but then suddenly jump somewhere else. The compiler/linker have noticed that more than one function in the program have a code block that looks identical. Either it's the tail of two functions, in which case one of the functions can end with a jump into the middle of the other function. Or maybe it is some sequence in the middle of a function that is common with other code somewhere - so the code sequence can be broken out into a new, auto-generated, function. This can surprise a lot when trying to use breakpoints - the code is run. But the code isn't in this function, but instead identical code is run somewhere else.

  • That makes a lot of sense and definitely brings attention to how little I know about what's actually going on behind the scenes. I'm not sure I follow 100% of what you're saying but I'll read it over a bit and see if I can wrap my head around everything you wrote here.

    Is there a place I can look to find out how to see what register banks each variable is being stored in to see if the auto assign is placing something in a different register bank and causing issues?

    I guess my question is where do I start to learn a solution to this issue? Is there something I can do in code to work around this?

    As far as "identical looking code" being compiled in an odd way (at least, I think that's what you're referring to), I don't believe I have much optimization set (it's currently set to 8 - Reuse Common Entry Code . . . maybe that's what you're referring to though).

    As far as other settings go, I have the memory model set to Small, the Code Rom Size set to Large, and no operating system (I am currently using a M8051W chip from Mentor Graphics).

    If you need any additional information, please let me know.

    One last thing I should note, the NumOutSamples and Pressure1 variables are being stored as global variables and I have them in my VARS.C file as:

    signed short idata Pressure1 = 0;
    unsigned char NumOutSamples = 0;
    

    and my VARS.H file as:

    extern signed short idata Pressure1;
    extern unsigned char NumOutSamples;
    

    I apologize in advance if this causes any confusion or seems to conflict with my previous code posts, I was trying to create a simple piece of code that is quick and easy to read and evaluate.

    Thanks again for the help!

  • I just realized that the lower the setting, the less optimization. I guess I misunderstood the optimization ratings because setting the number lower makes my code bigger. Which is concerning, already being at 7k . . . :p

    I guess I have a lot more optimization in my code than I realized. That might explain a few things . . .

  • void AverageOutput(void)
    {
            unsigned char tempvar = 0;
            unsigned char NumOutSamples = 0;
            unsigned char Pressure1 = 500;
    
            if(Pressure1<600)
            {
                    NumOutSamples = 0;
                    AveragedPressureOut=Pressure1;
            }
            else
            {
                    //More code here
            }
            tempvar+=1; // Place breakpoint on this line
    }
    


    That code does nothing, the Optimizer can remove it since it will not change the operation of the code.
    If tempvar was static it may keep it. it is was a volatile and declared out side the function it would be forced to keep it.

  • Did you noticed this ?

    unsigned char Pressure1 = 500;
    
            if(Pressure1<600)
    

    What is the maximum number that unsigned char in C51 can hold?

  • The reason your break point fails is most likely because there is no code generated for:

    tempvar+=1; // Place breakpoint on this line
    

    The compiler has no reason to generate code for this since the next thing it does is exit the function.

    Jon

  • void AverageOutput(void)
    {
            unsigned char tempvar = 0;
            unsigned char NumOutSamples = 0;
            unsigned char Pressure1 = 500;
    
            if(Pressure1<600)
            {
                    NumOutSamples = 0;
                    AveragedPressureOut=Pressure1;
            }
            else
            {
                    //More code here
            }
            tempvar+=1; // Place breakpoint on this line
    }
    

    If that's your actual code, and you're not terribly worried about all the compiler warnings you get about it, then you you have the warning level set way too tolerant. For starters, this line

    unsigned char Pressure1 = 500;
    

    must have triggered a warning about an out-of-range initializer --- 500 is too big for an unsigned char.

    As-is, for sufficiently high optimization level this entire function could be optimized into a one-liner

    void AverageOutput(void)
    {
         AveragedPressureOut=244;
    }
    

  • One last thing I should note, the NumOutSamples and Pressure1 variables are being stored as global variables and I have them in my VARS.C file as:

    signed short idata Pressure1 = 0;
    unsigned char NumOutSamples = 0;
    

    Unfortunately, that means the code you showed so far has esentially no relation any more to the code you actually used. That makes it all but impossible to help you meaningfully.

    You've not only messed up the type of your key variable, Pressure1, from short to unsigned char, but also changed its storage duration (from static to automatic) and linkage (from function-internal to global). In short, you kept nothing but the name intact.

    If you have problems with some code, you really have to show that actual code, or at least a reduction of it that actually exhibits all the problems you have.

  • My apologies to everyone here for the confusion. I didn't post my entire code because it is rather lengthy and tried to post a fairly straight forward example of what I'm seeing but apparently, I made a few mistakes when posting an "example" that obscured the issue.

    Pressure1 is actually an unsigned SHORT (it was the end of the day and I looked right past this. It's originally in my VARS.C file so I had moved it over here and, apparently, posted it incorrectly).

    However, all your posts did help me understand how the compiler works and how it removes code that goes nowhere and, sure enough, I did have that realization that I did something very dumb. The reason tempvar was in there is I was testing my function with multiple pressures and created an if statement to give those values that looked like this:

            if(ProcessedSensorNumber==1)
            {
    
                    unsigned char i = 0;
    
                    if (tempvar==0)
                    {
                            Pressure1 = 500;
                    }
                    else if (tempvar==1)
                    {
                            Pressure1 = 550;
                    }
                    else if (tempvar==2)
                    {
                            Pressure1 = 600;
                    }
                    else if (tempvar==3)
                    {
                            Pressure1 = 1000;
                    }
                    else if (tempvar==4)
                    {
                            Pressure1 = 1002;
                    }
                    else if (tempvar==5)
                    {
                            Pressure1 = 1004;
                    }
                    else if (tempvar==6)
                    {
                            Pressure1 = 1202;
                    }
                    else if (tempvar==7)
                    {
                            Pressure1 = 1800;
                    }
            }
    

    This is why I needed that

    tempvar+=1;
    

    line. The thing that caused all the problems I was seeing is that I placed the variable declaration IN THIS FUNCTION, rather than in my VARS.C file, which means it gets reinitialized everytime it enters the function and makes the increment pointless (hence why it was not simulating correctly).

    The function is now giving me problems with this logic statement:

    if(((Pressure1-AveragedPressureOut)>410)||((Pressure1-AveragedPressureOut)<-410))
    {
         // some code here
    }
    else
    {
         // more code here
    }
    

    when AveragedPressureOut = 500 (0x01F4) and Pressure1 = 550 (0x0226) (both are signed shorts)

    Now from what I understand, 550-500 = 50 so, since it is between -410 and 410, it should go into the else statement code but it appears to be going into the if statement code. I don't really understand why.

    I apologize for all the confusion earlier but thanks for the help! I understand what's going on with the compiler a lot better, which is always a good thing!

  • I'm afraid there's still some clarity that needs to be increased:

    Pressure1 is actually an unsigned SHORT (it was the end of the day and I looked right past this. It's originally in my VARS.C file so I had moved it over here and, apparently, posted it incorrectly).
    [...]
    when AveragedPressureOut = 500 (0x01F4) and Pressure1 = 550 (0x0226) (both are signed shorts)

    Not only did you contradict yourself there, but that bit of information you appear confused about is actually crucial to the issue at hand. The problem is that if even one of those variables actually is unsigned, in C51, then so is the resulting '50' you're comparing with the signed number -410. At that point you would enter the realm of comparisons between values of different signedness. You don't want to go there.

  • Nevermind, apparently, I had one of them declared as unsigned again. Is it really only Monday . . . heh.

  • Yeah, you caught it right before I posted here. I should've taken the extra minute to check on these things before posting them as truths. Sorry about that!

  • Well, software development is an iterative process :D