Skip to main content
Associate
September 16, 2026
Question

NFC-A Collision Resolution returns Timeout error code RFAL_ERR_TIMEOUT

  • September 16, 2026
  • 5 replies
  • 56 views

Hi,

We have a project with ST25R3916B to read a NFC-B T4T card. This driver works fine.

In the same state machine I am adding support for reading a NFC-A card. The `rfalNfcGetActiveDevice` correctly returns RFAL_NFC_LISTEN_TYPE_NFCA and rfalNfcaPollerCheckPresence returns RFAL_ERR_NONE, however rfalNfcaPollerFullCollisionResolution() function is returning a RFAL_ERR_TIMEOUT 

The Type 4B reader loop has the equivalent functions calls as the Type 4A reader and works fine, but Type 4A is having the abovementioned timeout issues with collision resolution.

I am having some issues with attaching a .c file, so I will post the whole function in a comment after the question is published

5 replies

sdesai32Author
Associate
September 16, 2026

Leave a reply...
 

 switch (self.state) {
    case HAL_NFC_STATE_START_DISCOVERY:
      // NFC is off, reinitialize Discovery
      if (rfalNfcGetState() == RFAL_NFC_STATE_IDLE) {
        err = rfalNfcDiscover(&self.discovery_params);
      }
      // NFC is active, restart Discovery
      else {
        err = rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
      }
      if (err == RFAL_ERR_NONE) {
        self.state = HAL_NFC_STATE_DISCOVERY;
      }
      break;
    case HAL_NFC_STATE_DISCOVERY:
      if (rfalNfcIsDevActivated(rfalNfcGetState())) {
        rfalNfcGetActiveDevice(&nfc_device);
        DBGTRACE_LOG1("DDEV", nfc_device->type);
        switch (nfc_device->type) {
          case RFAL_NFC_LISTEN_TYPE_NFCB:
            rfalIsoDepDeselect();
            self.state = HAL_NFC_STATE_POLLING;
            break;
          case RFAL_NFC_LISTEN_TYPE_NFCA:
            err = rfalIsoDepDeselect();
            DBGTRACE_LOG1("DSEL", err);
            self.state = HAL_NFC_STATE_POLLING;
            break;
          default:
            break;
        }
      }
      break;

    case HAL_NFC_STATE_CONNECTED:
      break;

    case HAL_NFC_STATE_POLLING:
      if (rfalNfcIsDevActivated(rfalNfcGetState())) {
        rfalNfcGetActiveDevice(&nfc_device);
        DBGTRACE_LOG1("PDEV", nfc_device->type);
        if (nfc_device->type == RFAL_NFC_LISTEN_TYPE_NFCB) {
          if (rfalNfcbIsIsoDepSupported(&nfc_device->dev.nfcb)) {
            err = rfalNfcbPollerCheckPresence(RFAL_NFCB_SENS_CMD_ALLB_REQ,
                                              RFAL_NFCB_SLOT_NUM_1, &sensbRes,
                                              &sensbResLen);
            if (err == RFAL_ERR_NONE) {
              if (memcmp(sensbRes.nfcid0, nfc_device->dev.nfcb.sensbRes.nfcid0,
                         RFAL_NFCB_NFCID0_LEN) == 0) {
                err = rfalIsoDepPollBHandleActivation(
                    self.discovery_params.isoDepFS, RFAL_ISODEP_NO_DID,
                    self.discovery_params.maxBR, 0x00, &nfc_device->dev.nfcb,
                    NULL, 0, &nfc_device->proto.isoDep);
                if (err == RFAL_ERR_NONE) {
                  self.state = HAL_NFC_STATE_CONNECTED;
                  break;
                }
              }
            }
          }
        } else if (nfc_device->type == RFAL_NFC_LISTEN_TYPE_NFCA) {
#ifdef RFAL_FEATURE_NFCA
          err = rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_REQA,
                                            &sensARes);
          DBGTRACE_LOG1("CHKP", err);
          if (err == RFAL_ERR_NONE) {
            // Collision resolution
            err = rfalNfcaPollerFullCollisionResolution(
                RFAL_COMPLIANCE_MODE_NFC, 1, &nfc_device->dev.nfca, &devCnt);
            DBGTRACE_LOG1("COLR", err);
            if (err == RFAL_ERR_NONE) {
              // Issue ISO Dep A Activation
              err = rfalIsoDepPollAHandleActivation(
                  self.discovery_params.isoDepFS, RFAL_ISODEP_NO_DID,
                  self.discovery_params.maxBR, &nfc_device->proto.isoDep);
              DBGTRACE_LOG1("ISOA", err);
              // ReturnCode rfalIsoDepPollAHandleActivation(
              //     rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR,
              //     rfalIsoDepDevice* rfalIsoDepDev);
              if (err == RFAL_ERR_NONE) {
                self.state = HAL_NFC_STATE_CONNECTED;
              }
            }
          }
        }
#endif  // RFAL_FEATURE_NFCA
      }
      self.state = HAL_NFC_STATE_START_DISCOVERY;
      break;

 

Brian TIDAL
ST Technical Moderator
September 17, 2026

Hi,

The state machine mixes calls to the RFAL high layer (HL) and direct calls to the protocol and technology layers.

The ST RFAL architecture is explicitly layered. The rfal_nfc module provides the high-level loop (RFAL HL) for discovery, activation, and deactivation, but it intentionally exposes or uses the underlying protocol and technology layers (rfal_isoDep.c and rfal_nfca.c) to execute deeper interactions. However, arbitrary use of these layers can break the internal state.

See UM2890 RF/NFC abstraction layer (RFAL) user manual for details.

When the system reaches the RFAL_NFC_STATE_ACTIVATED state, that is, when rfalNfcIsDevActivated returns true, technology detection, collision resolution, and device activation are already complete. The tag is ready for data exchange. Therefore, it is not necessary to deselect the tag manually and perform collision resolution again. Please share more information about this additional HAL_NFC_STATE_POLLING state.

Regarding the RFAL_ERR_TIMEOUT in rfalNfcaPollerFullCollisionResolution:

rfalNfcaPollerCheckPresence causes the NFC-A tag to leave the IDLE state and enter the READY_A state. Therefore, the tag cannot reply properly to rfalNfcaPollerFullCollisionResolution. If the code fully relies on RFAL HL, it should not be needed to manually call rfal_nfca API.

Rgds

BT

 

 

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
sdesai32Author
Associate
September 24, 2026

Hi Brian,

 

Thanks for your reply, I did not know that when rfalNfcIsDevActivated returns True, it means that the card is activated. I was able to confirm that after code inspection as well as the reference manual you linked. I have since removed the HAL_NFC_STATE_POLLING and the Tag moves to HAL_NFC_STATE_CONNECTED once rfalNfcIsDevActivated is true and RFAL_NFC_LISTEN_TYPE_NFCB or RFAL_NFC_LISTEN_TYPE_NFCA active device type is detected. The new consolidated states are pasted in the comment below, please let me know if you notice any redundancies there.

 

I studied some examples for Type 4A/4B support in the XCUBENFC6 software package and noticed that rfalIsoDepPollBHandleActivation is only called for Type 4B listen type device and not Type 4A.

Can you explain why the same check is not done for Type 4A?

 

 

 

sdesai32Author
Associate
September 24, 2026

 

 

Brian TIDAL
ST Technical Moderator
September 25, 2026

Hi,

I guess the question is why rfalNfcbIsIsoDepSupported() is called for an NFC-B listen device, and why a similar function is not called for an NFC-A listen device.

The NFC Forum defines several types of NFC-A listen device, such as Type 1 Tag (now obsolete), Type 2 Tag, and Type 4A Tag. Type 1 Tag and Type 2 Tag do not support the ISO-DEP higher-layer protocol.

When the application detects an NFC-A listen device, the demo_polling.c demo distinguishes the device types and uses ISO-DEP only for tags that support this higher-layer protocol:

case RFAL_NFC_LISTEN_TYPE_NFCA:
platformLedOn(PLATFORM_LED_A_PORT, PLATFORM_LED_A_PIN);
switch( nfcDevice->dev.nfca.type )
{
case RFAL_NFCA_T1T:
platformLog("ISO14443A/Topaz (NFC-A T1T) TAG found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
break;

case RFAL_NFCA_T4T:
platformLog("NFCA Passive ISO-DEP device found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
demoAPDU();
break;

case RFAL_NFCA_T4T_NFCDEP:
case RFAL_NFCA_NFCDEP:
...

For NFC-B listen devices, the application must also check whether ISO-DEP is supported. The code performs this check through rfalNfcbIsIsoDepSupported().

For your application, the following modifications are recommended:

  • Ensure that discParam.p2pNfcaPrio = false; is set instead of true.
  • Manage the NFC-A listen device types as follows: 
case RFAL_NFC_LISTEN_TYPE_NFCA:
switch( nfcDevice->dev.nfca.type )
{
case RFAL_NFCA_T4T_NFCDEP:
case RFAL_NFCA_T4T:
/*
* Your code here e.g. self.state = HAL_NFC_STATE_CONNECTED
*/
break;

default:
break;
}
break;

 

Rgds

BT

 

 

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.