2025-08-13 1:59 PM - last edited on 2025-08-20 9:25 AM by Ulysses HERNIOSUS
Hi all,
I’m using an ST25R3916 with RFAL on an STM32 and I’m trying to talk to an NXP NTAG 5 Boost (ISO15693/NFC-V) using its custom commands: READ/WRITE SRAM (0xD2/0xD3) and READ/WRITE I²C (0xD5/0xD4).
Plain ISO15693 commands work fine (e.g., ReadSingleBlock / WriteSingleBlock). For example, reading config block 0x37 returns:
Now I’d like to send the NXP customs via rfalNfcvPollerTransceiveReq(), but I’m not getting a response (often RFAL_ERR_TIMEOUT).
For customs I call rfalNfcvPollerTransceiveReq(cmd, flags, param, uid, payload, payloadLen, rx, rxLen, &rcvLen) like this:
flags: RFAL_NFCV_REQ_FLAG_DEFAULT (0x02, high data rate, no option bit)
param: 0x04 (NXP manufacturer code)
uid: 8-byte UID (addressed mode)
payload and length per the NTAG 5 Boost datasheet (see below)
rx: buffer big enough + checking rcvLen
Example (READ SRAM, command 0xD2:(
uint8_t tx[2] = { startBlock, (uint8_t)(numBlocks - 1) }; // request N blocks
uint8_t rx[1 + 4*64] = {0}; // RES_FLAGS + data uint16_t rcv = 0;
ReturnCode rc = rfalNfcvPollerTransceiveReq( 0xD2, // READ SRAM
RFAL_NFCV_REQ_FLAG_DEFAULT, // 0x02
0x04, // NXP mfg code
uid, // addressed mode
tx,
sizeof(tx),
rx,
sizeof(rx),
&rcv );
Similarly for WRITE SRAM (0xD3) and I²C bridge (0xD4/0xD5).
From the NTAG 5 Boost user manual (table looks like this):
READ SRAM (0xD2) request
Flags (8)
READ SRAM (8) = 0xD2
Manuf. code (8) = 0x04
UID (64, optional if addressed mode)
Block Address (8)
Number of Blocks (8) — value is N-1 (so 0x00 means 1 block)
CRC16
READ SRAM response (no error)
Flags (8)
(Number of Blocks + 1) × 32 bits Data
CRC16
WRITE SRAM (0xD3) request
Flags (8)
WRITE SRAM (8) = 0xD3
Manuf. code (8) = 0x04
UID (optional)
Block Address (8)
Number of Blocks (8) — N-1
Data = N × 4 bytes
CRC16
Only Option_flag = 0 is supported for D2/D3. Datasheet also says SRAM must be enabled and not protected.
My payload lengths follow that (READ: 2 bytes payload; WRITE: 2 + 4*N).
ISO15693 ReadSingleBlock/WriteSingleBlock via rfalNfcvPollerReadSingleBlock() / ...WriteSingleBlock() → OK
NXP custom 0xD2/0xD3/0xD4/0xD5 via rfalNfcvPollerTransceiveReq() as above → mostly RFAL_ERR_TIMEOUT
param field in rfalNfcvPollerTransceiveReq
For customs should I always pass 0x04 (NXP mfg code)? Or should param be skipped (RFAL_NFCV_PARAM_SKIP) and the mfg code embedded somewhere else?
Flags / Addressed mode
Is RFAL_NFCV_REQ_FLAG_DEFAULT (0x02) correct for D2/D3/D4/D5?
Should I also set RFAL_NFCV_REQ_FLAG_ADDRESS myself, or does RFAL add it automatically when uid != NULL?
Option flag
READ/WRITE SRAM specify “Only Option_flag = 0b is supported”. I’m keeping Option=0. Is that correct with RFAL (i.e., don’t set RFAL_NFCV_REQ_FLAG_OPTION)?
Buffer sizes / rcvLen
Is there any RFAL limit/quirk for rxBuf lengths on customs I should be aware of?
If anyone has a minimal working call for Custom Commands (e.g. NTAG 5 Boost 0xD2/0xD3) using rfalNfcvPollerTransceiveReq(), I’d really appreciate a short snippet showing the exact flags, param, and payload formatting.
Thanks!
Solved! Go to Solution.
2025-08-20 9:38 AM
Hi,
looks about right.
Ad 1) correct way for custom commands
ad 2) RFAL looks at uid==NULL and sets the addressed flag if there
ad 3) correct
ad 4) rx buf needs to be able to cope also with the CRC (even if not recieved/wished for). If the CRC does not fit you would get a NO_MEM code.
You could do a logic analyzer trace and provide it here (SPI+IRQ). When doing so, please also enable the NFC-V debugging code inside rfal_rfst25r3916.c (#if 0 -> 1).
Are you sure the tag you are using is actually supporting the commands? Maybe you can verify using the manufacturers tools/apps.
BR, Ulysses
2025-08-20 9:38 AM
Hi,
looks about right.
Ad 1) correct way for custom commands
ad 2) RFAL looks at uid==NULL and sets the addressed flag if there
ad 3) correct
ad 4) rx buf needs to be able to cope also with the CRC (even if not recieved/wished for). If the CRC does not fit you would get a NO_MEM code.
You could do a logic analyzer trace and provide it here (SPI+IRQ). When doing so, please also enable the NFC-V debugging code inside rfal_rfst25r3916.c (#if 0 -> 1).
Are you sure the tag you are using is actually supporting the commands? Maybe you can verify using the manufacturers tools/apps.
BR, Ulysses
2025-08-20 11:02 PM
Hi @Ulysses HERNIOSUS ,
if i debug the code currently the rfalTransceiveBlockingTxRx(...) in rfalTransceiveBlockingTxRx(...) does not return an error (return value = 0).
Then it checks further down in this function if an error has been in the received frame (answer).
/* Check if an error has been signalled */
if( (rxBuf[RFAL_NFCV_FLAG_POS] & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U )
{
return rfalNfcvParseError( rxBuf[RFAL_NFCV_DATASTART_POS] );
}
The Value of the error_pos equals 0xF (dec. 15). For all my custom commands.
But i do not understand why. Therefore i guess it is a configuration problem of my used NFC I2C Bridge (NTAG5 Boost). Or what do you guess? Do you know what 0xF normally stands for? What does this error mean exactly?
2025-08-21 4:00 AM
Hi,
according to ISO/IEC 15693-3: '0F' : Error with no information given or a specific error code is not supported.
I think the manufacturer DS should indicate more conditions when this 0Fh is reported. I think 8.2.6.2 of its DS indicates that "received command or option is not supported".
BR, Ulysses
2025-08-21 6:07 AM
Hi @Ulysses HERNIOSUS ,
Thank you so much so far :)
So the Commands for ReadI2C and WriteI2C should be executed the exact same way using the rfal - right? Or am i understanding the rfal function wrong? rx / sizeof(rx) can be larger then needed - or might this lead to a problem?
So first i would write the ADC register i want to read out via WriteI2C and then immediately i would send a ReadI2C with the amount of data to read from the ADC (speficied by the ADC register).
// I²C bridge (0xD4/0xD5)
uint8_t tx[2] = { i2c_slave_addr, data_length_rx };
uint8_t rx[data_length_rx ] = {0};
ReturnCode rc = rfalNfcvPollerTransceiveReq( 0xD4,
RFAL_NFCV_REQ_FLAG_DEFAULT, // 0x02
0x04, // NXP mfg code
uid, // addressed mode
tx,
sizeof(tx),
rx,
sizeof(rx),
&rcv );
2025-08-21 7:32 AM
Hi,
rx size should be at least two bytes bigger then needed when using ST25R39xx devices (as RFAL is internally using the Stream mode and does need to receive and check CRC in SW). It can be even bigger.
BR Ulysses