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 个引脚功能如下:
用于检测不同接口类型的连接方案
2. RK3568 与 RC522 的连接
RK3568共接6个引脚对应如下:
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>;};};
设置一些引脚复用功能
/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\";};
下面这个是系统自带的引脚复用直接使用
/home/chenmy/rk356x/RK356X_Android11.0/kernel/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi
修改完成后需要编译kernel,烧录boot.img
查看引脚复用
cd /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrlcat pinmux-pins
四、内核驱动开发
RC522一些寄存器设置,可以参考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