2026-03-17 3:58 AM
Hello,
I am using the ST25R3918 in NFC-F (FeliCa) Card Emulation (CE) mode, controlled by an MCU via RFAL (based on STEVAL-25R3916B_V2.1.0).
[Issue Description]
The system works correctly under normal conditions: the ST25R3918 receives commands like "Write Without Encryption" or "Read Without Encryption" from a reader and sends back the appropriate responses.
However, if the reader is moved away from the ST25R3918 (resulting in RF field loss) during the communication process, the MCU firmware falls into an infinite loop.
[Analysis Details]
The loop occurs within the do-while block of demoTransceiveBlocking() in card_emulation.c. The call stack is as follows: rfalNfcWorker() -> rfalWorker() -> rfalRunTransceiveWorker() -> rfalTransceiveRx()
Inside rfalTransceiveRx(), the state gRFAL.TxRx.state remains stuck at RFAL_TXRX_STATE_RX_WAIT_RXS. The function st25r3916GetInterrupt() is called with the following mask: (ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_NRE | ST25R3916_IRQ_MASK_EOF)
Since no interrupts are triggered, it returns ST25R3916_IRQ_MASK_NONE, causing the rfalTransceiveRx() to break and re-enter the same state in the next cycle, preventing any progress.
I expected the ST25R3916_IRQ_MASK_NRE (No Response Error) to trigger a timeout, but it never occurs when the field is lost.
[Questions]
Is it expected behavior that the NRE interrupt is not triggered when the RF field is lost in CE mode?
What is the recommended way to handle this "field loss during transceive" scenario in RFAL to avoid an infinite loop? Should I explicitly monitor the External Field Event (e.g., ST25R3916_IRQ_MASK_EXT_COL or similar) to break the loop?
Any advice or insights would be greatly appreciated.
Thank you.
Solved! Go to Solution.
2026-03-18 1:26 AM
Hi,
Thank you, indeed your observation and analysis seems consistent.
Below a few aspects to consider:
Hope it helps
Kind regards
GP
2026-03-17 7:24 AM - edited 2026-03-17 7:25 AM
Hi,
Thank you for your detailed analysis.
In general could you better detail your test setup and procedure.
To you questions:
Kind regards
GP
2026-03-17 9:24 PM
Hi,
Thank you for your prompt and clear explanation regarding the NRE behavior in CE mode.
To answer your questions about my setup and the issue:
1. Environment & Software
Hardware: Custom MCU board connected to ST25R3918 via SPI.
Source Code: Based on STEVAL-25R3916B_V2.1.0. Specifically, I am using the RFAL stack and card_emulation.c from the ST25R3916Demo project.
Modifications:
rfal_platform.h: Adapted to my MCU (STM32L4 series equivalent HAL).
st25r3916.c: Commented out st25r3916CheckChipID( NULL ) in the initialize function.
card_emulation.c: Only modified the IDm value.
Other parts of the RFAL stack remain unchanged.
2. Procedure to Reproduce
The communication sequence is as follows (repeated every 100ms):
Reader sends "Write Without Encryption".
ST25R3918 sends response.
Reader sends "Read Without Encryption".
ST25R3918 sends response.
The infinite loop occurs randomly (approx. 1 out of 100 trials) when the reader is removed during this cycle. It is not 100% reproducible but happens frequently during stress tests.
3. SPI Trace Analysis
I managed to capture a brief SPI trace right when the issue occurs.
(S: MOSI from MCU to ST25R3918 / R: MISO from ST25R3918 to MCU)
The last recorded transactions were:
S: 0x5A (Read Interrupt Status)
R: 0x00, 0x08, 0x00, 0x00 (Result: EOF interrupt detected?)
S: 0xC4 (Close RX?)
S: 0x5A (Read Interrupt Status again)
R: 0x08, 0x00, 0x00, 0x00
After step 5, no further SPI activity occurs and no IRQ is triggered, even though the MCU remains in the do-while loop in demoTransceiveBlocking().
It seems the EOF interrupt (0x08) was actually reported by the chip, but for some reason, the RFAL state machine (RFAL_TXRX_STATE_RX_WAIT_RXS) does not seem to consume it or transition to an error state.
Could you please advise why the RFAL might get stuck even when the EOF bit is present in the interrupt status?
2026-03-17 10:19 PM
Apologies, I forgot to include the link to the software package I am using. It is STSW-ST25R018: https://www.st.com/en/embedded-software/stsw-st25r018.html
2026-03-17 11:59 PM
Hi,
Thank you for the clarification of the setup and sequence.
From the SPI data you collected it seems that the EOF IRQ is occurring immediately before the transmission (C4) of the card response.
In order to avoid triggering the transmission of the card response in absence of the Reader RF field, the operation before is exactly the check for RF Carrier - rfalIsExtFieldOn().
In case the transmit command is issued and the RF Carrier is lost within the SPI timing operation it may happen that the response is actually not transmitted. Nevertheless the EOF shall be processed in the next state (RFAL_TXRX_STATE_TX_WAIT_TXE) and error LINK_LOSS reported.
Questions:
Kind regards
GP
2026-03-18 12:52 AM
Thank you for your insightful feedback. I have conducted further investigations based on your comments.
1. Answers to your questions:
SPI Speed: 800 kHz.
RFAL Worker frequency: It is called within a main loop as frequently as possible (polling).
SPI Trace: Unfortunately, capturing a complete trace with all signals (timings/IRQ) is difficult in my current environment, so I have focused on code-level debugging.
2. New Findings on the Potential Root Cause:
Based on my analysis, I suspect the following scenario might be causing the infinite loop. When the issue occurs, I observed a specific interrupt state in rfal_rfst25r3916.c within rfalTransceiveTx() under the RFAL_TXRX_STATE_TX_WAIT_TXE case:
When calling:
irqs = st25r3916GetInterrupt( (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_EOF) );
The value of irqs returns 0x0808. This indicates that both ST25R3916_IRQ_MASK_TXE and ST25R3916_IRQ_MASK_EOF are set simultaneously.
In the current RFAL implementation:
if( (irqs & ST25R3916_IRQ_MASK_TXE) != 0U )
{
gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_DONE;
}
Since the TXE condition is evaluated first and transitions the state to TX_DONE, the EOF (field loss) flag is effectively ignored. Consequently, the state machine proceeds to RFAL_TXRX_STATE_RX_WAIT_RXS in rfalTransceiveRx(). However, since the reader has already been removed, no further interrupts occur, leading to the infinite loop in demoTransceiveBlocking().
3. Proposed Solution:
To prevent this, I am considering the following modifications in RFAL_TXRX_STATE_TX_WAIT_TXE:
Check for ST25R3916_IRQ_MASK_EOF before TXE to catch the field loss immediately and return an error.
Alternatively, implementing a timeout mechanism within the do-while loop in the application layer.
2026-03-18 1:26 AM
Hi,
Thank you, indeed your observation and analysis seems consistent.
Below a few aspects to consider:
Hope it helps
Kind regards
GP
2026-03-18 2:14 AM
Hi,
Thank you very much for the clear and detailed explanation.
Your points regarding the prioritization of TXE due to AP2P (ACM mode) and the possibility of enabling the sanity timer (gRFAL.tmr.txRx) even in CE mode are extremely helpful.
I will proceed with the following actions based on your recommendations:
Increase the SPI speed to improve response times and reduce the likelihood of race conditions.
Implement a timeout/sanity timer within the RFAL or application layer, as our system does not require indefinite waiting in CE mode.
Adjust the IRQ handling logic in rfalTransceiveTx to better suit our specific requirements, since AP2P is not used in our application.
I truly appreciate your support and the deep dive into the RFAL behavior.
Best regards,