cancel
Showing results for 
Search instead for 
Did you mean: 

ST25R3911B Stuck in ISR While Polling for NFC-A on Quectel EC200U (Helios SDK)

Samman
Associate II

 

I am porting the ST25R3911B NFC module library to work with the Quectel EC200U 4G module in the Helios SDK. While I have successfully achieved rfalNfcInitialize and rfalFieldOnAndStartGT, I am facing issues when running the NFC-A polling code. The execution gets stuck inside the while loop mentioned in the callback of the ISR.

Observed Behavior:

  1. The module sometimes gets stuck in the ISR loop, with the interrupt pin remaining high even when no NFC-A card is near.
  2. Occasionally, instead of getting stuck, it throws RFAL_ERR_IO.
  3. In rare cases, it does not throw any error but gets stuck as soon as an NFC-A card is brought near.
  4. ST25R_SELFTEST_TIMER and ST25R_SELFTEST pass without any errors.

Polling Code:

 

while (1)
    {
        rfalNfcWorker();
        MYLOG("Checking NFC \n");
        err = rfalFieldOff(); /* Turn the Field Off */
        if(err != RFAL_ERR_NONE){
            MYLOG("Error in rfalFieldOff: %d\n", err);
        }
        platformDelay(500);
        err = rfalNfcaPollerInitialize(); /* Initialize RFAL for NFC-A */
        if(err != RFAL_ERR_NONE){
            MYLOG("Error in rfalNfcaPollerInitialize: %d\n", err);
        }
        err = rfalFieldOnAndStartGT();    /* Turns the Field On and starts GT timer */
        if(err != RFAL_ERR_NONE){
            MYLOG("Error in rfalFieldOnAndStartGT: %d\n", err);
        }

        /*******************************************************************************/
        /* Perform NFC-A Technology detection                                          */
        err = rfalNfcaPollerTechnologyDetection(RFAL_COMPLIANCE_MODE_NFC, &sensRes); /* Poll for nearby NFC-A devices */
        if (err == RFAL_ERR_NONE)                                                    /* NFC-A type card found */
        {
            /*******************************************************************************/
            /* Perform NFC-A Collision Resolution                                          */
            err = rfalNfcaPollerFullCollisionResolution(RFAL_COMPLIANCE_MODE_NFC, MAX_DEVICE_DISCOVERY, nfcaDevList, &devCnt); /* Perform collision avoidance */
            if ((err == RFAL_ERR_NONE) && (devCnt > 0))
            {
                MYLOG("NFC-A device(s) found %d\r\n", devCnt);
                devIt = 0; /* Use the first device on the list */
                           /*******************************************************************************/
                           /* Check if desired device is in Sleep                                         */
                if (nfcaDevList[devIt].isSleep)
                {
                    err = rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_WUPA, &sensRes); /* Wake up all cards  */
                    if (err != RFAL_ERR_NONE)
                    {
                        MYLOG("Error in rfalNfcaPollerCheckPresence: %d\n", err);
                        continue;
                    }
                    err = rfalNfcaPollerSelect(nfcaDevList[devIt].nfcId1, nfcaDevList[devIt].nfcId1Len, &selRes); /* Select specific device  */
                    if (err != RFAL_ERR_NONE)
                    {
                        MYLOG("Error in rfalNfcaPollerSelect: %d\n", err);
                        continue;
                    }
                }
                /*******************************************************************************/
                /* Perform protocol specific activation                                        */
                switch (nfcaDevList[devIt].type)
                {
                case RFAL_NFCA_T1T:
                    /* No further activation needed for a T1T (RID already performed)*/
                    MYLOG("NFC-A T1T device found \r\n"); /* NFC-A T1T device found, NFCID/UID is contained in: t1tRidRes.uid */
                    /* Following communications shall be performed using:
                     *   - Non blocking: rfalStartTransceive() + rfalGetTransceiveState()
                     *   -     Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx()    */
                    break;
                case RFAL_NFCA_T2T:
                    /* No specific activation needed for a T2T */
                    MYLOG("NFC-A T2T device found \r\n"); /* NFC-A T2T device found, NFCID/UID is contained in: nfcaDev.nfcid */
                    /* Following communications shall be performed using:
                     *   - Non blocking: rfalStartTransceive() + rfalGetTransceiveState()
                     *   -     Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx()    */
                    break;
                case RFAL_NFCA_T4T:
                    MYLOG("NFC-A T4T (ISO-DEP) device found \r\n"); /* NFC-A T4T device found, NFCID/UID is contained in: nfcaDev.nfcid */
                    /* Activation should continue using rfalIsoDepPollAHandleActivation(), see exampleRfalPoller.c */
                    break;
                case RFAL_NFCA_T4T_NFCDEP:                                /* Device supports T4T and NFC-DEP */
                case RFAL_NFCA_NFCDEP:                                    /* Device supports NFC-DEP */
                    MYLOG("NFC-A P2P (NFC-DEP) device found \r\n"); /* NFC-A P2P device found, NFCID/UID is contained in: nfcaDev.nfcid */
                    /* Activation should continue using rfalNfcDepInitiatorHandleActivation(), see exampleRfalPoller.c */
                    break;
                }
                rfalNfcaPollerSleep(); /* Put device to sleep / HLTA (useless as the field will be turned off anyhow) */
            }
            else{
                MYLOG("Error in rfalNfcaPollerInitialize: %d\n", err);
            }
        }
        else{
            MYLOG("Error in rfalNfcaPollerFullCollisionResolution: %d\n", err);
            MYLOG("NFC-A device(s) found %d\r\n", devCnt);
        }
    }

 

Troubleshooting Done:

  • Verified that hardware connections are correct.
  • Checked interrupt behavior using a logic analyzer (attached capture file).
  • Ensured correct initialization of RFAL.
  • Confirmed interrupt pin remains HIGH in error cases.

Request for Help:

  • What could cause the interrupt pin to stay high indefinitely?
  • Why does polling sometimes result in RFAL_ERR_IO?
  • Are there any timing constraints I might be missing?
  • Any modifications required for running this on the EC200U (Helios SDK)?

Would appreciate any guidance on this!
Thanks in advance.


Post edited to apply proper source code formatting - please see How to insert source code for future reference.

1 ACCEPTED SOLUTION

Accepted Solutions

Hi Samman,

I have named the two states, locate them and put breakpoints. The next state after RFAL_TXRX_STATE_TX_TRANSMIT should be RFAL_TXRX_STATE_TX_WAIT_TXE. Find out why it isn't.

Ulysses

View solution in original post

8 REPLIES 8
Samman
Associate II

I have further attached some more capture files for reference:

Hi,

your session2 shows no 57h frame after IRQ went high again. Potentially your ISR not triggering or your SPI abstraction having an issue when IRQ rises during normal register access. Could be a there is a problem in your platformProtect...() macros.

 

BR, Ulysses

Hi Ulysses,

I found that I had not properly defined the platformProtect...() macros. After correctly defining them to enable and disable the IRQ, the module no longer gets stuck in the ISR loop. However, I am now facing a new issue:

When executing rfalNfcaPollerTechnologyDetection, as soon as I bring an NFC-A card near, the module gets stuck in another loop indefinitely. This eventually causes the watchdog timer to reset the EC200U module.

The function executes rfalNfcaPollerFullCollisionResolution, which contains:

ReturnCode ret;

RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartFullCollisionResolution( compMode, devLimit, nfcaDevList, devCnt ) );  
rfalRunBlocking( ret, rfalNfcaPollerGetFullCollisionResolutionStatus() );  

return ret;

It seems like the module is stuck inside rfalRunBlocking( ret, rfalNfcaPollerGetFullCollisionResolutionStatus() ); indefinitely.

I’m not sure what could be causing this behavior. Any suggestions on debugging this further would be greatly appreciated.

Hi Samman,

just again do a logic analyzer trace. 

BR, Ulysses

Hi Ulysses,

I have attached the logic analyzer trace.

Hi Samman,

I find in this trace:

  1. Noise on IRQ line - observer artifact: Please twist IRQ with GND / enable glitch filter, etc.
  2. Noise on MISO - similar to 1, this should not happen with miso_pd*=1 as the code does.
  3. I see sometimes additional data driven on MOSI - e.g. 0x570000f1 Better to drive always zeroes while reading. This is a side finding but better fix to prevent future problems
  4. At the screenshot you see part of anti-collision. Frame 93 70... being sent (C4 command). The MCU is not waiting for I_txe to happen but rather immediately advances to rfalPrepareTransceive() with C2 and D5 commands. For some reason the software seems to alternate between RFAL_TXRX_STATE_TX_PREP_TX and RFAL_TXRX_STATE_TX_TRANSMIT which should not happen in normal flow. Please use a debugger to find the issue on your MCU.

 

3911_SPI_tx_prepareTransceive.png

P.S.: I have enabled the SPI transaction framer which make it easier to navigate the traces. It makes it easy to see e.g. all FIFO writes which are starting with "0x80".

BR, Ulysses

Hi Ulysses,

I’m not sure what’s causing this issue. Could you suggest some debugging steps to identify the possible root cause? Specifically, what might cause the MCU to not wait for I_TXE to happen, and what is the expected purpose of I_TXE in this context?

Additionally, I tried using rfalNfcaPollerSingleCollisionResolution, and I noticed that in rfalGetTransceiveStatus, the gRFAL.TxRx.state ends up as RFAL_TXRX_STATE_RX_FAIL. Do you have any insights into why this might be happening?

Thanks for your help!

Hi Samman,

I have named the two states, locate them and put breakpoints. The next state after RFAL_TXRX_STATE_TX_TRANSMIT should be RFAL_TXRX_STATE_TX_WAIT_TXE. Find out why it isn't.

Ulysses