Responding in new thread since other thread is dead. http://www.keil.com/forum/21199
So, anyone else with this problem? It seems to be a general Keil issue...
Anyone else with what problem? Forgetting to use the correct keyword to tag an ISR as an ISR?
What general Keil issue? That the compiler needs to adapt to the hardware?
Lots of compilers for lots of processors have needed a special keyword to let the compiler know when it should generate prologue/epilogue for an ISR instead of for a normal function.
A number of processors have a normal "RET" instruction and a special "RETI" instruction. Or need to name specific registers to reload PC with the correct return address depending on if the processor did use the normal stack or an interrupt stack.
And an ISR often need to save extra registers compared to a normal function, since the interrupt can happen asynchronously - breaking in in the middle of other code execution.
So if you Google and finds lots of mentions of Keil, it is just because Keil works with compilers for embedded use. So the majority of users of Keil tools will create interrupt handlers.
Only OS or drive routine coders need to care about any interrupt handlers if you write code for a modern PC. So you don't see lots of threads about interrupt handlers for Visual C++.
Of course - a processor can be implemented in a way where an ISR do not need any special prologue or epilogue. In that case, there will be no need for any extra keyword to tag the ISR as different from a normal function. ARM did add extra logic in the Cortex chips to allow 100% of the code to be written in C, and without any special keyword for ISR. But that is an exception to the rule that interrupt service routines are different from normal functions.
Per,
Thank you for a (finally) answer that makes sence. All I sumbled upon so far is someone to argue with about my skills. I tried to compare the ISR vector routines and it didn't make any sence all the time. This is where I got so far: When I incluced the paths for the compiler explicitly (../ and the path to the ST's FW library _explicitly_) it seems to be working just fine (without any modifications to the given ISR - so I didn't have to put __irq instruction for the compiler infront of the ISR routines). I always had a feelling that it was some small mistake that makes a complete mess of whatever I do. But I can't use the Configuration Wizard (for) now (that given by Keil) but it's not that of a big deal, I configure the device "manually" in the source.
The confusing part was (and is), that it compiled without _any_ complaints (warnings/errors) without above two given paths to the compiler - the compiler probably took some default startup codes from some of it's predefined directories (even if I included mines in the project) and made a complete mess
Maybe you have two different versions of the ST libraries - one that makes use of a common IRQHandler (that needs to be linked in, or duplicated in your startup files) and one that requires the use of the Keil keyword instead, to allow direct call to each of your ISR. Or maybe you have a startup file that isn't compatible with the library.
Anyway - it isn't anything strange with Keil. Unless the processor have special hardware to handle an ISR identical to a normal function, then the compiler or some hidden code somewhere must take care of the issue.
Which means that directories for header files and libraries must match - and match any ISR-related code in the startup file of your project. And potentially require you to use the __irq keyword.
The compiler only complains about compile-time errors (or warnings). It does not know what is "correct" code.
The linker only complains if it runs out of memory or can't fulfill any references. It doesn't care if it links in the wrong version of a function as long as it has the correct name.
When using something like the ST libraries, you need to have a stone-hard version control. So you always know exactly which version you are using. Whenever you make changes to your source code, or to the project settings, or change any library version or compiler version, then it's time for a full retesting of your project again.
By the way - you forgot to mention your cross-posting at: my.st.com/.../DispForm.aspx
"Thank you for a (finally) answer that makes sence"
The goal was for you to wonder about how/were the processor would save the required state before starting to run your functions.
Basically the difference between having the startup file look like:
LDR PC, [PC, #-0x0FF0]
where the processor directly picks up the vector address from the VIC and jump to the correct ISR (but requiring the ISR to be compiled with the __irq keyword so it has the proper prologue/epilogue). Or being written in assembler with explicit prologue/epilogue.
Or a startup file looking like:
LDR PC, IRQ_Addr EXTERN IRQHandler IRQ_Addr DCD IRQHandler
And where there then exists a special function IRQHandler that does something like:
IRQHandler SUB LR, LR, #4 ; Update Link Register STMFD SP!, {R0-R12, LR} ; Save Workspace & LR to Stack LDR R0, =VectorAddr LDR R0, [R0] ; Read the Routine Address BLX R0 ; Branch to the IRQ Handler LDMFD SP!, {R0-R12, PC}^ ; Restore Workspace & PC from Stack
I.e. a common function that performs the same magic that __irq would have done, but shared betweeen all ISR to save space. But instead costing a bit of extra time compared to the first solution where each ISR have their own interrupt-specific prologue/epilogue. Both because of the extra jump and that too many registers are sometimes saved.
In the end, we have lot to gain by actually digging down and trying to understand the inner workings.
Naturally. But the problem started when I didn't count on a possibility that there is an "incorrect" or rather to say different code on some path included by default. I'll never stop finding this issue quite odd. I was expecting that the compiler would complain missing if some part of the source is not properly included in the project instead of finiding one of a same name on some other location.
Ok, so you read my cross-posting (actually there are more, I tried to find the solution for my problem any way I can) - I'm an old TI-based device programmer and I didn't bother to imagine what issues come up when one vendors IDE for 3rd party chip manufacturers.
The stone-hard version control part is what I could absolutely agree with after all.
Thanks for your elaborate.
Yes, I saw all that in the startup code(s) sources, but when I started RT debugging my project, there was something completely different on the debugger screen. It was clear that it's not linking all the code there is, but I couldn't imagine why. I was also having random configuration issues with the Keil Wizard (probably also due to the compiler was "finding" another startup code on some other location because of inproper path setup)... So I jumped on the problem "from the top" - why should I bother with assembler when the FW is provided....even a generic ISR is sourcef... and that part basically started working, except that the IRQ handling was still inproper until I managed to make it compile the correct startup and IRQ handlers.
Don'know about other products (moving on to some NXP ARM7 MCB too these days), but about Keil - some hint to "mind the include paths!" would help a newbie Keil design kit user.
Well, the linker is happy with any implementation it finds that happens to have the correct name. But that doesn't mean that the linker gets a function that is written to be compatible with other code that happens to make references to this function name.
The most common issues is that the linker do get good code, but that the user have included header files for another version of the code. And these header files may have more or less number of fields in a struct. So the struct you thought you allocated had wrong size compared to the size that other code assumed. And the offset of individual fields were different between the code you compiled, and the code you linked.
Extremely strange things can happen when the header files aren't for same version of code that is already compiled and is just brought in during linking.
So lots of people makes copies of header files and libraries and duplicate in their project tree, to really make sure that the library with related files are locked down to the project. This also makes sure that someone copying the project directory tree will not be standing there without a library and without being able to guess what library (and version) that is required.
"but about Keil - some hint to "mind the include paths!" would help a newbie Keil design kit user."
Yes of course. But if you do try Google, you will find that this world is full of developers who have run full-speed into the wall because the compiler or linker have picked up the wrong version of files. And that it happens with almost any compiler and for almost any build platform or target platform.
I bet almost all visitors on this forum have once or twice been burned by similar issues. With Keil or with other tools. So the only really good solution would probably that every GUI in existence should regularly pop up such a warning - and repeat it until the developer answers "Yes: have been burned. Now will do my outmost to not suffer this one again". And even then, the GUI would need to maybe once/year bring back that warning again :D