Nordic 的 nRF52832 和 nRF52840 具有 NFC 的功能,官方提供 t2t_lib 和 t4t_lib 支持 NFC Type 2 tag 和 NFC Type 4 tag 类型的标签。其中 T2T 的库仅支持读卡,不支持写卡,T4T 的库支持读和写。
目前手头有个标签需要满足 Ntag213(T2T) 数据格式,并支持读写,查阅 Nordic 资料后发现他们不提供 T2T NFC 写的技术支持,并且不开源驱动调用部分的代码,只能自己写。参考 Nordic 论坛这篇博客后,决定抛弃 SDK 中 nfc_t2t_lib_gcc.a,编写一个 T2T 支持读写库。
以下为 Demo 详细部分:
一、前提
1、可以使用 SDK 的 examples\nfc\record_text 进行修改;
2、驱动为官方提供的 nrfx_nfct.c,需要使能的宏定义移植时参考 NFC 的例程。
二、修改 nrfx_nfct.c
1、nrfx_nfct_tx 函数添加以下代码:
nrf_nfct_tx_frame_config_set(NRF_NFCT_TX_FRAME_CONFIG_PARITY |
NRF_NFCT_TX_FRAME_CONFIG_DISCARD_START |
NRF_NFCT_TX_FRAME_CONFIG_SOF |
NRF_NFCT_TX_FRAME_CONFIG_CRC16);
修改前:
修改后:
2、添加 ACK 回复函数,并在头文件 nrfx_nfct.h 中添加该函数:
nrfx_err_t nrfx_nfct_tx_ack_nack(uint8_t code)
{
static uint8_t Ack;
Ack = code;nrfx_err_t err = NRFX_SUCCESS;
NRFX_CRITICAL_SECTION_ENTER();
/* In case when NFC frame transmission has already started, it returns an error. */
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMESTART))
{
err = NRFX_ERROR_BUSY;
}
else
{
/* In case when Tx operation was scheduled with delay, stop scheduled Tx operation. */
*(volatile uint32_t *)0x40005010 = 0x01;nrf_nfct_rxtx_buffer_set(&Ack, 16);
nrf_nfct_tx_bits_set(4);
nrf_nfct_tx_frame_config_set(NRF_NFCT_TX_FRAME_CONFIG_SOF);nrfx_nfct_rxtx_int_enable(NRFX_NFCT_TX_INT_MASK);
nrf_nfct_task_trigger(NRF_NFCT_TASK_STARTTX);
}NRFX_CRITICAL_SECTION_EXIT();
return err;
}
三、编写 NFC 调用逻辑
这里我命名为 custom_nfc.c,头文件由你们自己定义啦,关于 NFC 的读写过程,命令码什么的参考 NFC 论坛 T2T 使用文档,详细代码如下:
#include <stdint.h>
#include "nrfx_nfct.h"
#define NFC_RX_BUFFER_SIZE 16u /**< NFC Rx data buffer size */
#define T2T_READ_CMD 0x30u /**< Type 2 Tag Read command identifier */
#define T2T_WRITE_CMD 0xA2u
#define ACK_CODE 0x0Au
#define NACK_CODE 0x00u
static uint8_t nfc_card_raw[180];
static uint8_t nfc_card_id[7] = {/*自定义*/};
static bool m_is_started;
static nrfx_nfct_config_t nfct_config;
static uint8_t rx_data[NFC_RX_BUFFER_SIZE];
static nrfx_nfct_data_desc_t rx_nfct_data_desc = {
.p_data = rx_data,
.data_size = NFC_RX_BUFFER_SIZE,
};
static nrfx_nfct_param_t nfct_param = {
.id = NRFX_NFCT_PARAM_ID_NFCID1,
.data.nfcid1.id_size = 7,
};
static void nfc_callback(nrfx_nfct_evt_t const * p_event)
{
switch(p_event->evt_id)
{
case NRFX_NFCT_EVT_FIELD_DETECTED: {
nrfx_nfct_state_force(NRF_NFCT_TASK_ACTIVATE);
} break;
case NRFX_NFCT_EVT_RX_FRAMEEND: {
nrfx_nfct_evt_rx_frameend_t const *rx_fram = &p_event->params.rx_frameend;
uint8_t BNo = rx_fram->rx_data.p_data[1];
if(rx_fram->rx_status == 0)
{
if(rx_fram->rx_data.p_data[0] == T2T_READ_CMD) //读命令
{
if(BNo < 252)
{
rx_nfct_data_desc.p_data = &nfc_card_raw[BNo * 4];
nrfx_nfct_tx(&rx_nfct_data_desc, NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID);
NRF_LOG_HEXDUMP_INFO(rx_nfct_data_desc.p_data, rx_nfct_data_desc.data_size);
}
else
{
nrfx_nfct_tx_ack_nack(NACK_CODE);
}
}
else if(rx_fram->rx_data.p_data[0] == T2T_WRITE_CMD) //写命令
{
if (rx_fram->rx_data.data_size == 6)
{
uint8_t i, c;
NRF_LOG_INFO("Ready to write :");
NRF_LOG_HEXDUMP_INFO(rx_nfct_data_desc.p_data, rx_nfct_data_desc.data_size);
for (i = 0; i < 4; i++) {
c = rx_fram->rx_data.p_data[2 + i];
nfc_card_raw[BNo * 4 + i] = c;
}
nrfx_nfct_tx_ack_nack(ACK_CODE); // Ack for write command
}
else
{
nrfx_nfct_tx_ack_nack(NACK_CODE); // NAck for write command : should be 0, 1, 4 or 5
}
}
else
{
nrfx_nfct_init_substate_force(NRFX_NFCT_ACTIVE_STATE_SLEEP);
}
}
else
{
nrfx_nfct_init_substate_force(NRFX_NFCT_ACTIVE_STATE_SLEEP);
}
} break;
case NRFX_NFCT_EVT_SELECTED: {
rx_nfct_data_desc.p_data = rx_data;
nrfx_nfct_rx(&rx_nfct_data_desc);
} break;
case NRFX_NFCT_EVT_TX_FRAMEEND: {
rx_nfct_data_desc.p_data = rx_data;
nrfx_nfct_rx(&rx_nfct_data_desc);
} break;
default: break;
}
}
void nfc_data_update(void *p_data, uint16_t len)
{
memcpy(nfc_card_raw, p_data, len);
if(m_is_started)
{
nrfx_nfct_disable();
}
nrfx_nfct_enable();
m_is_started = true;
}
void nfc_init(void)
{
nfct_config.rxtx_int_mask = 0x450;
nfct_config.cb = nfc_callback;
nrfx_nfct_init(&nfct_config);
nfct_param.data.nfcid1.p_id = nfc_card_id;
nrfx_nfct_parameter_set(&nfct_param);
}
四、总结
该部分代码写的比较仓促,简单实现了 T2T 的读写功能,不排除有 BUG,若编写存在问题或者是使用起来存在 BUG,麻烦告诉我一声,感谢!