-
Notifications
You must be signed in to change notification settings - Fork 13.3k
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
Fixes and implementation to expose attachInterruptArg in Arduino.h #6003
Conversation
dok-net
commented
Apr 20, 2019
- attachInterrupt and detachInterrupt don't require ICACHE_RAM_ATTR.
- fix incorrect handling of non-"functional" interrupt handlers.
- complete and expose attachInterruptArg().
@earlephilhower In order to go ahead with an efficient small footprint EspSoftwareSerial, I've ported parts of the attachInterruptArg implementation from ESP32 Arduino. Keeping double tables in libraries using interrupts to account for the until now missing argument to ISRs, whereas the interrupt attachment code already keeps such tables, is now obviated. Also, I found that the use of ICACHE_RAM_ATTR on attachInterrupt and detachInterrupt is strictly redundant, consuming the constrained resource while the part of attaching/detaching interrupts has no real-time requirements AFAIK. Once this PR is merged, I have the matching EspSoftwareSerial PR right at hand :-) |
@dok-net : Been busy with other stuff, I just noticed this thread. The difference you noticed in implementation happened because of the sequence in patches on both platforms. Unless I missed some specific items/issues I expect you can get ESP8266 and ESP32 code compatibility without this update |
To split it up: |
Yes, (most) use of attach/detach will be outside the ISR. However I do have a homeautomation application where I change attach to/from CHANGE/RISE and detach in ISR. For me it is "just another" local patch to add.
Up to @d-a-v whether to have nice-to-haves in the core
That is scheduled interrupt functionality. There are no (t yet) scheduled functions in ESP32. |
Nothing against that myself, especially if it goes towards esp8266/esp32 unofficial arduino api compatibility.
About the ability to attach/detach interrupts from an ISR, there is in fact a solution. It is quite fair, as you say, to do that in some case. @earlephilhower mentionned it too, few days ago. What is feasible is the following:
(I think this would go into Where relevant, change
Now when a projects needs that, add in
and in the sketch:
(this is not yatmo - Yet Another Tools Menu Option ;) |
@@ -8,7 +8,7 @@ typedef void (*voidFuncPtr)(void); | |||
typedef void (*voidFuncPtrArg)(void*); | |||
|
|||
// Helper functions for Functional interrupt routines | |||
extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp , int mode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading several times, I don't understand why it is needed to have this bool functional
.
It is always checked along with the not-nullptr
arg. Why is arg
not sufficient ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do a detailed check (maybe thursday. otherwise friday).
I needed it in ESP32 to distinguish the use of attachinterruptArg from user exposed and usage for functional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-a-v The bool functional
prevents undefined behavior of type-casting void* arg
to ArgStructure*
and dereferencing in all those cases that the whole exercise of exposing
void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode)
is done for: whenever it's not an ArgStructure*
, not null either, but for instance some this
pointer or whatever else fits into void*
(32bit integers).
I've revisited the code and I am quite sure it's needed where it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: I've tested using microsecond resolution instead of CPU cycles for the Software Serial bit timing. The ESP8266 shows no difference, but on the ESP32, at high bit rate (57600cps), the error rate increases measurably.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the reduction of the complexity of the generated code, I always try to cpu cycle (if measured durations are less than 26 seconds (esp8266@160MHz) or if overflow is managed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But here (SW serial) it impacts basic usefulness, each worsening in error rate renders it useless in more cases.
My point of view is that unconditionally requiring C++ functional objects in the attachInterruptArg interface through an API that looks like plain C attracts confusion. The compiler can't catch any of it. I have to admit, that I am not entirely happy with the whole construct between FunctionalInterrupt and core_esp8266_wiring_digital, exemplified by the need to copy&paste type definitions
//duplicate from functionalInterrupt.h keep in sync
typedef struct InterruptInfo
because the relationship is bit forced as it is right now.
But anyway, in ESP32 Arduino, it's just the same, so future patches just might take advantage or a more in similarity.
if (handler->functional) | ||
{ | ||
ArgStructure* localArg = (ArgStructure*)handler->arg; | ||
if (localArg && localArg->interruptInfo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this spot, discerning only null from non-null causes undefined behavior in all non-"functional" uses due to accessing arg->interruptInfo.
Therefore, the check for functional == true is correct and necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I missed that, thanks for the explanation
Why is it closed ? |
Entirely not on purpose!!! Must be a side effect of me trying to avoid ugly merge history by local rebase followed by force push to my git repo. Dammit :-) |
Re-pushed (ugly merge commits, but opinions on merge vs. rebase differ wildly anyhow). |
Please observe #6048 |