> 技术文档 > RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522

RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522


RK3568 平台 RC522 RFID 驱动开发全解析

    • 一、引言
    • 二、硬件连接
      • 1. RC522 模块引脚说明
      • 2. RK3568 与 RC522 的连接
      • 3. 硬件注意事项
    • 三、设备树配置
    • 四、内核驱动开发
    • 五、调试与验证
    • 六、参考资料

一、引言

RFID 技术在物联网、门禁系统、支付终端等地方有着广泛应用。RC522 作为一款高集成度的 RFID 读写模块,支持 ISO/IEC 14443A/MIFARE 协议,可轻松实现 13.56MHz 频段的近场通信。本文将详细介绍如何在 RK3568 开发板上开发 RC522 的驱动程序,实现 RFID 卡片的读写功能。

二、硬件连接

1. RC522 模块引脚说明

RC522 模块共有 8 个引脚,常用的 6 个引脚功能如下:

引脚名称 功能描述 SDA SPI 片选信号 SCK SPI 时钟信号 MOSI SPI 主出从入信号 MISO SPI 主入从出信号 IRQ 中断引脚 GND 接地 RST 复位引脚 3.3V 电源(3.3V)

用于检测不同接口类型的连接方案
RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522

2. RK3568 与 RC522 的连接

RK3568共接6个引脚对应如下:

RC522引脚 RK3568引脚 RK3568GPIO引脚复用 SDA SPI0_CS0_M1 GPIO2_D2 SCK SPI0_CLK_M1 GPIO2_D3 MOSI SPI0_MOSI_M1 GPIO2_D1 MISO SPI0_MISO_M1 GPIO2_D0 IRQ GND 接地 RST 3.3V 电源(3.3V)

RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522

3. 硬件注意事项

RC522 工作电压为 3.3V,不可直接连接 5V 电源,否则会损坏模块。
之前用的杜邦线过长导致通信异常,后来通过将杜邦线裁剪到3-5cm才通信成功。
RST 引脚可连接到 GPIO,以便软件控制 RC522 的复位操作。

三、设备树配置

在 Linux 系统中,设备树(Device Tree)是描述硬件设备信息的关键文件。我们需要在 RK3568 的设备树中添加 RC522 的节点配置。

/home/chenmy/rk356x/RK356X_Android11.0/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi

&spi0 { status = \"okay\";rc522:rc522@0{  compatible = \"rc522\"; reg = <0>; spi-max-frequency = <1000000>;};};

RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522
设置一些引脚复用功能
/home/chenmy/rk356x/RK356X_Android11.0/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi

spi0: spi@fe610000 { compatible = \"rockchip,rk3066-spi\";reg = <0x0 0xfe610000 0x0 0x1000>;interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;#address-cells = <1>;#size-cells = <0>;clocks = <&cru CLK_SPI0>, <&cru PCLK_SPI0>;clock-names = \"spiclk\", \"apb_pclk\";dmas = <&dmac0 20>, <&dmac0 21>;dma-names = \"tx\", \"rx\";pinctrl-names = \"default\", \"high_speed\";//pinctrl-0 = ;pinctrl-0 = <&spi0m1_cs0 &spi0m1_pins>;//pinctrl-1 = ;pinctrl-1 = <&spi0m1_cs0 &spi0m1_pins_hs>;status = \"disabled\";};

RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522
下面这个是系统自带的引脚复用直接使用
/home/chenmy/rk356x/RK356X_Android11.0/kernel/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi
RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522

修改完成后需要编译kernel,烧录boot.img
查看引脚复用

cd /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrlcat pinmux-pins

在这里插入图片描述

RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522

四、内核驱动开发

RC522一些寄存器设置,可以参考RC522手册
RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522
数据格式
RK3568 平台 RC522 RFID 驱动开发全解析_rk平台适配rc522
rc522.c

#include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include \"mfrc522.h\"#define MAXRLEN 18/* 认证参数结构 */struct rc522_auth {  uint8_t code; /* 认证模式(PICC_AUTHENT1A/B) */ uint8_t block_addr; /* 块地址 */ uint8_t key[6]; /* 密钥 */ uint8_t sid[4]; /* 卡片序列号 */};/* RC522设备结构 */struct rc522_dev {  struct spi_device *spi; struct mutex mutex; int irq; int reset_gpio; //struct gpio_desc *cs_gpio; /* 片选GPIO描述符 */ dev_t devt; struct cdev cdev; struct class *class; struct device *device; bool card_present; uint8_t card_uid[5]; struct timer_list detect_timer; struct work_struct detect_work; // 工作队列};/* 向RC522写寄存器 */static void rc522_write_reg(struct rc522_dev *dev, u8 reg, u8 value){  /* 拉低片选,选中设备 */ //gpiod_set_value(dev->cs_gpio, 0); u8 buf[2]; struct spi_message msg; struct spi_transfer xfer = {  .tx_buf = buf, .len = 2, .cs_change = 0, }; /* 寄存器地址格式: 0XXXXXX0 */ buf[0] = (reg << 1) & 0x7E; buf[1] = value; //spi_write(dev->spi, buf, 2); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); spi_sync(dev->spi, &msg); /* 拉高片选,释放设备 */ //gpiod_set_value(dev->cs_gpio, 1); }/* 从RC522读寄存器 */static u8 rc522_read_reg(struct rc522_dev *dev, u8 reg){  /* 拉低片选,选中设备 */ //gpiod_set_value(dev->cs_gpio, 0); u8 tx_buf[2]; u8 rx_buf[2]; struct spi_message msg; struct spi_transfer xfer = {  .tx_buf = tx_buf, .rx_buf = rx_buf, .len = 2, .cs_change = 0, }; /* 寄存器地址格式: 1XXXXXX0 */ tx_buf[0] = ((reg << 1) & 0x7E) | 0x80; tx_buf[1] = 0; //spi_write_then_read(dev->spi, tx_buf, 2, rx_buf, 2); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); spi_sync(dev->spi, &msg); /* 拉高片选,释放设备 */ //gpiod_set_value(dev->cs_gpio, 1); return rx_buf[1];}/* 设置RC522寄存器的多个位 */static void rc522_set_bit_mask(struct rc522_dev *dev, u8 reg, u8 mask){  u8 tmp; tmp = rc522_read_reg(dev, reg); rc522_write_reg(dev, reg, tmp | mask);}/* 清除RC522寄存器的多个位 */static void rc522_clear_bit_mask(struct rc522_dev *dev, u8 reg, u8 mask){  u8 tmp; tmp = rc522_read_reg(dev, reg); rc522_write_reg(dev, reg, tmp & (~mask));}/* 计算CRC校验值 */static int rc522_calculate_crc(struct rc522_dev *dev, u8 *data, u8 length, u8 *crc){  u8 i; /* 清空CRC寄存器 */ rc522_clear_bit_mask(dev, DivIrqReg, 0x04); /* 清除CRC中断标志 */ rc522_write_reg(dev, CommandReg, PCD_IDLE); rc522_set_bit_mask(dev, FIFOLevelReg, 0x80); /* 清空FIFO */ /* 写入数据 */ for (i = 0; i < length; i++) {  rc522_write_reg(dev, FIFODataReg, data[i]); } /* 启动CRC计算 */ rc522_write_reg(dev, CommandReg, PCD_CALCCRC); /* 等待计算完成 */ i = 0; while (!(rc522_read_reg(dev, DivIrqReg) & 0x04)) {  i++; if (i > 0xFF) return MI_ERR; udelay(10); } /* 读取CRC结果 */ crc[0] = rc522_read_reg(dev, CRCResultRegL); crc[1] = rc522_read_reg(dev, CRCResultRegM); return MI_OK;}///////////////////////////////////////////////////////////////////////功 能:通过RC522和ISO14443卡通讯/////////////////////////////////////////////////////////////////////static int rc522_transceive(struct rc522_dev *dev, u8 command, u8 *send_data, u8 send_len, u8 *recv_data, u8 *recv_len){  int status = MI_ERR; u8 irq_en = 0x00; u8 irq_wait = 0x00; u8 last_bits; u8 n; u16 i; switch (command) {  case PCD_AUTHENT: irq_en = 0x12; irq_wait = 0x10; break; case PCD_TRANSCEIVE: irq_en = 0x77; irq_wait = 0x30; break; default: break; } rc522_write_reg(dev, ComIEnReg, irq_en | 0x80); rc522_clear_bit_mask(dev, ComIrqReg, 0x80); rc522_write_reg(dev, CommandReg, PCD_IDLE); rc522_set_bit_mask(dev, FIFOLevelReg, 0x80); for (i = 0; i < send_len; i++) {  rc522_write_reg(dev, FIFODataReg, send_data[i]); } rc522_write_reg(dev, CommandReg, command);  if (command == PCD_TRANSCEIVE) {  rc522_set_bit_mask(dev, BitFramingReg, 0x80