cancel
Showing results for 
Search instead for 
Did you mean: 

NDEF URL write Error when first initialisation

SimoE
Associate II

I use the ST25DV04KC. I initialize the chip and write to like the eval software the CCFile to Block 0 this works. In this state the chip is CCFile unlocked, the NFC-Tag protocol is selected to Type5, RFMngt_Dyn is in NFC off mode (0x01) and I2C secure session is open. After all this, the function NDEF_DEMO_Write_URI_URL() is called. Same function like the Demo-Eval. But no register is written. On I2C, I receive at write to the EEPROM, NAK.

Only the first Block (0) is filled with values.

If I restart the microconroller with power ON->OFF->ON, It works. And in EEPROM is the NDEF URL and works with the smartphone.

Now also Block (1...+) and more are filled with values

Something is there witch is blocking the chip by configuration. Is there something to pay attention to by configuring the chip?

1 ACCEPTED SOLUTION

Accepted Solutions
JL. Lebon
ST Employee

Hi, 

The delay is indeed important.

The write is done in the EEPROM memory. EEPROM memory has a programing cycle time of 5ms per row of EEPROM. In the ST25DV04KC, the EEPROM row on I2C side is 16 Bytes long (i.e. memory addresses 0x0000 to 0x000F are part of a same row, 0x0010 to 0x001F is the second row, etc.). If you write 1 byte up to 16 Bytes in a row, it will take 5ms to program the EEPROM. If your write across the row border, then it will take 10ms to write (to rows to program in that case), even if you don't write more than 16 Bytes. Each row added to the write will add a 5ms delay.
During the programming cycle, the i2C bus is not accessible and any I2C access is Nacked. This is how all EEPROM work.

There are 2 solutions to solve this: 
- add a fixed, pre-calculated, delay after a write to EEPROM.
- add a polling loop to check when the programing cycle is completed after each write in EEPROM. This polling loop is simply sending a 1 Byte write I2C command (with only the device select code, no data). If this command is nacked, then I2c bus is not ready, and you need to poll again later. If the poll command is Acked, then I2C is ready for the next command.

Best regards.

View solution in original post

5 REPLIES 5
JL. Lebon
ST Employee

Hello, 

If you received a NAK on the EEPROM write, then no data is written.
So it is strange that you can find data after a reboot. May be they have been written earlier?

Anyway, for the NAK issue, you can check if the memory is not protected by reading the I2CSS configuration byte. This byte controls the protection of memory area for I2C access. But if you have already open the I2C security session this should not be a problem.

Can you share the code of your NDEF_DEMO_Write_URI_URL() function?

Best regards.

Yes, sure.

uint32_t NDEF_Write_URI_URL(void)
{

	uint16_t status;
	sURI_Info r_uri = {0};

	/* Write URI for web page */
	sURI_Info w_uri = {URI_ID_0x02_STRING, NDEF_DEMO_URL ,""};
	status = NDEF_WriteURI(&w_uri);

  /* Read back written URI */
	if(status == NDEF_OK)
  {
    status = getURI(&r_uri);
	}

	if((status != NDEF_OK) || \
      strcmp(r_uri.protocol,w_uri.protocol) || \
      strcmp(r_uri.URI_Message,w_uri.URI_Message))
	{
		return NDEF_ERROR;
	}
	else
	{
	  	return NDEF_OK;
	}
}

The NDEF_WriteURI(); witch make the problem.

/**
  * @brief  This function write the NDEF file with the URI data given in the structure.
  * @PAram  pURI : pointer on structure that contain the URI information.
  * @retval NDEF_OK : NDEF file data written in the tag.
  * @retval NDEF_ERROR : not able to store NDEF in tag.
  * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag.
  * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present.
  * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory.
  * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write.
  */
uint16_t NDEF_WriteURI( sURI_Info *pURI )
{
  uint16_t status = NDEF_ERROR, Offset = 0;

  NDEF_PrepareURIMessage( pURI, NDEF_Buffer, &Offset );

  status = NfcTag_WriteNDEF( Offset , NDEF_Buffer );

  return status;
}

char getUriType( char *protocol )
{
  if( !memcmp( protocol, URI_ID_0x01_STRING, strlen(URI_ID_0x01_STRING) ) ) return URI_ID_0x01;
  else if( !memcmp( protocol, URI_ID_0x02_STRING, strlen(URI_ID_0x02_STRING) ) ) return URI_ID_0x02;
  else if( !memcmp( protocol, URI_ID_0x03_STRING, strlen(URI_ID_0x03_STRING) ) ) return URI_ID_0x03;
  else if( !memcmp( protocol, URI_ID_0x04_STRING, strlen(URI_ID_0x04_STRING) ) ) return URI_ID_0x04;
  else if( !memcmp( protocol, URI_ID_0x05_STRING, strlen(URI_ID_0x05_STRING) ) ) return URI_ID_0x05;
  else if( !memcmp( protocol, URI_ID_0x06_STRING, strlen(URI_ID_0x06_STRING) ) ) return URI_ID_0x06;
  else if( !memcmp( protocol, URI_ID_0x07_STRING, strlen(URI_ID_0x07_STRING) ) ) return URI_ID_0x07;
  else if( !memcmp( protocol, URI_ID_0x08_STRING, strlen(URI_ID_0x08_STRING) ) ) return URI_ID_0x08;
  else if( !memcmp( protocol, URI_ID_0x09_STRING, strlen(URI_ID_0x09_STRING) ) ) return URI_ID_0x09;
  else if( !memcmp( protocol, URI_ID_0x0A_STRING, strlen(URI_ID_0x0A_STRING) ) ) return URI_ID_0x0A;
  else if( !memcmp( protocol, URI_ID_0x0B_STRING, strlen(URI_ID_0x0B_STRING) ) ) return URI_ID_0x0B;
  else if( !memcmp( protocol, URI_ID_0x0C_STRING, strlen(URI_ID_0x0C_STRING) ) ) return URI_ID_0x0C;
  else if( !memcmp( protocol, URI_ID_0x0D_STRING, strlen(URI_ID_0x0D_STRING) ) ) return URI_ID_0x0D;
  else if( !memcmp( protocol, URI_ID_0x0E_STRING, strlen(URI_ID_0x0E_STRING) ) ) return URI_ID_0x0E;
  else if( !memcmp( protocol, URI_ID_0x0F_STRING, strlen(URI_ID_0x0F_STRING) ) ) return URI_ID_0x0F;
  else if( !memcmp( protocol, URI_ID_0x10_STRING, strlen(URI_ID_0x10_STRING) ) ) return URI_ID_0x10;
  else if( !memcmp( protocol, URI_ID_0x11_STRING, strlen(URI_ID_0x11_STRING) ) ) return URI_ID_0x11;
  else if( !memcmp( protocol, URI_ID_0x12_STRING, strlen(URI_ID_0x12_STRING) ) ) return URI_ID_0x12;
  else if( !memcmp( protocol, URI_ID_0x13_STRING, strlen(URI_ID_0x13_STRING) ) ) return URI_ID_0x13;
  else if( !memcmp( protocol, URI_ID_0x14_STRING, strlen(URI_ID_0x14_STRING) ) ) return URI_ID_0x14;
  else if( !memcmp( protocol, URI_ID_0x15_STRING, strlen(URI_ID_0x15_STRING) ) ) return URI_ID_0x15;
  else if( !memcmp( protocol, URI_ID_0x16_STRING, strlen(URI_ID_0x16_STRING) ) ) return URI_ID_0x16;
  else if( !memcmp( protocol, URI_ID_0x17_STRING, strlen(URI_ID_0x17_STRING) ) ) return URI_ID_0x17;
  else if( !memcmp( protocol, URI_ID_0x18_STRING, strlen(URI_ID_0x18_STRING) ) ) return URI_ID_0x18;
  else if( !memcmp( protocol, URI_ID_0x19_STRING, strlen(URI_ID_0x19_STRING) ) ) return URI_ID_0x19;
  else if( !memcmp( protocol, URI_ID_0x1A_STRING, strlen(URI_ID_0x1A_STRING) ) ) return URI_ID_0x1A;
  else if( !memcmp( protocol, URI_ID_0x1B_STRING, strlen(URI_ID_0x1B_STRING) ) ) return URI_ID_0x1B;
  else if( !memcmp( protocol, URI_ID_0x1C_STRING, strlen(URI_ID_0x1C_STRING) ) ) return URI_ID_0x1C;
  else if( !memcmp( protocol, URI_ID_0x1D_STRING, strlen(URI_ID_0x1D_STRING) ) ) return URI_ID_0x1D;
  else if( !memcmp( protocol, URI_ID_0x1E_STRING, strlen(URI_ID_0x1E_STRING) ) ) return URI_ID_0x1E;
  else if( !memcmp( protocol, URI_ID_0x1F_STRING, strlen(URI_ID_0x1F_STRING) ) ) return URI_ID_0x1F;
  else if( !memcmp( protocol, URI_ID_0x20_STRING, strlen(URI_ID_0x20_STRING) ) ) return URI_ID_0x20;
  else if( !memcmp( protocol, URI_ID_0x21_STRING, strlen(URI_ID_0x21_STRING) ) ) return URI_ID_0x21;
  else if( !memcmp( protocol, URI_ID_0x22_STRING, strlen(URI_ID_0x22_STRING) ) ) return URI_ID_0x22;
  else if( !memcmp( protocol, URI_ID_0x23_STRING, strlen(URI_ID_0x23_STRING) ) ) return URI_ID_0x23;
  else return URI_ID_0x00; // No abreviation for this protocol	
}

Use the NFC Type 5

uint16_t NfcTag_WriteNDEF(uint16_t Length , uint8_t *pData )
{
  uint16_t status = NDEF_ERROR;
  switch (CurrentProtocol)
  {
    case NFCTAG_TYPE4:
      status = NfcType4_WriteNDEF(Length, pData);
    break;
    case NFCTAG_TYPE3:
      status = NfcType3_WriteNDEF(Length,pData);
    break;
    case NFCTAG_TYPE5:
    case NFCTAG_TYPE2:
    case NFCTAG_TYPE1:
      status = NfcType5_WriteNDEF(Length, pData);
    break;
    default:
      status = NDEF_ERROR;
    break;
  }
  return status;
}

 Witch writes the data

/**
  * @brief  This function writes a NDEF message in the NFC Tag.
  * @PAram	Length Number of bytes to write.
  * @PAram	pData  Pointer on the buffer to copy.
  * @retval NDEF_ERROR_MEMORY_INTERNAL Memory size is too small for the data.
  * @retval NDEF_ERROR_NOT_FORMATED    No Capability Container detected.
  * @retval NDEF_ERROR                 Error when writing the Tag.
  * @retval NDEF_OK                    The data has been successfully written.
  */
uint16_t NfcType5_WriteNDEF(uint16_t Length , uint8_t *pData )
{
  return NfcType5_WriteData(NFCT5_NDEF_MSG_TLV,Length,pData);
}
uint16_t NfcType5_WriteData(uint8_t Type, uint16_t Length , uint8_t *pData )
{
  TT5_TLV_t tlv;
  uint8_t tlv_size;
  uint32_t offset;
  uint8_t NfcT5_Terminator = NFCT5_TERMINATOR_TLV;

  uint32_t max_length = NDEF_Wrapper_GetMemorySize()        /* Memory size */
                        - ((Length >= 0xFF) ? 4 : 2)    /* - TLV length */
                        - sizeof(NfcT5_Terminator)      /* - Terminator TLV */
                        - CCFileStruct.NDEF_offset;     /* - CCfile length */

  /* If too many data to write return error */
  if( Length > max_length )
  {
    return NDEF_ERROR_MEMORY_TAG;
  }
  
  /* Detect NDEF message in memory */
  if( NfcType5_NDEFDetection( ) != NDEF_OK )
  {
    return NDEF_ERROR;
  }
  
  /* Prepare TLV */
  tlv.Type = Type;
  if(Length >= 0xFF)
  {
    tlv.Length = NFCT5_3_BYTES_L_TLV;
    tlv.Length16 = ((Length&0xff)<<8) | ((Length>>8)&0xff) ;
    tlv_size = 4;
    
  } else {
    tlv.Length = Length;
    tlv_size = 2;
  }
  HAL_Delay(5);
  offset = CCFileStruct.NDEF_offset;
  /* Start write TLV to EEPROM */
  if(NDEF_Wrapper_WriteData( (uint8_t*)&tlv, offset, tlv_size )!= NDEF_OK)
    return NDEF_ERROR;
  offset += tlv_size;
  /* Continue write TLV data  to EEPROM */
  if(NDEF_Wrapper_WriteData( pData , offset, Length ) != NDEF_OK )
    return NDEF_ERROR;
  offset +=Length;
  /* Write Terminator TLV */
  if(NDEF_Wrapper_WriteData( &NfcT5_Terminator, offset, sizeof(NfcT5_Terminator) ) != NDEF_OK)
    return NDEF_ERROR;
  return NDEF_OK;

}

And in the NDEF_Wrapper is the function to write over I2C:

int32_t NFC_WriteReg(uint16_t DevAddr, uint16_t Reg, const uint8_t *pData, uint16_t Length) {
  uint32_t r = 1;

  /* Write to the register */
  if(!HAL_I2C_Mem_Write(&hi2c1, DevAddr, Reg, I2C_MEMADD_SIZE_16BIT, (void*)pData, Length, HAL_MAX_DELAY))
    return 0;


 return r;
}

 

Hello, 

So I assume that if you have a Nack on I2C, the error is happening in NFC_WriteReg() function?

Do you have the value of NFC_WriteReg() arguments when the error is happening?

Best regards,

Yes, that happens when you write. When the device address is sent, a Nack is received followed by 0x00 instead of an Ack. I'm not sure if it could be a timing issue. There is no delay in the evaluation code. Update: When I add delays in different places it seems to work perfectly. But I can't understand why this happens. And why the evaluation code does work without.

uint16_t NfcType5_WriteData(uint8_t Type, uint16_t Length , uint8_t *pData )
{
  TT5_TLV_t tlv;
  uint8_t tlv_size;
  uint32_t offset;
  uint8_t NfcT5_Terminator = NFCT5_TERMINATOR_TLV;

  uint32_t max_length = NDEF_Wrapper_GetMemorySize()        /* Memory size */
                        - ((Length >= 0xFF) ? 4 : 2)    /* - TLV length */
                        - sizeof(NfcT5_Terminator)      /* - Terminator TLV */
                        - CCFileStruct.NDEF_offset;     /* - CCfile length */

  /* If too many data to write return error */
  if( Length > max_length )
  {
    return NDEF_ERROR_MEMORY_TAG;
  }
  
  /* Detect NDEF message in memory */
  if( NfcType5_NDEFDetection( ) != NDEF_OK )
  {
    return NDEF_ERROR;
  }
  
  /* Prepare TLV */
  tlv.Type = Type;
  if(Length >= 0xFF)
  {
    tlv.Length = NFCT5_3_BYTES_L_TLV;
    tlv.Length16 = ((Length&0xff)<<8) | ((Length>>8)&0xff) ;
    tlv_size = 4;
    
  } else {
    tlv.Length = Length;
    tlv_size = 2;
  }
  HAL_Delay(5);
  offset = CCFileStruct.NDEF_offset;
  /* Start write TLV to EEPROM */
  if(NDEF_Wrapper_WriteData( (uint8_t*)&tlv, offset, tlv_size )!= NDEF_OK)
    return NDEF_ERROR;
  offset += tlv_size;
  HAL_Delay(5);
  /* Continue write TLV data  to EEPROM */
  if(NDEF_Wrapper_WriteData( pData , offset, Length ) != NDEF_OK )
    return NDEF_ERROR;
  offset +=Length;
  HAL_Delay(5);
  /* Write Terminator TLV */
  if(NDEF_Wrapper_WriteData( &NfcT5_Terminator, offset, sizeof(NfcT5_Terminator) ) != NDEF_OK)
    return NDEF_ERROR;
  HAL_Delay(5);
  return NDEF_OK;
JL. Lebon
ST Employee

Hi, 

The delay is indeed important.

The write is done in the EEPROM memory. EEPROM memory has a programing cycle time of 5ms per row of EEPROM. In the ST25DV04KC, the EEPROM row on I2C side is 16 Bytes long (i.e. memory addresses 0x0000 to 0x000F are part of a same row, 0x0010 to 0x001F is the second row, etc.). If you write 1 byte up to 16 Bytes in a row, it will take 5ms to program the EEPROM. If your write across the row border, then it will take 10ms to write (to rows to program in that case), even if you don't write more than 16 Bytes. Each row added to the write will add a 5ms delay.
During the programming cycle, the i2C bus is not accessible and any I2C access is Nacked. This is how all EEPROM work.

There are 2 solutions to solve this: 
- add a fixed, pre-calculated, delay after a write to EEPROM.
- add a polling loop to check when the programing cycle is completed after each write in EEPROM. This polling loop is simply sending a 1 Byte write I2C command (with only the device select code, no data). If this command is nacked, then I2c bus is not ready, and you need to poll again later. If the poll command is Acked, then I2C is ready for the next command.

Best regards.