Shared irq line, guard shared IRQ line against hangs/timeouts - #11
Merged
Conversation
cparata
approved these changes
Aug 27, 2026
cparata
left a comment
Contributor
There was a problem hiding this comment.
Hello @bartkodden ,
thanks for your PR. Actually, this library was never tested with 2 instances of the NFC reader device. Unfortunately, I don't have the hardware setup to test this use case on my side. Because the patch is backward compatible, I don't have any particular concern to integrate the PR.
Best Regards,
Carlo
Contributor
|
Hi @bartkodden , |
Upstream gates the IRQ register read on the IRQ pin level, which assumes the pin belongs to exactly one ST25R3916. When several ICs share one IRQ input -- or the line is otherwise not trustworthy as per-IC state (wired-AND, diode bus, a level shifter that holds it) -- the level describes the bus, not the selected IC, and the guard fails both ways: held de-asserted nothing is ever collected and every RFAL wait times out; held asserted by a neighbour the while() cannot terminate, since this IC has nothing left to clear. Define ST25R3916_SHARED_IRQ_LINE to read this IC's registers unconditionally once per call and bound the repeat count (ST25R3916_ISR_MAX_REG_READS, default 8). Undefined, the upstream loop is compiled verbatim -- it stays live code so it cannot bit-rot, and reverting is undefining one macro. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The wait loop only reads st25r3916interrupt.status and relies on a pin-edge ISR to fill it in concurrently. On a shared or untrustworthy IRQ line that edge is not dependable, so .status stays empty and the loop runs to its timeout on every transceive. Define ST25R3916_SHARED_IRQ_LINE to call st25r3916Isr() every ST25R3916_IRQ_POLL_INTERVAL_US (default 200) while waiting, fetching this IC's own registers over SPI so progress does not depend on the pin. Undefined, the upstream loop is compiled verbatim. Timing uses micros() from Arduino.h -- already relied on by this file for digitalRead() -- so the change adds no platform-specific symbol. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…when polling, since only the status collection is needed and this avoids invoking the IRQ callback from the timed wait loop.
fpistm
force-pushed
the
shared-irq-line
branch
from
August 31, 2026 09:10
ca4fc75 to
cb98f36
Compare
Member
|
I've applied astyle on each commit. |
Contributor
Thanks Frederic! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add an opt-in workaround for configurations where the ST25R3916 IRQ GPIO level cannot be treated as per-device state (for example, two readers sharing a host IRQ input, or additional IRQ-path circuitry).
When
ST25R3916_SHARED_IRQ_LINEis enabled, the driver polls this chip’s IRQ status registers in a bounded way so RFAL wait paths do not depend solely on the IRQ pin level.When the flag is not defined, the upstream code path and behavior are unchanged.
bugs/features fixed
Bug 1: Avoid a potential infinite loop in
st25r3916CheckForReceivedInterrupts()if the host IRQ line is held HIGH while the selected ST25R3916 has no more IRQ flags to clear (bounded reads underST25R3916_SHARED_IRQ_LINE).Bug 2: Avoid
st25r3916WaitForInterruptsTimed()expiring in poll/shared-IRQ configurations by periodically polling the IRQ status registers to refreshst25r3916interrupt.status.motivation
In my project I am integrating multiple ST25R3916 devices on a shared SPI bus (separate CS) with an IRQ signal that is effectively shared/unreliable (per-device IRQ state is not guaranteed at the host pin). During bring-up the IRQ path included additional circuitry (level shifting + diode/pull network), which made the GPIO level unsuitable as a strict indicator of the currently selected device’s IRQ state.
My project is built for ESP32 and has an additional layer between my project code and the ST25R3916 repo
On the upstream path, interrupt collection is guarded by:
while (digitalRead(int_pin) == HIGH) { ... }This assumes the IRQ pin level directly represents the selected ST25R3916. When that assumption does not hold, two problematic cases can occur:
If the GPIO reads LOW while the selected ST25R3916 has pending IRQ flags, the loop body never runs and
st25r3916interrupt.statusmay not be updated, so RFAL wait paths can time out.If the GPIO is held HIGH by another device/circuit, the unbounded loop may not terminate because reading this chip’s IRQ registers cannot clear the external assertion.
With
ST25R3916_SHARED_IRQ_LINEdefined, this PR makes interrupt status collection depend on the selected chip rather than solely on the IRQ pin level:st25r3916CheckForReceivedInterrupts()reads this chip’s IRQ registers at least once per call and bounds repeated reads viaST25R3916_ISR_MAX_REG_READS.st25r3916WaitForInterruptsTimed()periodically callsst25r3916CheckForReceivedInterrupts()(notst25r3916Isr()) so the wait loop can make progress even when no GPIO ISR is updating.status, without dispatching the user callback from the timed wait loop.Validation
Built and smoke-tested on my hardware setup (2× ST25R3916, SPI @ 1 MHz) with
ST25R3916_SHARED_IRQ_LINEenabled. This improved stability in my usage (I did not observe hangs during my tests).Built/tested with
ST25R3916_SHARED_IRQ_LINEdisabled: upstream behavior is preserved (no functional change expected).Remark
This is my first pr ever, this project has been made possible by ai. I have a working prototype right now. If my solution for this issue is not how it should be handled i would be happy to change my approach.