两个 CH58X 芯片通过 NFC-A 实现 FIFO 数据透传

CH58X 系列(CH585/CH584)的 NFC-A 外设同时支持 PCD(Proximity Coupling Device,读卡器)和 PICC(Proximity Integrated Circuit Card,卡模拟)两种角色。FIFO(First In First Out,先进先出队列)是数据透传的核心——双方各维护一个发送队列,上层应用往里塞数据,通信层在每次交互时取出并发送。SDK 没有提供开箱即用的"透传模式",但底层的 PCD(读卡器)/PICC(卡模拟)API 允许在 ISO 14443-3A 传输层之上构建任意数据交换。一块芯片做读卡器发起命令,另一块做卡响应,双方通过自定义命令码通信。

核心思路

PCD(读卡器)主动发起通信,PICC(卡模拟)被动响应。ISO 14443-3A 的标准选择流程——REQA(Request,寻卡指令)→ ANTICOLL(Anti-Collision,防冲突)→ SELECT(选中)——完成后,PICC(卡模拟)进入 ACTIVE 状态。在此状态下,data_handler 回调可以识别自定义命令码,读写任意数据缓冲区。每次数据交换由 PCD(读卡器)发起一帧,PICC(卡模拟)回复一帧。

两端如何收发数据

PCD(读卡器)端——主动发、等回复:

PCD(读卡器)是通信的发起方。先把要发送的数据填入 g_nfca_pcd_send_buf,调用 nfca_pcd_communicate(data_bits_num, recv_mode, offset)——前两个参数指定要发送的比特数和接收模式,第三个参数 offset 是首比特在首字节中的偏移(0-7),通常填 0。芯片会自动把数据调制成 13.56 MHz 射频信号发射出去,发完后自动切换到接收模式,等待 PICC(卡模拟)回复。轮询 nfca_pcd_get_communicate_status 直到状态变为 DONE,回复数据就从 g_nfca_pcd_recv_buf 里读,长度用 nfca_pcd_get_recv_data_len 获取。

整个过程是:填发送缓冲 → 调 communicate → 等状态结束 → 读接收缓冲

PICC(卡模拟)端——被动收、填回复:

PICC(卡模拟)靠读卡器的射频场供电,不能主动发数据。SDK 通过回调机制处理通信:注册一个 nfca_picc_cb_t 结构体,其中 data_handler 是核心回调,在中断里被调用。每当读卡器发来一帧数据,g_picc_data_buf 里就是收到的内容,bits_num 是比特数。你在这个回调里解析命令、准备响应:把回复数据写入同一个 g_picc_data_buf,校验位写入 g_picc_parity_buf,最后返回回复的比特数,芯片自动完成后续的射频回复。

整个过程是:data_handler 被触发 → 读 g_picc_data_buf → 写回复到同一缓冲 → 返回比特数

通信流程

  1. PCD(读卡器)发 REQA(寻卡,0x26)/WUPA(唤醒,0x52)→ PICC(卡模拟)回 ATQA(寻卡应答)→ PICC(卡模拟)进入 READY 状态
  2. PCD(读卡器)执行 ANTICOLL(防冲突,0x93)+ SELECT(选中)→ PICC(卡模拟)回 UID(唯一标识符)+ SAK(选中确认)→ PICC(卡模拟)进入 ACTIVE 状态
  3. ACTIVE 状态下,PCD(读卡器)可发送任意自定义命令码,PICC(卡模拟)的 data_handler 处理并回复

PICC(卡模拟)端可以参考 SDK 中 T2T(Type 2 Tag,NFC Forum 定义的标签标准之一)示例(wch_nfca_picc_t2t.c)的 NFCA_PICC_T2T_STATE_ACTIVE 分支,把 READ/WRITE 等标准命令替换为自己的协议即可。

FIFO 交换帧格式

PCD(读卡器)必须持续轮询才能维持通信,每次轮询本身就是一次数据交换机会。一个实用的做法是双方各维护一个发送 FIFO,每次帧交互时顺带捎上自己的 FIFO 数据:

PCD → PICC 帧

字段 字节 说明
命令码 1 自定义值(如 0xF0),标识这是数据交换帧
序号/确认 1 高 4 位:本次发送的序号(0-15);低 4 位:已收到的对方上一帧序号(ACK)
数据长度 1 本次携带的 FIFO 数据字节数,无数据时填 0
数据 变长 FIFO 中取出的数据,长度由上字段决定
CRC 2 ISO 14443-3A 标准 CRC_A

PICC → PCD 响应帧(不含命令码,其余结构相同):

字段 字节 说明
序号/确认 1 高 4 位:本次发送的序号;低 4 位:已收到的对方上一帧序号(ACK)
数据长度 1 本次携带的 FIFO 数据字节数,无数据时填 0
数据 变长 FIFO 中取出的数据
CRC 2 ISO 14443-3A 标准 CRC_A

序号和确认的设计:

关键点:

断连与恢复

PICC(卡模拟)离开射频场后,PCD(读卡器)的 nfca_pcd_communicate 会超时返回错误。PCD(读卡器)侧需要在主循环中检测这个状态:超时后停止对当前卡的轮询,回到 REQA 重新寻卡。

PICC(卡模拟)侧离场后回调 offline 被触发,状态回到 IDLE。重新进入射频场时回调 online 被触发,之后必须重新走完整的选卡流程(REQA → ANTICOLL → SELECT)才能再次进入 ACTIVE 状态接收数据帧。

这意味着上层协议要能接受通信中断:数据 FIFO 在断连期间可能积压,恢复后需从断点继续,而不应假设通道永远在线。

传输中途断开的数据保护

断连最棘手的情况发生在发送中途——已经从 FIFO 取出了数据,但 NFC 发送失败,数据不能丢,又不能塞回 FIFO。用暂存区解决:

  1. 从内部 FIFO 取出一定量数据,放到一个暂存区(staging buffer)
  2. 用暂存区里的数据组帧,尝试 NFC 发送
  3. 发送成功 → 暂存区清空,下次从 FIFO 取新数据
  4. 发送失败(超时/断连)→ 暂存区数据保留,下次轮询时直接用暂存区里的数据重试,无需动 FIFO

这样数据流向是单向的:FIFO → 暂存区 → NFC 发送。数据从 FIFO 取出后只往前走,失败就停在暂存区里等下次重试,不需要回退。

至于链路层的丢包或 CRC 校验失败,不在这一层处理——保持通信层轻量,数据完整性校验和重传策略交给上层应用决定。

限制