-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Faster isr #2408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Faster isr #2408
Conversation
You probably wanted to submit this against the ide-1.5.x b ranch, nog master? |
yes, but the file is the same in both branches. On Mon, Nov 3, 2014 at 9:07 AM, Matthijs Kooijman [email protected]
Visit my github for awesome Arduino code @ https://github.com/xxxajk |
in short, it is a fix for BOTH 1.0 and 1.5 |
Hi @xxxajk I can now see your commit (but only because @matthijskooijman has commented after it). BTW the fix is here: and is very good IMHO, I'm for merging it. |
Looking good. You could change the "nothings" to different functions, make them weak and an aliasof "nothing". Then the user could overwrite this function directly. Not sure if it makes sense. example: https://github.com/NicoHood/PinChangeInterrupt/blob/dev/PinChangeInterrupt.cpp#L34 |
weak aliasing would be very awesome. I constantly run into a brick wall when wanting to use a custom ISR v.s. what is provided. |
Also, FWIW I think all the arduino-provided ISRs should be weak aliases, not just pin interrupts. This would allow someone to do advanced programming, especially important when writing a shield library. |
Not sure if its possible to implement an ISR itself weak. But if it is, why not do it? There is nothing to lose i think. That is a great idea! (thanks, i will add this to my PCINT library as well if possible). |
Not sure what the point of this would be. The "nothing" functions are only set in the array while the corresponding interrupt is disabled, so it would never be called. Also, if you want your custom function to be called when an interrupt happens, you should just use Declaring ISRs as weak is probably a good idea, but unrelated to this PR. If you want to see this happen, please prepare a pullrequest and test if this works as expected (or is there already a PR for this?) |
Nevermind what I wrote last time. The PR looks good to me, it will just not work for every MCU. (like the U2 Series which has tons of normal pin interrupts) |
@NicoHood, there is a way to make the array flexible without resorting to macros. Simply let the array elements initialize themselves regardless of how many are present, as opposed to generating code to explicitly initialize each element. These changes slot into the changes proposed by @xxxajk This requires changing Winterrupts.c to WInterrupts.cpp static void nothing(void) {}
struct cbHandler{
cbHandler() : ptr(nothing) {}
void operator =( const voidFuncPtr in ) volatile { ptr = in; }
void operator ()() volatile { ptr(); }
voidFuncPtr ptr;
};
static volatile cbHandler intFunc[EXTERNAL_NUM_INTERRUPTS] = {}; //Use default initialization. Here is a comparison: xxxajk/Arduino-1@faster-isr...Chris--A:patch-1 |
That looks complicated but sounds good if it works. Changing to cpp should be tested of course. |
@Chris--A, I think that if you add a |
(Note that constexpr needs C++11 support, which currently needs an hourly build) |
@NicoHood #ifdef __cplusplus
extern "C"{
#endif
//...
#ifdef __cplusplus
} // extern "C"
#endif @matthijskooijman There is something different happening which I'll try investigate, however I've also noticed only the function pointer in the I've also noticed that @xxxajk's original code does not currently work with an Uno. |
@Chris--A, I actually believe constexpr is needed to allow compile-time initialization of the array. I previousrly wrote a piece on this thing that I think might be appropriate here: http://www.stderr.nl/Blog/Software/Cpp/ConstantInitialization.html I wonder if another approach might be easier and more readable here, though:
It's easier to read than fiddling with a struct, but won't work with any One midway might be a simpler struct:
And then just access this as I just noticed that all this code is in a .c file, meaning we could use
(untested) |
@matthijskooijman The first solution is so simple that I never ever would have thought of this :D |
Unfortunately The usage code outputs the same though. From your article:
This is not quite correct, as only the temporary anonymous typedef void (*voidFuncPtr)(void);
void nothing(){}
class Foo {
public:
constexpr Foo() : ptr(nothing) { }
volatile voidFuncPtr ptr;
};
Foo a[2];
void setup() {
GPIOR0 = (uint16_t) a[0].ptr;
}
void loop() {} Without The struct was designed to not require 'fiddling' with the code. However the designated initializer approach you used is nice and simple and the file can stay a .c file. As a C++ programmer I have not used these, so thanks for the new insight, and yeah, its not supported. From what I've read and assumed, constructors are C++'s way of dealing with abstracted initialization. |
I'm looking at this one. What is the maximum for NUM_EXTERNAL_INTERRUPT? It looks like 8 is the max for the Arduino boards, but maybe some 3rd party boards may define more external int pins? static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
#if EXTERNAL_NUM_INTERRUPTS > 8
#warning There are more than 8 external interrupts. Some callbacks may not be initialized.
#endif
#if EXTERNAL_NUM_INTERRUPTS > 7
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 6
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 5
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 4
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 3
nothing,
#endif
nothing,
nothing,
nothing
}; As said by @matthijskooijman even if the array is not initialized it should not be a problem when the |
The Uno only has 2 INTs. So your paste is wrong for the uno and I also would add the possibility for a single interrupt as well (maybe some attinys only have a single INT). The 16u2 has 8 Interrupts: Also some boards might not have any interrupts (maybe some attinys) where the array would just be empty. It doesnt hurt to add a definition here, so in any case this doesnt cause a problem. Where is After your warning you can still add a single static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
#if EXTERNAL_NUM_INTERRUPTS > 8
#warning There are more than 8 external interrupts. Some callbacks may not be initialized.
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 7
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 6
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 5
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 4
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 3
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 2
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 1
nothing,
#endif
#if EXTERNAL_NUM_INTERRUPTS > 0
nothing,
#endif
}; |
Right, it's defined here: https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_private.h#L55 @NicoHood |
Oh. Maybe we should move this to the variants file with this patch? I think I also missed this in the 16u2 USB-Core fix. Can you please add the 16u2 definitions here as well? As said, the variants file seems to be a better place. And for compatibility you can add a |
The number of external interrupts is a CPU-bounded value so, thinking again at this, it seems more obvious to keep things as they are.
Ok |
Yeah that sounds okay to me then. Will you open a new PR or merge it directly? Please cc us the commits. Note: |
Even if the pin is not broken out, you can still use the pin for a On Mon, Aug 31, 2015 at 9:56 AM, Nico [email protected] wrote:
Visit my github for awesome Arduino code @ https://github.com/xxxajk |
Why didnt you add #if EXTERNAL_NUM_INTERRUPTS > 0
nothing,
#endif This can now cause problems if the MCU doesnt have an external interrupt. Attiny 13 seems to have no pin interrupts. @xxxajk Sounds like a good idea, thanks. I'll test it. |
Oops... cut & paste errors sorry. Fixed here: 8720384 |
I think you can add an error if the number is >8. https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/WInterrupts.c#L70 Another thing I want to discuss here (before opening another ticket):What about a function disable/enableInterrupt? Sometimes you want to turn off an interrupt, similar as detaching. But you do not want to save the MODE and the userfunction all the time, so you need a function without this parameter. This also speeds up the deactivation a bit. Simply the functions would not set the userfunction again/remove it and uses the old mode. I am not sure if the mode is still saved after you disable/enable the interrupt. Would this be an idea? I need this feature for my IRLremote to temporary turn it off, cause the interrupts ma cause errors on some code parts. |
Before:
After:
The checking if the target ISR is set is removed
and traded in for setting the initial array values and an empty function.
This gives you a speed gain when an ISR comes in, without increasing the size of the binary.