#77223 - CyberSlag5k - Wed Mar 29, 2006 4:40 pm
Quick question, can I pass my Interrupt Handling function a variable? I'd like to pass it the address of my OAM data for use during the actual interrupt. Is it just a simple matter of doing something like this:
REG_IRQ_HANDLER = myInterruptFunction(&stuff);
Or must I do something tricky?
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...
#77228 - Cearn - Wed Mar 29, 2006 5:33 pm
Function arguments rely on passing data of the calling function to the called function (in ARM's case via registers r0-r3 + stack). Hardware interrupts can happen at any point in the code, you never really know what the states of the registers are, so basically no, you can't pass arguments in isr's like you would in normal functions. Well, maybe there is, but that would indeed rely on trickery.
You could just use a global variable to store that pointer, though.
#77229 - CyberSlag5k - Wed Mar 29, 2006 5:42 pm
You mean like an extern stored in some commonly shared file? I had that thought but was unsure of when exactly it would be defined. before I use it in the one file or not. Or does that not matter, as everything will come together simultaneously at link time?
What I mean is this:
//gba.h
extern u16* myVar;
//fileOne.cpp
u16* myVar = spritePtr;
//fileTwo.cpp
myVar[0].attribute2 = 0;
The order I compile everything in has no bearing on when myVar is defined as a pointer to my sprite data, right? So I should be able to do something similar to the above?
I've never really used extern much, so I'm not 100% sure of the exact mechanics of sharing things between separately compiled objects, but it's fun and interesting to be learning about it now.
Anyway, thank you for your reply, Cearn. Am I on the right track?
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...
#77232 - Cearn - Wed Mar 29, 2006 6:09 pm
CyberSlag5k wrote: |
Am I on the right track? |
mmmm ... yes and no. Mostly no. :P Take a step back and think of what you're trying to do.
You have a function that should operate on a set of OAM entries. Usually, you use function parameters for this because they're nice and encapsulated, no (or little) side effects, all that jazz. However, because you can't use function parameters in ISRs because you can never be sure when they are actually called, like I said. So you have to use something else.
In the end, interrupt service routines (ISR) are still functions like any other, and will work like any other even if you weren't using it as an ISR. It'd just be a parameter-less function like many others. Nothing special.
As you probably know (but overlooked I guess) is what global variables are: they're just variables outside the scope of functions. That's it. You must have used them before as they're everywhere in the tutorials.
CyberSlag5k wrote: |
You mean like an extern stored in some commonly shared file? I had that thought but was unsure of when exactly it would be defined. Before I use it in the one file or not. Or does that not matter, as everything will come together simultaneously at link time?
What I mean is this:
//gba.h
extern u16* myVar;
//fileOne.cpp
u16* myVar = spritePtr;
//fileTwo.cpp
myVar[0].attribute2 = 0;
The order I compile everything in has no bearing on when myVar is defined as a pointer to my sprite data, right? So I should be able to do something similar to the above? |
Something like that, yes. However, the code above won't work. Because myVar here is a halfword pointer, and halfwords don't have members variables.
Code: |
//gba.h
extern u16* myVar;
//fileOne.cpp
OAMENTRY *myVar = spritePtr; (or whatever you've called the struct for spritePtr).
//fileTwo.cpp
myVar[0].attribute2 = 0;
|
Actually, scratch that. In all probability, spritePtr already is the global variable you need. So there's no need to go further.
CyberSlag5k wrote: |
I've never really used extern much, so I'm not 100% sure of the exact mechanics of sharing things between separately compiled objects, but it's fun and interesting to be learning about it now.
|
tonc:on data ^_^. Particularly the section on 'Symbols, declarations and definitions'.
#77235 - CyberSlag5k - Wed Mar 29, 2006 6:19 pm
Er..right, myVar should have been declared as one of my OAMInstance data types.
I have no problem with using a global variable in this instance (you are indeed correct that spritePtr is global in scope), except my ISR is in an entirely different file that is compiled separately. The global variables in my main file have long since gone out of scope by the time I compile the second file. Unless I'm overlooking something?
So making the appropriate change to myVar's data type, I should be good to go? My big concern there was that for some reason the compiler would look at the myVar[0].attribute2 line before the myVar = spritePtr line, but as I think on it that should be moot at link time. That's the part I was confused on, and hope I have straight.
Thanks again, Cearn!
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...
#77237 - Cearn - Wed Mar 29, 2006 6:27 pm
CyberSlag5k wrote: |
Er..right, myVar should have been declared as one of my OAMInstance data types.
I have no problem with using a global variable in this instance (you are indeed correct that spritePtr is global in scope), except my ISR is in an entirely different file that is compiled separately. The global variables in my main file have long since gone out of scope by the time I compile the second file. Unless I'm overlooking something?
So making the appropriate change to myVar's data type, I should be good to go?
|
Think that's pretty much it. Add the right declaration to the ISR file with 'extern' and you should be set. That's exactly what 'extern' is for: make something from one file visible to another file. It basically says to the compiler "something of this name (and type!) exists somewhere else." so that the compiler doesn't have to moan about undeclared identifiers. Of course it should actually exist in the project's files -and exist only once!- otherwise the linker will complain.
#77240 - CyberSlag5k - Wed Mar 29, 2006 6:45 pm
Ah, so I can even cut the declaration in gba.h out of the loop and just keep it in main. And I can use extern to grab a couple functions from main, too. I've used extern in the past, but never quite as extensively. Very cool stuff.
Thank you very much, Cearn.
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...
#77248 - Miked0801 - Wed Mar 29, 2006 7:32 pm
One more gotcha - anytime you have a variable that is being accessed at both normal and interrupt time, it needs to be declared 'volatile'. Otherwise, the compiler will "Optimize" your code for you and things will break.
Example:
Code: |
u32 bufferIsFull;
void interruptVblankFoo()
{
// Do Normal Vblank stuff here
if(bufferIsFull)
{
bufferIsFull = FALSE;
// Copy buffer info here
}
}
void foo()
{
while(bufferIsFull);
// Buffer has now been copied via our vblank handler, go ahead and fill it with next tic's info
// Buffer fill code
bufferIsFull = TRUE;
}
|
In the above, if bufferIsFull is not declared volatile, the compiler will optimize the while loop by reading the var once and storing it in a register. Thus, when the interrupt occurs and the var is cleared, the code won't know.
#77252 - CyberSlag5k - Wed Mar 29, 2006 7:36 pm
Ah yes, I remember reading that somewhere.
Thanks Mike!
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...