Hello,
has anybody expierienced with the Realview Compiler (ARM) and C++ interrupt programming? How can I call an non static method as a interrupt handler? I use ATMEL AT91SAM7 controllers. It's not easy if one has just started to learn C++ at all ... (the reviews I found haven't helped me much).
Interrupt programming really has nothing to do with C++ - actually, C++ is not a factor in it whatsoever. use standard C or assembly for that, and refer to your compiler's data sheet to see how. by the way, I hope you are aware of the intricacies involved in using C++, especially on microcontrollers...?
Make a static ISR and call the non-static method from within that ISR. That's why I don't like C++: a whole new level of abstraction, a whole new lot of unnecessary choices, and plenty of new ways to shoot yourself in the foot. But I guess it has its uses...
How can I call an non static method as a interrupt handler?
Do you have to use a method as an interrupt handler? Won't a plain function do?
PROGRAMMING POINTERS by Dan Saks:
Better even at the lowest levels
"Why might you prefer to write low-level code in C++ rather than in C? You've got much to gain and little or nothing to lose."
newsletter.embedded.com/.../eBOEV0GgTyU0FrY0G2xS0EC
Andy, I read the article. My personal opinion is that the risks that are introduced into software by using C++ are far greater than the mild benefits of stripped embedded C++. Yes, sometimes I'm DIEING to able to inherit, but for me, in comes down to the following: writing correct C++ code is far more challenging that writing C code. performance might be more of less the same (given a good compiler and some size trade-offs) but still - I would not use it for really low-level software.
Why might you prefer to write low-level code in C++ rather than in C? You've got much to gain and little or nothing to lose.
Thank you for the link, but I'll stick to C :-) There is actually a lot to loose: C++ is much harder to learn and use. And the only real-world example in the article is not convincing at all...
No extra trouble to get C++ to work. It is a quite straight-forward language as long as you don't spend too much time digging yourself down with multiple base classes with or without virtual base classes.
But operator-overriden C++ can result in a few nice trivial lines of code that actually consuming huge amounts of CPU time because the operator overloading isn't obvious.
Because of this, great care should be used in interrupt service routines. They are intended to be fast, to let the next interrupt also be serviced quickly.
The processor interrupt can never enter an object method since the processor only knows how to call a specific address. But an ISR can make use of a global variable to call a non-static method.
But if you have a single global object that your ISR is calling one method in, then you can think about having a single function and a number of variables directly inside a namespace. It will also encapsulate the symbols and except for no overloading will be quite similar to a singleton object. And that encapsulated function can be specified as an ISR directly, instead of requiring an extra function call.
Per, A very informative post. I only want to add that some implicit, innocent mistakes can have, as you stated, a large impact on performance/correctness: * implicit type conversions can lead to unexpected program behavior. if somebody adds a type conversion/constructor to a class without you knowing about it, it might introduce program stability issues/invalidate correctness. * using arrays polymorphically will destroy and program. * ...
But isn't that also true of ANSI 'C'...?
The following is an example of what I use on an the STR711Z2 (STmicro ARM 7)
As Per states you will need to call 1 C or Assembly language function that saves your context properly (i.e. ceic_irq_function). If ALL of your interrupt routines are in C++, you could call the ceic_IRQhandler as your single IRQ_HANDLER. I am sure this could be easily adapted to your ARM processor.
As for myself, I have found C++ to allow me to make my code smaller (yes, I said smaller) as well as more likely to be correct algorithmically. ( I have certainly written code that does not work in both C and C++ and still can, but I find it easier to do correctly in C++ than C)
I am not trying to start a war here. If you prefer C that's find and you should stick with C. No reason you can't provide the same functionality, just in a different way. I just sometimes find people claim C++ has "issues" in ways that it really does not. And sometimes these so called issues are actually strengths of the language.
#include "callback.h" // Callback definitions #include "eic.h" // ux types and STR eic library defs // that is all the includes class devCeic { public: devCeic() {}; static void setHandler(IRQChannel_TypeDef channel, CallbackBase<void> *callback, u16 prio = 1, FunctionalState NewState = ENABLE); static void setConfig(IRQChannel_TypeDef channel, FunctionalState NewState); static void setPriority(IRQChannel_TypeDef channel, u8 prio) { EIC_IRQChannelPriorityConfig(channel, prio); }; static void setIRV(void *irv) { EIC->IVR = (u32) irv; }; // static CallbackBase<void>* operator[] (u16 channel) { return vectors[channel]; }; friend void ceic_IRQhandler(void) __irq; private: static CallbackBase<void>* vectors[32]; }; extern devCeic CEIC;
void ceic_IRQhandler(void) __irq { u16 vector; vector = EIC->CICR; //determine vector // Enable and save IRQ nesting here if desired if (devCeic::vectors[vector]) (*devCeic::vectors[vector])(); // This is a none static member function call // i.e. call to a member function of a specific instance of an object // Interrupt routine has no knowledge of the object // other than the member function to be called takes no parameters // Called member function has full knowledge of the instance of the object, because it is the object EIC->IPR = 1 << vector; // acknowledge interrupt }
The following link gives one definition for the Generic Callback class. It is worth the time to go through it and understand it (complexity rating of 5 out of 10). Understanding means you can define templates that handle callbacks that return a value of a generic type and handles anywhere from 0 to at least 2 parameters.
www.gotw.ca/.../083.htm
"implicit type conversions can lead to unexpected program behavior."
This is basically the operator overloading I'm talking about. Elegance dictates that overloading should be invisible. When talking about performance or interrupts, invisible "extras" can be dangerous. This isn't so much a problem with the language. I think it is more a question of experience to not always do it the academic way and strive for maximum elegance. Sometimes it helps to make operations visible. In an performance-oriented world, you do not want to have to single-step in the debugger to be able to understand the code.
"using arrays polymorphically will destroy and program."
Some object-oriented languages solves this elegantly by not allowing you to create arrays of objects - just arrays of primitive data types or arrays of pointers. A very academic solution that may result in millions of memory allocations. And since they don't like pointers, the call them references and let the garbage collector solve the problem. It looks elegant, but consumes many, many extra MW of processing power. The people who complains about TVs left in stand-by should probably take a closer look at the power consumption of todays PCs, and what percentage of the power that is lost because of programming languages or how the languages are used. I have programs that can consume more processor instructions/second when I move the mouse cursor over their icon in the menu bar than my old dual-processor P90 could peak.
A C++ program with heavy use of operator overloading etc can be such a wasteful program. But a C++ program may on the other hand be just as lean as a C program. I think that is one of the advantages of C++. Since it was originally designed to be a direct superset of C, the developer may decide how to use it. In a PC environment, you may go for smart pointers to get similar behaviour as the garbage collect of Java. In a tiny embedded environment, you may write C code with very limited objectification.
But the rule is the same as for any other language: You are expected to know your tools. And you are epxected to know _why_ a specific code construct works. It is the "magic black boxes" that will hurt.
I suspect that the 'C' programmers that make such claims are very much like the assembler programmers who assume that all 'C' code is inherently bloatware.
And I also suspect that the same 'C' programmers that so vehemently defend 'C' against such ill-founded acusations from ill-informed (or just antagonistic?) assembler programmers are the same ones that make the similar accusations against C++...
But I am just a 'C' programmer, so I can't see it from the C++ programmer's viewpoint...
Not necessarily. It just so happens that for a many (most?) embedded applications C is the best tool for the job.
I have worked with C++ in the past. I have made up my mind based on my experience and quite some reading.
Mike and Tamir, you guys should stay with what you are comfortable with. There is nothing more detrimental to a project than someone coding in C++ that would really rather code in C.
I find C++ to be an excellent choice for embedded applications. This would be based on experience. I would be interested to know what bad experiences any of you have had with C++. Maybe you should consider these as learning experiences. Identify the mistakes that were made and don't do them again. I am sure this is how you became "good" C programmers. I am also 100% certain it was not the C++ language itself that caused your issues and that using the C language in itself would not have solved them.
View all questions in Keil forum