This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52 write NFC Tag

Hi,

I am not yet familiar with NFC and have a question about using NFC with the nRF52.

If I understood it correctly the nRF52 is a "listening device" i.e. it cannot generate a NFC field and write data to another device. But is it possible to send/write data from another device (for example a smartphone) to the NFC tag of the nRF52. Or is it only possible to read data from the tag? If it is not possible at the moment will it be possible in the future?

I am using a nRF52 development kit with nRF5 SDK 11.0.0-2.alpha.

Thanks, Alex

Parents
  • Hello,

    The write NFC Tag is now enabled :)

    I've removed the libnfc library because it didn't support the write feature, and no documentation is provided by Nordic to manage it. Furthermore the library gives information to the host (the NFC reader), that the card is NOT writable. So the host will never send the write request (0xA2).

    What exactly does this library? It simulates a Type2 NFC buffer card, and provided data to the HAL driver. I've replaced it, by a function who sends the buffer content with the right datas.

    static uint8_t Test_Memory_Type2[NFC_MAX_PAYLOAD_SIZE_RAW] = {
    	// page 0
    	0x5F, 0xF6, 0x4C, 0x6D,	// Internal 0-3
    	0x2F, 0xF4, 0xDA, 0x59,	// Internal 4-7
    	0x58, 0x03, 0x00, 0x00, // Internal 8-9 | Lock0-1       // <-- makes the card writable !
    	0xE1, 0x11, 0x7C, 0x00, // CC0-3						// <-- makes the card writable !
    	// page 4
    	0x03, 0x16, 0xC1, 0x01,	// TLV Tag field, Length field, Value field
    	0x00, 0x00, 0x00, 0x0F, // NDEF Payload length 15
    	0x54, 0x02, 0x65, 0x6E, // NDEF Message Type : Text UTF8, "Hello World!"
    	0x48, 0x65, 0x6C, 0x6C, //
    	// page 8
    	0x6F, 0x20, 0x57, 0x6F,
    	0x72, 0x6C, 0x64, 0x21, //
    	0x00, 0x00, 0x00, 0x00,
    	0x00, 0x00, 0x00, 0x00,
    };
    

    I've linked directly the application calls to the HAL functions to check if it's working

    ret_val = nfcSetup(nfc_callback, NULL);
    

    replaced by ret_val = hal_nfc_setup(nfc_callback, NULL);

    welcome_msg_encode(ndef_msg_buf, &len);
    ret_val = nfcSetPayload( (char*)ndef_msg_buf, len);	
    

    no need because the buffer is already set with the right datas

    ret_val = nfcStartEmulation();
    

    replaced by ret_val = hal_nfc_start();

    So the main function looks like this below :

    int main(void) {
    	NfcRetval ret_val;
    
    	printf("nfc_1 start\n");
    
    	uint32_t err_code = NRF_LOG_INIT();
    	APP_ERROR_CHECK(err_code);
    
    	/* Configure LED-pins as outputs */
    	LEDS_CONFIGURE(BSP_LED_0_MASK);
    	LEDS_OFF(BSP_LED_0_MASK);
    
    	ret_val = hal_nfc_setup(nfc_callback, NULL); // <-- callback to to application 
    	APP_ERROR_CHECK(ret_val);
    
    	// Start sensing NFC field
    	ret_val = hal_nfc_start();
    	APP_ERROR_CHECK(ret_val);
    	while(1)
    	{
    		if (!NFC_NEED_MCU_RUN_STATE())
    		{
    			__WFE();
    		}
    	}
    return 0;
    }
    

    And I've added the read & write command inside the NFCT_IRQHandler !

    ...
    if (NRF_NFCT->EVENTS_RXFRAMEEND && (NRF_NFCT->INTEN & NFCT_INTEN_RXFRAMEEND_Msk))
    {
        /* Take into account only number of whole bytes */
        uint32_t rx_data_size = ((NRF_NFCT->RXD.AMOUNT & NFCT_RXD_AMOUNT_RXDATABYTES_Msk) >> NFCT_RXD_AMOUNT_RXDATABYTES_Pos);
    
        nrf_nfct_event_clear(&NRF_NFCT->EVENTS_RXFRAMEEND);
    
    	if (rx_data_size>NFC_CRC_SIZE) {
    		rx_data_size -= NFC_CRC_SIZE;
    
    		LOG_HAL_NFC("[NFC_HAL]: rx %02X [%02X]\r\n", m_nfc_rx_buffer[0], m_nfc_rx_buffer[1]);
    
            switch (m_nfc_rx_buffer[0]) {
    
            case T2T_READ_CMD :		// 30h
            	{
    				uint8_t BNo = m_nfc_rx_buffer[1];
    				if (BNo<252) /* Max Block number */
    					hal_nfc_send(&Test_Memory_Type2[BNo*4], 16);
    				else 
    					/* hal_nfc_send(&Dymamic_Memory_Aera[0], 16); */
    					hal_send_ack_nack(0x0);	// NAck
            	}
            	break;
    
    
    
            case T2T_WRITE_CMD :	// A2h
            	{
    				uint8_t BNo = m_nfc_rx_buffer[1];
    				if (rx_data_size==6) {
    					LOG_HAL_NFC("[NFC_HAL]: receive");
    					uint8_t i, c;
    					for (i=0;i<4;i++) {
    						c = m_nfc_rx_buffer[2+i];
    						Test_Memory_Type2[BNo*4 + i] = c;
    						NRF_LOG_PRINTF(" %02X", c);
    					}
    					NRF_LOG_PRINTF("\n");
    
    					hal_send_ack_nack(0xA);	// Ack for write command
    				} else {
    					hal_send_ack_nack(0x0);	// NAck for write command : should be 0, 1, 4 or 5
    				}
            	}
            	break;
    
            case NFC_SLP_REQ_CMD :
            	LOG_HAL_NFC("[NFC_HAL]: SLP_REQ\r\n");
            	m_slp_req_received = true;
    
            default:
            	/* Not a READ Command, so wait for next frame reception */
            	NRF_NFCT->TASKS_ENABLERXDATA = 1;
            	break;
    
            }
    	}
    ...
    

    the HAL send functions are listed below:

    /**
     * send data to the host (the reader) with CRC16 
     */
    hal_nfc_retval hal_nfc_send(const uint8_t *data, size_t dataLength)
    {
    	if (dataLength == 0)
    	{
    		return HAL_NFC_RETVAL_INVALID_SIZE;
    	}
    
    	
    	/* Ignore previous TX END events, SW takes care only for data frames which tranmission is triggered in this function */
    	nrf_nfct_event_clear(&NRF_NFCT->EVENTS_TXFRAMEEND);
    
    	NRF_NFCT->PACKETPTR     = (uint32_t)(data);
    	NRF_NFCT->TXD.AMOUNT    = (dataLength << NFCT_TXD_AMOUNT_TXDATABYTES_Pos) & NFCT_TXD_AMOUNT_TXDATABYTES_Msk;
    
    	uint32_t reg = 0;
    	reg |= (NFCT_TXD_FRAMECONFIG_PARITY_Parity << NFCT_TXD_FRAMECONFIG_PARITY_Pos);
    	reg |= (NFCT_TXD_FRAMECONFIG_DISCARDMODE_DiscardStart << NFCT_TXD_FRAMECONFIG_DISCARDMODE_Pos);
    	reg |= (NFCT_TXD_FRAMECONFIG_SOF_SoF << NFCT_TXD_FRAMECONFIG_SOF_Pos);
    	reg |= (NFCT_TXD_FRAMECONFIG_CRCMODETX_CRC16TX << NFCT_TXD_FRAMECONFIG_CRCMODETX_Pos);
    	NRF_NFCT->TXD.FRAMECONFIG  = reg;
    
    	NRF_NFCT->INTENSET      = (NFCT_INTENSET_TXFRAMEEND_Enabled << NFCT_INTENSET_TXFRAMEEND_Pos);
    	NRF_NFCT->TASKS_STARTTX = 1;
    
    	LOG_HAL_NFC("[NFC_HAL]: send");
    	uint8_t i;
    	for (i=0;i<dataLength;i++) {
    		NRF_LOG_PRINTF(" %02X", *(data+i));
    	}
    
    	NRF_LOG_PRINTF("\n");
    
    
    	return HAL_NFC_RETVAL_OK;
    }
    
    /**
     * send a ack or nack to the host (the reader) without CRC16
     */
    static hal_nfc_retval hal_send_ack_nack(uint8_t ack_nack_code) {
    	static uint8_t Ack;
    	Ack = ack_nack_code;
    
    	nrf_nfct_event_clear(&NRF_NFCT->EVENTS_TXFRAMEEND);
    
    	NRF_NFCT->PACKETPTR     = (uint32_t)(&Ack);
    	NRF_NFCT->TXD.AMOUNT    =  4;
    
    	uint32_t reg = 0;
    	/* reg |= (NFCT_TXD_FRAMECONFIG_PARITY_Parity << NFCT_TXD_FRAMECONFIG_PARITY_Pos); */
    	reg |= (NFCT_TXD_FRAMECONFIG_SOF_SoF << NFCT_TXD_FRAMECONFIG_SOF_Pos);
    	NRF_NFCT->TXD.FRAMECONFIG  = reg;
    	NRF_NFCT->INTENSET      = (NFCT_INTENSET_TXFRAMEEND_Enabled << NFCT_INTENSET_TXFRAMEEND_Pos);
    	NRF_NFCT->TASKS_STARTTX = 1;
    
    	return HAL_NFC_RETVAL_OK;
    }
    

    Et voila !

Reply
  • Hello,

    The write NFC Tag is now enabled :)

    I've removed the libnfc library because it didn't support the write feature, and no documentation is provided by Nordic to manage it. Furthermore the library gives information to the host (the NFC reader), that the card is NOT writable. So the host will never send the write request (0xA2).

    What exactly does this library? It simulates a Type2 NFC buffer card, and provided data to the HAL driver. I've replaced it, by a function who sends the buffer content with the right datas.

    static uint8_t Test_Memory_Type2[NFC_MAX_PAYLOAD_SIZE_RAW] = {
    	// page 0
    	0x5F, 0xF6, 0x4C, 0x6D,	// Internal 0-3
    	0x2F, 0xF4, 0xDA, 0x59,	// Internal 4-7
    	0x58, 0x03, 0x00, 0x00, // Internal 8-9 | Lock0-1       // <-- makes the card writable !
    	0xE1, 0x11, 0x7C, 0x00, // CC0-3						// <-- makes the card writable !
    	// page 4
    	0x03, 0x16, 0xC1, 0x01,	// TLV Tag field, Length field, Value field
    	0x00, 0x00, 0x00, 0x0F, // NDEF Payload length 15
    	0x54, 0x02, 0x65, 0x6E, // NDEF Message Type : Text UTF8, "Hello World!"
    	0x48, 0x65, 0x6C, 0x6C, //
    	// page 8
    	0x6F, 0x20, 0x57, 0x6F,
    	0x72, 0x6C, 0x64, 0x21, //
    	0x00, 0x00, 0x00, 0x00,
    	0x00, 0x00, 0x00, 0x00,
    };
    

    I've linked directly the application calls to the HAL functions to check if it's working

    ret_val = nfcSetup(nfc_callback, NULL);
    

    replaced by ret_val = hal_nfc_setup(nfc_callback, NULL);

    welcome_msg_encode(ndef_msg_buf, &len);
    ret_val = nfcSetPayload( (char*)ndef_msg_buf, len);	
    

    no need because the buffer is already set with the right datas

    ret_val = nfcStartEmulation();
    

    replaced by ret_val = hal_nfc_start();

    So the main function looks like this below :

    int main(void) {
    	NfcRetval ret_val;
    
    	printf("nfc_1 start\n");
    
    	uint32_t err_code = NRF_LOG_INIT();
    	APP_ERROR_CHECK(err_code);
    
    	/* Configure LED-pins as outputs */
    	LEDS_CONFIGURE(BSP_LED_0_MASK);
    	LEDS_OFF(BSP_LED_0_MASK);
    
    	ret_val = hal_nfc_setup(nfc_callback, NULL); // <-- callback to to application 
    	APP_ERROR_CHECK(ret_val);
    
    	// Start sensing NFC field
    	ret_val = hal_nfc_start();
    	APP_ERROR_CHECK(ret_val);
    	while(1)
    	{
    		if (!NFC_NEED_MCU_RUN_STATE())
    		{
    			__WFE();
    		}
    	}
    return 0;
    }
    

    And I've added the read & write command inside the NFCT_IRQHandler !

    ...
    if (NRF_NFCT->EVENTS_RXFRAMEEND && (NRF_NFCT->INTEN & NFCT_INTEN_RXFRAMEEND_Msk))
    {
        /* Take into account only number of whole bytes */
        uint32_t rx_data_size = ((NRF_NFCT->RXD.AMOUNT & NFCT_RXD_AMOUNT_RXDATABYTES_Msk) >> NFCT_RXD_AMOUNT_RXDATABYTES_Pos);
    
        nrf_nfct_event_clear(&NRF_NFCT->EVENTS_RXFRAMEEND);
    
    	if (rx_data_size>NFC_CRC_SIZE) {
    		rx_data_size -= NFC_CRC_SIZE;
    
    		LOG_HAL_NFC("[NFC_HAL]: rx %02X [%02X]\r\n", m_nfc_rx_buffer[0], m_nfc_rx_buffer[1]);
    
            switch (m_nfc_rx_buffer[0]) {
    
            case T2T_READ_CMD :		// 30h
            	{
    				uint8_t BNo = m_nfc_rx_buffer[1];
    				if (BNo<252) /* Max Block number */
    					hal_nfc_send(&Test_Memory_Type2[BNo*4], 16);
    				else 
    					/* hal_nfc_send(&Dymamic_Memory_Aera[0], 16); */
    					hal_send_ack_nack(0x0);	// NAck
            	}
            	break;
    
    
    
            case T2T_WRITE_CMD :	// A2h
            	{
    				uint8_t BNo = m_nfc_rx_buffer[1];
    				if (rx_data_size==6) {
    					LOG_HAL_NFC("[NFC_HAL]: receive");
    					uint8_t i, c;
    					for (i=0;i<4;i++) {
    						c = m_nfc_rx_buffer[2+i];
    						Test_Memory_Type2[BNo*4 + i] = c;
    						NRF_LOG_PRINTF(" %02X", c);
    					}
    					NRF_LOG_PRINTF("\n");
    
    					hal_send_ack_nack(0xA);	// Ack for write command
    				} else {
    					hal_send_ack_nack(0x0);	// NAck for write command : should be 0, 1, 4 or 5
    				}
            	}
            	break;
    
            case NFC_SLP_REQ_CMD :
            	LOG_HAL_NFC("[NFC_HAL]: SLP_REQ\r\n");
            	m_slp_req_received = true;
    
            default:
            	/* Not a READ Command, so wait for next frame reception */
            	NRF_NFCT->TASKS_ENABLERXDATA = 1;
            	break;
    
            }
    	}
    ...
    

    the HAL send functions are listed below:

    /**
     * send data to the host (the reader) with CRC16 
     */
    hal_nfc_retval hal_nfc_send(const uint8_t *data, size_t dataLength)
    {
    	if (dataLength == 0)
    	{
    		return HAL_NFC_RETVAL_INVALID_SIZE;
    	}
    
    	
    	/* Ignore previous TX END events, SW takes care only for data frames which tranmission is triggered in this function */
    	nrf_nfct_event_clear(&NRF_NFCT->EVENTS_TXFRAMEEND);
    
    	NRF_NFCT->PACKETPTR     = (uint32_t)(data);
    	NRF_NFCT->TXD.AMOUNT    = (dataLength << NFCT_TXD_AMOUNT_TXDATABYTES_Pos) & NFCT_TXD_AMOUNT_TXDATABYTES_Msk;
    
    	uint32_t reg = 0;
    	reg |= (NFCT_TXD_FRAMECONFIG_PARITY_Parity << NFCT_TXD_FRAMECONFIG_PARITY_Pos);
    	reg |= (NFCT_TXD_FRAMECONFIG_DISCARDMODE_DiscardStart << NFCT_TXD_FRAMECONFIG_DISCARDMODE_Pos);
    	reg |= (NFCT_TXD_FRAMECONFIG_SOF_SoF << NFCT_TXD_FRAMECONFIG_SOF_Pos);
    	reg |= (NFCT_TXD_FRAMECONFIG_CRCMODETX_CRC16TX << NFCT_TXD_FRAMECONFIG_CRCMODETX_Pos);
    	NRF_NFCT->TXD.FRAMECONFIG  = reg;
    
    	NRF_NFCT->INTENSET      = (NFCT_INTENSET_TXFRAMEEND_Enabled << NFCT_INTENSET_TXFRAMEEND_Pos);
    	NRF_NFCT->TASKS_STARTTX = 1;
    
    	LOG_HAL_NFC("[NFC_HAL]: send");
    	uint8_t i;
    	for (i=0;i<dataLength;i++) {
    		NRF_LOG_PRINTF(" %02X", *(data+i));
    	}
    
    	NRF_LOG_PRINTF("\n");
    
    
    	return HAL_NFC_RETVAL_OK;
    }
    
    /**
     * send a ack or nack to the host (the reader) without CRC16
     */
    static hal_nfc_retval hal_send_ack_nack(uint8_t ack_nack_code) {
    	static uint8_t Ack;
    	Ack = ack_nack_code;
    
    	nrf_nfct_event_clear(&NRF_NFCT->EVENTS_TXFRAMEEND);
    
    	NRF_NFCT->PACKETPTR     = (uint32_t)(&Ack);
    	NRF_NFCT->TXD.AMOUNT    =  4;
    
    	uint32_t reg = 0;
    	/* reg |= (NFCT_TXD_FRAMECONFIG_PARITY_Parity << NFCT_TXD_FRAMECONFIG_PARITY_Pos); */
    	reg |= (NFCT_TXD_FRAMECONFIG_SOF_SoF << NFCT_TXD_FRAMECONFIG_SOF_Pos);
    	NRF_NFCT->TXD.FRAMECONFIG  = reg;
    	NRF_NFCT->INTENSET      = (NFCT_INTENSET_TXFRAMEEND_Enabled << NFCT_INTENSET_TXFRAMEEND_Pos);
    	NRF_NFCT->TASKS_STARTTX = 1;
    
    	return HAL_NFC_RETVAL_OK;
    }
    

    Et voila !

Children
Related