cancel
Showing results for 
Search instead for 
Did you mean: 

Writing NDEF for ST25DV. Code failing

isaacseeto
Associate III

Hi I was just wondering if someone could help point out where I could be going wrong with my implementation of write NDEF function. This is a very rough implementation but I believe I am following the correct message structure. I know my i2c mem write commands are working as I have tested the addresses. When I use the ST25 Tap app I don't see NDEF storage being populated. 

My implementation:

HAL_StatusTypeDef write_ndef_pressure_message(int32_t pressure_mmHg_scaled) {

HAL_StatusTypeDef status;

 

// Create a buffer for the pressure message (e.g., "123.45 mmHg")

char pressure_str[16]; // Max size for the pressure string (with decimals and unit)

snprintf(pressure_str, sizeof(pressure_str), "%ld.%02ld mmHg", pressure_mmHg_scaled / 100, pressure_mmHg_scaled % 100);

 

uint16_t message_len = strlen(pressure_str);

 

// Ensure the total length doesn't exceed the memory limit

if (message_len + NDEF_HEADER_SIZE > 32) {

message_len = 32 - NDEF_HEADER_SIZE; // Limit to 32 bytes (adjust based on available memory size)

}

 

// 1. Clear User Memory Area 1 (32 bytes for this example)

uint8_t clear_memory[32] = {0}; // Clear memory

status = HAL_I2C_Mem_Write(&hi2c1, ST25DV_I2C_DATA_ADDRESS, USER_MEMORY_START, I2C_MEMADD_SIZE_16BIT, clear_memory, 32, HAL_MAX_DELAY);

 

// Ensure the device is ready for the next operation (check readiness)

while (HAL_I2C_IsDeviceReady(&hi2c1, ST25DV_I2C_DATA_ADDRESS, 1, HAL_MAX_DELAY) != HAL_OK) {

HAL_Delay(5); // Small delay to allow the device to complete the write

}

 

// 2. Adjust NDEF Header for the correct payload length

NDEF_Text_Header[2] = message_len; // Set the correct payload length in the NDEF header

 

// 3. Write the NDEF header to User Memory Area 1

status = HAL_I2C_Mem_Write(&hi2c1, ST25DV_I2C_DATA_ADDRESS, USER_MEMORY_START, I2C_MEMADD_SIZE_16BIT, NDEF_Text_Header, NDEF_HEADER_SIZE, HAL_MAX_DELAY);

 

// Ensure the device is ready for the next operation (check readiness)

while (HAL_I2C_IsDeviceReady(&hi2c1, ST25DV_I2C_DATA_ADDRESS, 1, HAL_MAX_DELAY) != HAL_OK) {

HAL_Delay(5); // Small delay to allow the device to complete the write

}

 

// 4. Write the NDEF payload (pressure value as string) right after the header

status = HAL_I2C_Mem_Write(&hi2c1, ST25DV_I2C_DATA_ADDRESS, USER_MEMORY_START + NDEF_HEADER_SIZE, I2C_MEMADD_SIZE_16BIT, (uint8_t*)pressure_str, message_len, HAL_MAX_DELAY);

 

// Ensure the device is ready for the next operation (check readiness)

while (HAL_I2C_IsDeviceReady(&hi2c1, ST25DV_I2C_DATA_ADDRESS, 1, HAL_MAX_DELAY) != HAL_OK) {

HAL_Delay(5); // Small delay to allow the device to complete the write

}

 

return status;

}

 

Thank you.

7 REPLIES 7
Brian TIDAL
ST Employee

Hi,

can you dump the user memory from block #0 to the last block being used by your NDEF and share it with us? You can use the ST25 NFC Tap application to dump the memory content

 

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.

Hi,

This is the memory bin file from the ST25 Tap app.

Thank you

Hi,

the NDEF message seems to be written starting from block 0:

BrianTIDAL_0-1727853071200.png

This is not compilant with NFC Forum T5T technical specification. Block 0 should contain the so-called Capability Container (aka CC). See Application Note AN4911 (ST25DV-I2C, ST25TV16K and ST25TV64K configuration to support a NDEF message).

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.

Hi,

I just tried to update my code according to the document you sent but it is still not appearing in the NDEF section of the app.

// NDEF Header: Text Record (UTF-8)

uint8_t NDEF_Text_Header[NDEF_HEADER_SIZE] = {

0xD1, // MB, ME, SR, TNF = 0x1 (Well-known type)

0x01, // Type Length = 1 byte (for text)

0x00, // Payload Length (to be updated dynamically based on the pressure value string)

0x54, // Type = 'T' (for text record)

0x02, // UTF-8 encoding, language code length = 2

0x65, // 'e' (for "en" language code)

0x6E, // 'n' (for "en" language code)

0x00

};

 

// 8-byte Capability Container for ST25DV64K

uint8_t CapabilityContainer[8] = {

0xE2, // Magic number (2-byte address mode)

0x40, // Version + Access (1.x, Read/Write allowed)

0x00, // Reserved

0x00, // Additional feature information

0x00, // Reserved

0x00, // Reserved

0x03, // MLEN high byte (1023 blocks used for NDEF area)

0xFF // MLEN low byte (1023 blocks used for NDEF area)

};

// Function to write the Capability Container (CC) to Block 0

HAL_StatusTypeDef write_capability_container(void) {

HAL_StatusTypeDef status;

 

// Write the CC to Block 0 (8 bytes)

status = HAL_I2C_Mem_Write(&hi2c1, ST25DV_I2C_DATA_ADDRESS, CC_BLOCK, I2C_MEMADD_SIZE_16BIT, CapabilityContainer, 8, HAL_MAX_DELAY);

if (status != HAL_OK) {

// Handle error

return status;

}

 

// Ensure the device is ready for the next operation

while (HAL_I2C_IsDeviceReady(&hi2c1, ST25DV_I2C_DATA_ADDRESS, 1, HAL_MAX_DELAY) != HAL_OK) {

HAL_Delay(5);

}

return status;

}

 

HAL_StatusTypeDef write_ndef_pressure_message(int32_t pressure_mmHg_scaled) {

HAL_StatusTypeDef status;

 

status = write_capability_container();

 

// Create a buffer for the pressure message (e.g., "123.45 mmHg")

char pressure_str[20]; // Max size for the pressure string (with decimals and unit)

snprintf(pressure_str, sizeof(pressure_str), "%ld.%02ld mmHg", pressure_mmHg_scaled / 100, pressure_mmHg_scaled % 100);

 

uint16_t message_len = strlen(pressure_str);

 

// Ensure the total length doesn't exceed the memory limit

if (message_len + NDEF_HEADER_SIZE > 32) {

message_len = 32 - NDEF_HEADER_SIZE; // Limit to 32 bytes (adjust based on available memory size)

}

 

// 1. Adjust NDEF Header for the correct payload length

NDEF_Text_Header[2] = message_len; // Set the correct payload length in the NDEF header

 

// 2. Write the NDEF header to User Memory Area 1

status = HAL_I2C_Mem_Write(&hi2c1, ST25DV_I2C_DATA_ADDRESS, NDEF_BLOCK_START, I2C_MEMADD_SIZE_16BIT, NDEF_Text_Header, NDEF_HEADER_SIZE, HAL_MAX_DELAY);

 

// Ensure the device is ready for the next operation (check readiness)

while (HAL_I2C_IsDeviceReady(&hi2c1, ST25DV_I2C_DATA_ADDRESS, 1, HAL_MAX_DELAY) != HAL_OK) {

HAL_Delay(5); // Small delay to allow the device to complete the write

}

 

// 3. Write the NDEF payload (pressure value as string) right after the header

status = HAL_I2C_Mem_Write(&hi2c1, ST25DV_I2C_DATA_ADDRESS, NDEF_BLOCK_START + NDEF_HEADER_SIZE, I2C_MEMADD_SIZE_16BIT, (uint8_t*)pressure_str, message_len, HAL_MAX_DELAY);

 

// Ensure the device is ready for the next operation (check readiness)

while (HAL_I2C_IsDeviceReady(&hi2c1, ST25DV_I2C_DATA_ADDRESS, 1, HAL_MAX_DELAY) != HAL_OK) {

HAL_Delay(5); // Small delay to allow the device to complete the write

}

 

return status;

}

Any advice for where I am going wrong?

Thanks

Hi,

block #0 does not have a valid Capability Container and the NDEF TLV seems to start in the middle of the second block:

BrianTIDAL_0-1729165679752.png

Your memory should look like:

BrianTIDAL_0-1729173911365.png

In this dump, block #0 and block #1contains a valid CC starting with E2 (i.e. support of 2-byte address mode) and the NDEF TLV starts just after the CC (i.e. at the beginning of block #2).

Make sure to follow Application Note AN4911. 

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.

Hi,

I have read AN4911 but I am still having a hard time understanding the NDEF header, namely what values to put. 

Could each byte of the example be explained, please?

Thanks

Brian TIDAL
ST Employee

Hi,

In the example, block #0 and #1 contain an 8-bytes Capability Container (CC). The various bytes of the CC are described in §3.1 of AN4911. The format of the 8-bytes CC is shown in table 4 of AN4911

Then, the NDEF TLV starts on Block #2:

  • 03h is the T-field for the NDEF
  • 15h is the L-field of this NDEF (i.e. the overall length)
  • the next byte D1h is the beginning of the record header. I would suggest the reading of 4. Introducing NDEF - Beginning NFC [Book] that provides a comprehensive description of the NDEF structure.

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.