关于exynos4412开发平台编写RC522射频模块驱动

        关于RC522射频模块的信息就不特别介绍,网上的资源和介绍的都很详细,本文只针对在使用exynos4412平台开发时遇到的问题进行记录和解决

1.设备树的编写

 注意要配置好rts复位管脚和cs片选管脚,这里选择的是外接gpd1_2口和gpd1_3口。

2.配置好设备树之后进行驱动编写

#include <linux/module.h>//模块加载卸载函数
#include <linux/kernel.h>//内核头文件
#include <linux/types.h>//数据类型定义
#include <linux/fs.h>//file_operations结构体
#include <linux/device.h>//class_create等函数
#include <linux/ioctl.h>
#include <linux/kernel.h>/*包含printk等操作函数*/
#include <linux/of.h>/*设备树操作相关的函数*/
#include <linux/gpio.h>/*gpio接口函数*/
#include <linux/of_gpio.h>
#include <linux/platform_device.h>/*platform device*/
#include <linux/spi/spi.h> /*spi相关api*/
#include <linux/delay.h> /*内核延时函数*/
#include <linux/slab.h> /*kmalloc、kfree函数*/
#include <linux/cdev.h>/*cdev_init cdev_add等函数*/
#include <asm/gpio.h>/*gpio接口函数*/
#include <asm/uaccess.h>/*__copy_from_user 接口函数*/
#include "spi_rc522.h"

#define DEVICE_NAME    "nfc" 

typedef struct
{
      struct device_node *node;//设备树节点
      struct device_node *childnode;//设备树子节点
      struct cdev cdev;       //定义一个cdev结构体
      struct class *class;    //创建一个rc522类
      struct device *device;  //创建一个rc522设备 该设备是需要挂在rc522类下面的
      int major;              //主设备号
      dev_t  dev_id;
      struct spi_device *spi; /*spi设备*/
     int cspin;              /*片选脚*/
      int rstpin;               /*复位管脚*/
      struct mutex lock;
      void *private_data;
}rc522_typdef;

static rc522_typdef rc522_dev;//定义一个rc522设备

void spi_rst_enable(void) //拉低复位
{
    gpio_set_value(rc522_dev.rstpin, 0); 
}

void spi_rst_disable(void) 
{
   gpio_set_value(rc522_dev.rstpin, 1); 
}

void spi_cs_enable(void)//拉低片选
{
    gpio_set_value(rc522_dev.cspin, 0);
}

void spi_cs_disable(void)
{
    gpio_set_value(rc522_dev.cspin, 1);
}

static int rc522_read_regs(rc522_typdef *dev, unsigned char reg, unsigned char *dat, unsigned char len)
{

    int ret = -1;
    unsigned char txdata[len];
    unsigned char * rxdata;
    struct spi_message m;
    struct spi_transfer *t;
    struct spi_device *spi = dev->spi;
    
    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   /* 申请内存 */
    if(!t) {
        return -ENOMEM;
    }

    rxdata = kzalloc((sizeof(char) * len), GFP_KERNEL); /* 申请内存 */
    if(!rxdata) {
        goto out1;
    }
    spi_cs_enable();
    /* 一共发送len+1个字节的数据,第一个字节为
    寄存器首地址,一共要读取len个字节长度的数据,*/
    txdata[0] = ((reg << 1) & 0x7e) | 0x80;             
    t->tx_buf = txdata;         /* 要发送的数据 */
    t->rx_buf = rxdata;         /* 要读取的数据 */
    t->len = len + 1;           /* t->len=发送的长度+读取的长度 */
    spi_message_init(&m);       /* 初始化spi_message */
    spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
    ret = spi_sync(spi, &m);    /* 同步发送 */
    if(ret) {
        goto out2;
    }
    /* 只需要读取的数据 */
    memcpy(dat , rxdata +1, len); /* 只需要读取的数据 */

out2:
    kfree(rxdata);                  /* 释放内存 */
out1:   
    kfree(t);                       /* 释放内存 */
    spi_cs_disable();
    return ret;
}

static int rc522_write_regs(rc522_typdef *dev, unsigned char reg, unsigned char *dat, unsigned char len)
{

    int ret = -1;
    unsigned char *txdata;
    struct spi_message m;
    struct spi_transfer *t;
    struct spi_device *spi = dev->spi;
    
    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   /* 申请内存 */
    if(!t) {
        return -ENOMEM;
    }
    
    txdata = kzalloc(sizeof(char) + len, GFP_KERNEL);
    if(!txdata) {
        goto out1;
    }
    spi_cs_enable();
    /* 一共发送len+1个字节的数据,第一个字节为
    寄存器首地址,len为要写入的寄存器的集合,*/
    *txdata = ((reg << 1) & 0x7e);  /* 写数据的时候首寄存器地址bit8要清零 */
    memcpy(txdata + 1, dat, len);

    t->tx_buf = txdata;         /* 要发送的数据 */
    t->len = len + 1;                   /* t->len=发送的长度+读取的长度 */
    spi_message_init(&m);       /* 初始化spi_message */
    spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
    ret = spi_sync(spi, &m);    /* 同步发送 */
    if(ret) {
        goto out2;
    }
    
out2:
    kfree(txdata);      /* 释放内存 */
out1:
    kfree(t);                   /* 释放内存 */
    spi_cs_disable();
    return ret; 
}

static unsigned char read_one_reg(rc522_typdef *dev, unsigned char reg)
{
    unsigned char data = 0;

    rc522_read_regs(dev, reg, &data, 1);

    return data;    
}

static void write_one_reg(rc522_typdef *dev,unsigned char reg, unsigned char value)
{
    rc522_write_regs(dev, reg, &value, 1);
}

static int rc522_open(struct inode *inode, struct file *filp)
{

    filp->private_data = &rc522_dev;

      spi_rst_disable();
      udelay(10);
      spi_rst_enable();
       udelay(10);
       spi_rst_disable();
    udelay(10);
    printk("rc522_open ok1!\n");

    return 0;
}

static int rc522_release(struct inode* inode ,struct file *filp)
{
    spi_rst_enable();
    gpio_free(rc522_dev.rstpin);
    printk("rc522_release ok!\n");   
    return 0;
}

// loff_t rc522_llseek(struct file *file, loff_t offset, int whence)
// {
//  return 0;
// }

static int rc522_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
    unsigned char *write_buf;/*数据缓冲区*/
    int ret;

    write_buf = (unsigned char*)kzalloc(count, GFP_KERNEL);
    if(!write_buf )
       return -ENOMEM;

    ret = copy_from_user(write_buf, buf, count);
    if (ret < 0)
    {
        kfree(write_buf);
        printk("copy from user failed!\r\n");
        return ret;
    }

    write_one_reg(&rc522_dev, write_buf[0], write_buf[1]);

    return 0;
}

static ssize_t rc522_read(struct file *filp,char __user *buf, size_t count,loff_t *f_pos)
{
    int ret; 
    unsigned char adr,value; 

    ret = copy_from_user(&adr, buf, 1);
    if(ret < 0)
    {
        printk("copy from user failed!\r\n");
        return ret;
    }
    value = read_one_reg(&rc522_dev, adr);
    ret = copy_to_user(buf, &value, count);
    if (ret < 0)
    {
        printk("copy to user failed!\r\n");
        return ret;
    }

    return ret;
}

static struct file_operations rc522_fops={
    .owner      = THIS_MODULE,
    .open       = rc522_open,
    .write      = rc522_write,
    .read       = rc522_read,
    .release    = rc522_release,
    // .llseek     = rc522_llseek,
};
        
static int rc522_probe(struct spi_device *spi)
{
        int ret;
        const char *string = NULL;
        printk("rc522 probe!\n"); 
    
       /*获取设备节点*/
       rc522_dev.node = of_find_node_by_path("/spi@13940000/rc522@0");
       if(rc522_dev.node == NULL)
       {
          printk("device-tree:not found rc522!\r\n"); 
          return -1;
       }
    
       /*读取rc522设备节点的compatible属性值*/
       ret = of_property_read_string(rc522_dev.node, "compatible", &string);
       if(ret == 0)
       {
           printk("%s\n",string);
       }   
     /*读取rc522设备节点的rst-gpio属性值*/
       rc522_dev.rstpin = of_get_named_gpio(rc522_dev.node,"rst-gpio",0);
       if(!gpio_is_valid(rc522_dev.rstpin))
       {
            printk("get gpio error\n");
            ret = -EINVAL;
            return ret;
       }
       
       printk("gpio = %d\n",rc522_dev.rstpin);
    
       ret = gpio_request(rc522_dev.rstpin,"spi-rst");
       if(ret < 0) 
       {
          printk("gpio_request %d failed\n", rc522_dev.rstpin);
          return ret;
        }
        gpio_direction_output(rc522_dev.rstpin, 1);
        gpio_export(rc522_dev.rstpin, 1);

        /*获取rc522设备节点的子节点controller-data资源*/
       rc522_dev.childnode  = of_find_node_by_path("/spi@13940000/rc522@0/controller-data");

          /*获取rc522设备节点的子节点controller-data的cs-gpio属性*/
       rc522_dev.cspin = of_get_named_gpio(rc522_dev.childnode,"cs-gpio",0);
         if(!gpio_is_valid(rc522_dev.cspin))
       {
            printk("get gpio_cs error\n");
            ret = -EINVAL;
            return ret;
       }
         printk("gpio_cs = %d\n",rc522_dev.cspin);

       
         ret = gpio_request(rc522_dev.cspin,"spi-cspin");
       if(ret < 0) 
       {
          printk("gpio_request %d failed\n", rc522_dev.cspin);
          return ret;
        }
       gpio_direction_output(rc522_dev.cspin, 1);       
       gpio_export(rc522_dev.cspin, 1);
      
    
        /*申请设备号*/
        ret = alloc_chrdev_region(&rc522_dev.dev_id, 0, 1, DEVICE_NAME);
        if(ret < 0)
        {
             printk("alloc dev_id error %d\n", ret);
             return ret;
        }
    
       /*初始化一个cdev*/
       cdev_init(&rc522_dev.cdev, &rc522_fops);
    
       /*向cdev中添加一个设备*/
       ret = cdev_add(&rc522_dev.cdev, rc522_dev.dev_id, 1);
       if(ret != 0)
       {
            printk("cdev add error %d \n",ret);
            // goto Error;
       }
    
       /*创建一个nfc_class类*/
       rc522_dev.class = class_create(THIS_MODULE, "nfc_class");
       if(rc522_dev.class == NULL)
       {
          printk("class_create failed\r\n");
          return -1;
       }
       /*在nfc_class类下创建一个NFC_class设备*/
       rc522_dev.device = device_create(rc522_dev.class, NULL, rc522_dev.dev_id, NULL, DEVICE_NAME);   
    
       /*获取与本驱动匹配的spi设备*/
       rc522_dev.spi = spi;
       spi_setup(rc522_dev.spi);   
       
    // Error:
    //    cdev_del(&rc522_dev.cdev);
    //    unregister_chrdev_region(rc522_dev.dev_id, 1);
        return 0;

}

static int rc522_remove(struct spi_device *spi)
{
    printk("w25qxx remove!\n"); 

    /*删除rc522类*/
    cdev_del(&rc522_dev.cdev);

    /*释放rc522设备号*/
    unregister_chrdev_region(rc522_dev.dev_id, 1);

    /*注销rc522设备*/
    device_destroy(rc522_dev.class, rc522_dev.dev_id);

    /*注销rc522类*/
    class_destroy(rc522_dev.class);

    gpio_free(rc522_dev.rstpin);

    return 0;   
}

static const struct of_device_id rc522_of_match[] = {
   {.compatible = "firefly,rc522"},
   {},
};

static const struct spi_device_id rc522_id[] = {
    { "xxxx", 0 },
    {},
};

MODULE_DEVICE_TABLE(of, rc522_of_match);


static struct spi_driver rc522_driver = {
    .driver = {
        .owner = THIS_MODULE,       
        .name =  "rc522",
        .of_match_table = rc522_of_match,
    },
    .probe = rc522_probe,
    .remove = rc522_remove,
    .id_table = rc522_id,
};

static int __init rc522_init(void)
{
   int ret;

   ret = spi_register_driver(&rc522_driver);
   if(ret < 0)
   {
        printk("spi_register_driver error= %d \n",ret);
   }
   else
   {
        printk("module init ok\n");
   }
   return ret;
}

static void rc522_exit(void)
{
    spi_unregister_driver(&rc522_driver);  
    printk("module exit ok\n");
}

module_init(rc522_init);
module_exit(rc522_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("rc522 driver");
MODULE_AUTHOR("lsjml2022");

测试程序app

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <limits.h>
#include <asm/ioctls.h>
#include <time.h>
#include <pthread.h>
#include <string.h>
#include "spi_rc522.h"
 
#define  MAXRLEN 18 
 
 int fd = 0;//文件句柄
 
 void print_data(const char *title, char *dat, int count)
 {
	int i = 0; 
 
	printf(title);
 
	for(i = 0; i < count; i++) 
	{
	   printf(" 0x%x", dat[i]);
	}
	printf("\n");
 }
 
 unsigned char ReadRawRC(unsigned char Address)
 {
   unsigned char buf[1]; 
 
   buf[0] = Address;
	read(fd,buf,1);  
   return buf[0];  
 }
 
 void WriteRawRC(unsigned char Address, unsigned char Value)
 {	
   unsigned char buf[2];
 
   buf[0] = Address;
   buf[1] = Value;
   write(fd,buf,2);  
 }
 
 void SetBitMask(unsigned char ucReg, unsigned char ucMask)  
 {
   unsigned char ucTemp;
 
   ucTemp = ReadRawRC ( ucReg );
   WriteRawRC (ucReg, ucTemp | ucMask); // set bit mask
 }
 
 void ClearBitMask(unsigned char ucReg, unsigned char ucMask)  
 {
   unsigned char ucTemp;
 
   ucTemp = ReadRawRC (ucReg);
   WriteRawRC (ucReg, ucTemp & ( ~ ucMask)); // clear bit mask
 }
 
 void PcdAntennaOn(void)
 {
   unsigned char uc;
 
   uc = ReadRawRC (TxControlReg);
   if (! ( uc & 0x03 ))
   {
	   SetBitMask(TxControlReg, 0x03);	 
   }
 }
 
 static void PcdAntennaOff(void)
 {
	 ClearBitMask(TxControlReg, 0x03);
 }
 
 int PcdReset(void)
 {	
 	int res;
 	 fd = open("/dev/nfc", O_RDWR);
	 if(fd < 0)
	 {
		 printf("open rc522_drv error %d\n",fd);
		 
	   return fd;
   }
 
   WriteRawRC ( CommandReg, 0x0f );

   usleep(1000);
   
   while ( ReadRawRC ( CommandReg ) & 0x10 );
  
	//定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363
	WriteRawRC ( ModeReg, 0x3D );
	WriteRawRC ( TReloadRegL, 30 ); 	 //16位定时器低位   
	WriteRawRC ( TReloadRegH, 0 );		//16位定时器高位 
	WriteRawRC ( TModeReg, 0x8D );		//定义内部定时器的设置 
	WriteRawRC ( TPrescalerReg, 0x3E );   //设置定时器分频系数  
	WriteRawRC ( TxAutoReg, 0x40 ); 	  //调制发送信号为100%ASK 

	res = ReadRawRC(VersionReg);
        if(res!=0)
        {
                res=0;
        }
        res = ReadRawRC(ModeReg);
        if(res!=0x3d)
                {
                        res = 0;
                        return MI_ERR;
                }
        res = ReadRawRC(TReloadRegL);
        if(res!=30)
                {
                        res = 0;
                        return MI_ERR;
                }               
        res = ReadRawRC(TReloadRegH);
        if(res!=0)
                {
                        res = 0;
                        return MI_ERR;
                }       
        res = ReadRawRC(TModeReg);
        if(res!=0x8D)
                {
                        res = 0;
                        return MI_ERR;
                }
        res = ReadRawRC(TPrescalerReg);
        if(res!=0x3e)
                {
                        res = 0;
                        return MI_ERR;
                }
        res = ReadRawRC(TxAutoReg);
        if(res!=0x40)
                {
                        res = 0;
                        return MI_ERR;
                }
   return MI_OK;

 }
 
 char M500PcdConfigISOType ( unsigned char ucType )
 {
   if ( ucType == 'A')					   //ISO14443_A
	{
	   ClearBitMask ( Status2Reg, 0x08 );	 
	   WriteRawRC ( ModeReg, 0x3D );		 //3F	 
	   WriteRawRC ( RxSelReg, 0x86 );		 //84	 
	   WriteRawRC( RFCfgReg, 0x7F );		 //4F	 
	   WriteRawRC( TReloadRegL, 30 );			 
	   WriteRawRC ( TReloadRegH, 0 );	 
	   WriteRawRC ( TModeReg, 0x8D );	 
	   WriteRawRC ( TPrescalerReg, 0x3E );	 
	   usleep(10000);	 
	   PcdAntennaOn ();//开天线	 
	} 
	else
	{
	   return MI_ERR;
	}
	return MI_OK;	
 }
 
 char PcdComMF522 ( unsigned char ucCommand, unsigned char * pInData, unsigned char ucInLenByte, unsigned char * pOutData,unsigned int * pOutLenBit )	 
 {
   char cStatus = MI_ERR;
   unsigned char ucIrqEn   = 0x00;
   unsigned char ucWaitFor = 0x00;
   unsigned char ucLastBits;
   unsigned char ucN;
   unsigned int ul;
 
   switch ( ucCommand )
   {
	  case PCD_AUTHENT: 	 //Mifare认证
		 ucIrqEn   = 0x12;	 //允许错误中断请求ErrIEn  允许空闲中断IdleIEn
		 ucWaitFor = 0x10;	 //认证寻卡等待时候 查询空闲中断标志位
		 break;
	  
	  case PCD_TRANSCEIVE:	 //接收发送 发送接收
		 ucIrqEn   = 0x77;	 //允许TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
		 ucWaitFor = 0x30;	 //寻卡等待时候 查询接收中断标志位与 空闲中断标志位
		 break;
	  
	  default:
		break;	   
   }
   //IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反 
   WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 );
   //Set1该位清零时,CommIRqReg的屏蔽位清零
   ClearBitMask ( ComIrqReg, 0x80 );  
   //写空闲命令
   WriteRawRC ( CommandReg, PCD_IDLE ); 	
   
   //置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除
   SetBitMask ( FIFOLevelReg, 0x80 );	   
 
   for ( ul = 0; ul < ucInLenByte; ul ++ )
   {
	   WriteRawRC ( FIFODataReg, pInData [ ul ] ); //写数据进FIFOdata
   }
	 
   WriteRawRC ( CommandReg, ucCommand );		 //写命令
 
   if ( ucCommand == PCD_TRANSCEIVE )
   {  
	   //StartSend置位启动数据发送 该位与收发命令使用时才有效
	   SetBitMask(BitFramingReg,0x80);			 
   }
 
   ul = 1000;							  //根据时钟频率调整,操作M1卡最大等待时间25ms
 
   do									  //认证 与寻卡等待时间 
   {
		ucN = ReadRawRC ( ComIrqReg );	  //查询事件中断
		ul --;
   } while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) ); 
 
   ClearBitMask ( BitFramingReg, 0x80 );  //清理允许StartSend位


   if ( ul != 0 )
   {
	 //读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr
	 if ( ! ( ReadRawRC ( ErrorReg ) & 0x1B ) )  
	 {
	   cStatus = MI_OK;
	   
	   if ( ucN & ucIrqEn & 0x01)		 //是否发生定时器中断 -----01
	   
			cStatus = MI_NOTAGERR; 
	    
		 
	   if ( ucCommand == PCD_TRANSCEIVE )
	   {
		 //读FIFO中保存的字节数
		 ucN = ReadRawRC ( FIFOLevelReg );			   
		 
		 //最后接收到得字节的有效位数
		 ucLastBits = ReadRawRC ( ControlReg ) & 0x07; 
		 
		 if ( ucLastBits )
		   
		   //N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数
		   * pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits;    
		 else
		   * pOutLenBit = ucN * 8;		//最后接收到的字节整个字节有效
		 
		 if ( ucN == 0 )   
		   ucN = 1;    
		 
		 if ( ucN > MAXRLEN )
		   ucN = MAXRLEN;	
		 
		 for ( ul = 0; ul < ucN; ul ++ )
		   pOutData [ ul ] = ReadRawRC ( FIFODataReg );   
		 
		 }		  
	 }	 
	 else{

	 	  cStatus = MI_ERR;	   
	 	}
   }
 
   SetBitMask ( ControlReg, 0x80 ); 		  // stop timer now
   WriteRawRC ( CommandReg, PCD_IDLE ); 
	
   return cStatus;
 }
 
 char PcdRequest (unsigned char ucReq_code, unsigned char * pTagType)
 {
   char cStatus;  
   unsigned char ucComMF522Buf [ MAXRLEN ]; 
   unsigned int ulLen;

 
   //清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况
   ClearBitMask ( Status2Reg, 0x08 );

   //发送的最后一个字节的 七位
   WriteRawRC ( BitFramingReg, 0x07 );

 
   //ClearBitMask ( TxControlReg, 0x03 );  
   //TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号
   //usleep(10000); 
   
	SetBitMask ( TxControlReg, 0x03 );  
 
   ucComMF522Buf [ 0 ] = ucReq_code;   //存入 卡片命令字
 
   cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf,& ulLen );  //寻卡  
 
   if ( ( cStatus == MI_OK ) && ( ulLen == 0x10 ) )  //寻卡成功返回卡类型 
   {	
	  * pTagType = ucComMF522Buf[0];
	  * ( pTagType + 1 ) = ucComMF522Buf[1];
   }
   else
   {
	   cStatus = MI_ERR;
   }
 
   return cStatus;	
 }
 
 char PcdAnticoll ( unsigned char * pSnr )
 {
   char cStatus;
   unsigned char uc, ucSnr_check = 0;
   unsigned char ucComMF522Buf [ MAXRLEN ]; 
   unsigned int ulLen;
   
   //清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
   ClearBitMask ( Status2Reg, 0x08 );
   //清理寄存器 停止收发
   WriteRawRC ( BitFramingReg, 0x00);  
   //清ValuesAfterColl所有接收的位在冲突后被清除
   ClearBitMask ( CollReg, 0x80 );		 
  
   ucComMF522Buf [ 0 ] = 0x93;			 //卡片防冲突命令
   ucComMF522Buf [ 1 ] = 0x20;
  
   cStatus = PcdComMF522 ( PCD_TRANSCEIVE, 
						   ucComMF522Buf,
						   2, 
						   ucComMF522Buf,
						   & ulLen);	  //与卡片通信
 
   if ( cStatus == MI_OK)				 //通信成功
   {
	 for ( uc = 0; uc < 4; uc ++ )
	 {
		* ( pSnr + uc )  = ucComMF522Buf [ uc ]; //读出UID
		ucSnr_check ^= ucComMF522Buf [ uc ];
	 }
	 
	 if ( ucSnr_check != ucComMF522Buf [ uc ] )
	   cStatus = MI_ERR;			
   }
   
   SetBitMask ( CollReg, 0x80 );
	   
   return cStatus;	 
 }
 
 void CalulateCRC ( unsigned char * pIndata, unsigned char ucLen, unsigned char * pOutData )
 {
   unsigned char uc, ucN;
 
   ClearBitMask(DivIrqReg,0x04);
 
   WriteRawRC(CommandReg,PCD_IDLE);
 
   SetBitMask(FIFOLevelReg,0x80);
 
   for ( uc = 0; uc < ucLen; uc ++)
	 WriteRawRC ( FIFODataReg, * ( pIndata + uc ) );   
 
   WriteRawRC ( CommandReg, PCD_CALCCRC );
 
   uc = 0xFF;
 
   do 
   {
	   ucN = ReadRawRC ( DivIrqReg );
	   uc --;
   } while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );
   
   pOutData [ 0 ] = ReadRawRC ( CRCResultRegL );
   pOutData [ 1 ] = ReadRawRC ( CRCResultRegM );   
 }
 
 char PcdSelect ( unsigned char * pSnr )
 {
   char ucN;
   unsigned char uc;
   unsigned char ucComMF522Buf [ MAXRLEN ]; 
   unsigned int  ulLen;
   
   
   ucComMF522Buf [ 0 ] = PICC_ANTICOLL1;
   ucComMF522Buf [ 1 ] = 0x70;
   ucComMF522Buf [ 6 ] = 0;
 
   for ( uc = 0; uc < 4; uc ++ )
   {
	 ucComMF522Buf [ uc + 2 ] = * ( pSnr + uc );
	 ucComMF522Buf [ 6 ] ^= * ( pSnr + uc );
   }
   
   CalulateCRC ( ucComMF522Buf, 7, & ucComMF522Buf [ 7 ] );
 
   ClearBitMask ( Status2Reg, 0x08 );
 
   ucN = PcdComMF522 ( PCD_TRANSCEIVE,
					  ucComMF522Buf,
					  9,
					  ucComMF522Buf, 
					  & ulLen );
   
   if ( ( ucN == MI_OK ) && ( ulLen == 0x18 ) )
	 ucN = MI_OK;  
   else
	 ucN = MI_ERR;	  
   
   return ucN;	 
 }
 
 char PcdAuthState ( unsigned char ucAuth_mode, unsigned char ucAddr, unsigned char * pKey, unsigned char * pSnr )
 {
   char cStatus;
   unsigned char uc, ucComMF522Buf [ MAXRLEN ];
   unsigned int ulLen;
   
   ucComMF522Buf [ 0 ] = ucAuth_mode;
   ucComMF522Buf [ 1 ] = ucAddr;
 
   for ( uc = 0; uc < 6; uc ++ )
	 ucComMF522Buf [ uc + 2 ] = * ( pKey + uc );   
 
   for ( uc = 0; uc < 6; uc ++ )
	 ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc );   
 
   cStatus = PcdComMF522 ( PCD_AUTHENT,
						   ucComMF522Buf, 
						   12,
						   ucComMF522Buf,
						   & ulLen );

	printf("cStatus1:%d\n",cStatus);
   if ( ( cStatus != MI_OK ) || ( ! ( ReadRawRC ( Status2Reg ) & 0x08 ) ) )
	 cStatus = MI_ERR;	 

   return cStatus;
 }
 
 char PcdWrite ( unsigned char ucAddr, unsigned char * pData )
 {
   char cStatus;
   unsigned char uc, ucComMF522Buf [ MAXRLEN ];
   unsigned int ulLen;
	
   
   ucComMF522Buf [ 0 ] = PICC_WRITE;
   ucComMF522Buf [ 1 ] = ucAddr;
 
   CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
 
   cStatus = PcdComMF522 ( PCD_TRANSCEIVE,
						   ucComMF522Buf,
						   4, 
						   ucComMF522Buf,
						   & ulLen );

   if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || 
		  ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
	 cStatus = MI_ERR;	
	   
   if ( cStatus == MI_OK )
   {
	 //memcpy(ucComMF522Buf, pData, 16);
	 for ( uc = 0; uc < 16; uc ++ )
	   ucComMF522Buf [ uc ] = * ( pData + uc );  
	 
	 CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );
 
	 cStatus = PcdComMF522 ( PCD_TRANSCEIVE,
							ucComMF522Buf, 
							18, 
							ucComMF522Buf,
							& ulLen );
	 
	 if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || 
		  ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
	   cStatus = MI_ERR;   
	 
   }   
   return cStatus;	 
 }
 
 char PcdRead ( unsigned char ucAddr, unsigned char * pData )
 {
   char cStatus;
   unsigned char uc, ucComMF522Buf [ MAXRLEN ]; 
   unsigned int ulLen;
   
   ucComMF522Buf [ 0 ] = PICC_READ;
   ucComMF522Buf [ 1 ] = ucAddr;
 
   CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
  
   cStatus = PcdComMF522 ( PCD_TRANSCEIVE,
						   ucComMF522Buf,
						   4, 
						   ucComMF522Buf,
						   & ulLen );
 
   if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) )
   {
	 for ( uc = 0; uc < 16; uc ++ )
	   * ( pData + uc ) = ucComMF522Buf [ uc ];  

   }
   
   else
	 cStatus = MI_ERR;	 
	
   return cStatus;	 
 }
 
 char PcdHalt( void )
 {
   unsigned char ucComMF522Buf [ MAXRLEN ]; 
   unsigned int  ulLen;
   
 
   ucComMF522Buf [ 0 ] = PICC_HALT;
   ucComMF522Buf [ 1 ] = 0;
   
	CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
   PcdComMF522 ( PCD_TRANSCEIVE,
				 ucComMF522Buf,
				 4, 
				 ucComMF522Buf, 
				 & ulLen );
 
   return MI_OK; 
 }
 
 int main(int argc, const char * argv [ ])
 {
	int ret = -1;
	char buf[1];
   unsigned char KeyValue[]={0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF};	// 卡A密钥
   char cStr [ 30 ], writebuf[16] = {0x12,0x34,0x56,0x78,0xaa,0x22,0x33,0x44}, readbuf[16];
   unsigned char ucArray_ID [ 4 ];	  /*先后存放IC卡的类型和UID(IC卡序列号)*/																						   
   unsigned char ucStatusReturn, snr;	   /*返回状态*/ 	
	 
	snr = 3; //扇区号
   ret = PcdReset();
   if(ret != MI_OK)
   {
		 printf("rc522 rst error %d \n",ret);
	   return 0;
   }
   ucStatusReturn = M500PcdConfigISOType ( 'A' );
	if(ucStatusReturn == MI_ERR)
	{
	   printf("M500PcdConfigISOType error! \n");
	}
	else
	{
	   printf("M500PcdConfigISOType normal! \n");
	}

	while(1)
	{		
		  ucStatusReturn = PcdRequest ( PICC_REQIDL, ucArray_ID ); 
		  if ( ucStatusReturn == MI_OK )  
		  {
		  	printf("ucStatusReturn == MI_OK\n");
			 if ( PcdAnticoll ( ucArray_ID ) == MI_OK )  
			 {
			 	printf("PcdAnticoll ( ucArray_ID ) == MI_OK\n");
				   PcdSelect(ucArray_ID);	   // 选卡 
				   ucStatusReturn = PcdAuthState(KEYA, (snr*4 + 3) , KeyValue, ucArray_ID );//校验密码 
				   if(ucStatusReturn !=  MI_OK)
				   {
						printf("rc522 card number err!\r\n");
				   }
				   else
				   {						 
						sprintf(cStr, "The Card ID is: %02X%02X%02X%02X",ucArray_ID [0], ucArray_ID [1], ucArray_ID [2],ucArray_ID [3]);
						printf("%s\r\n",cStr);  //打印卡片ID 
				   }
 	
				  	if(PcdWrite((snr*4 + 0) , writebuf) == MI_OK)
		
				   {
					  printf("PcdWrite Success! \r\n");
				   }
				   	   else
				   {
					  printf("PcdWrite err! \r\n");
				   }
 
				   if(PcdRead((snr*4 + 0) , readbuf) == MI_OK)

				   {
					  print_data("read block", readbuf, 16);			
				   }
				   else
				   {
					  printf("PcdRead err! \r\n");
				   }
			 } 
			 else
			 {
				PcdHalt();
			 }										 
		  }
		   
	}
 
	return 0; 
 }


程序头文件

#ifndef _SPI_RC522_H
#define _SPI_RC522_H

#define PCD_IDLE              0x00               
#define PCD_AUTHENT           0x0E               
#define PCD_RECEIVE           0x08               
#define PCD_TRANSMIT          0x04               
#define PCD_TRANSCEIVE        0x0C               
#define PCD_RESETPHASE        0x0F               
#define PCD_CALCCRC           0x03               

#define PICC_REQIDL           0x26              
#define PICC_REQALL           0x52               
#define PICC_ANTICOLL1        0x93               
#define PICC_ANTICOLL2        0x95               
#define PICC_AUTHENT1A        0x60              
#define PICC_AUTHENT1B        0x61             
#define PICC_READ             0x30              
#define PICC_WRITE            0xA0               
#define PICC_DECREMENT        0xC0               
#define PICC_INCREMENT        0xC1              
#define PICC_RESTORE          0xC2              
#define PICC_TRANSFER         0xB0              
#define PICC_HALT             0x50              

#define DEF_FIFO_LENGTH       64                 

// PAGE 0
#define RFU00                   (0x00)      // 保留
#define CommandReg              (0x01)      // 启动和停止
#define ComIEnReg               (0x02)      // 中断请求传递的使能和失能控制位
#define DivlEnReg               (0x03)      // 中断请求传递的使能和失能控制位
#define ComIrqReg               (0x04)      // 包含中断请求标志
#define DivIrqReg               (0x05)      // 包含中断请求标志
#define ErrorReg                (0x06)      // 错误标志,指示执行的上个命令的错误状态
#define Status1Reg              (0x07)      // 包含通信的状态标志
#define Status2Reg              (0x08)      // 包含接收器和发送器的状态标志
#define FIFODataReg             (0x09)      // 64 字节 FIFO 缓冲区的输入和输出
#define FIFOLevelReg            (0x0A)      // 指示 FIFO 中存储的字节数
#define WaterLevelReg           (0x0B)      // 定义 FIFO 下溢和上溢报警的 FIFO 深度
#define ControlReg              (0x0C)      // 不同的控制寄存器
#define BitFramingReg           (0x0D)      // 面向位的帧的调节
#define CollReg                 (0x0E)      // RF 接口上检测到的第一位冲突的位的位置
#define RFU0F                   (0x0F)      // 保留
/* PAGE 1 */
#define RFU10                   (0x10)      // 保留用于未来使用
#define ModeReg                 (0x11)      // 定义发送和接收的常用模式
#define TxModeReg               (0x12)      // 定义发送过程中的数据传输速率
#define RxModeReg               (0x13)      // 定义接收过程中的数据传输速率
#define TxControlReg            (0x14)      // 控制天线驱动管脚 TX1 和 TX2 的逻辑特性
#define TxAutoReg               (0x15)      // 控制天线驱动器的设置
#define TxSelReg                (0x16)      // 控制天线驱动器的内部源
#define RxSelReg                (0x17)      // 选择内部的接收器
#define RxThresholdReg          (0x18)      // 选择位译码器的阀值
#define DemodReg                (0x19)      // 定义调节器的设置
#define RFU1A                   (0x1A)      // 保留用于未来使用
#define RFU1B                   (0x1B)      // 保留用于未来使用
#define MifareReg               (0x1C)      // 控制 ISO 14443/MIFARE 模式中 106kbit/s 的通信
#define RFU1D                   (0x1D)      // 保留用于未来使用
#define RFU1E                   (0x1E)      // 保留用于未来使用
#define SerialSpeedReg          (0x1F)      // 选择串行 UART 接口的速率
/* PAGE 2 */
#define RFU20                   (0x20)      // 保留用于未来使用
#define CRCResultRegM           (0x21)      // 显示 CRC 计算的实际 MSB 值
#define CRCResultRegL           (0x22)      // 显示 CRC 计算的实际 LSB 值
#define RFU23                   (0x23)      // 保留用于未来使用
#define ModWidthReg             (0x24)      // 控制 ModWidth 的设置
#define RFU25                   (0x25)      // 保留用于未来使用
#define RFCfgReg                (0x26)      // 配置接收器增益
#define GsNReg                  (0x27)      // 选择天线驱动器管脚 TX1 和 TX2 的调制电导
#define CWGsCfgReg              (0x28)      // 选择天线驱动器管脚 TX1 和 TX2 的调制电导
#define ModGsCfgReg             (0x29)      // 选择天线驱动器管脚 TX1 和 TX2 的调制电导
#define TModeReg                (0x2A)      // 定义内部定时器的设置
#define TPrescalerReg           (0x2B)      // 定义内部定时器的设置
#define TReloadRegH             (0x2C)      // 描述 16 位长的定时器重装值
#define TReloadRegL             (0x2D)      // 描述 16 位长的定时器重装值
#define TCounterValueRegH       (0x2E)      // 显示 16 位长的实际定时器值
#define TCounterValueRegL       (0x2F)      // 显示 16 位长的实际定时器值
/* PAGE 3 */
#define RFU30                   (0x30)      // 保留用于未来使用
#define TestSel1Reg             (0x31)      // 常用测试信号的配置
#define TestSel2Reg             (0x32)      // 常用测试信号的配置和 PRBS 控制
#define TestPinEnReg            (0x33)      // D1-D7 输出驱动器的使能管脚(仅用于串行接口)
#define TestPinValueReg         (0x34)      // 定义 D1-D7 用作 I/O 总线时的值
#define TestBusReg              (0x35)      // 显示内部测试总线的状态
#define AutoTestReg             (0x36)      // 控制数字自测试
#define VersionReg              (0x37)      // 显示版本
#define AnalogTestReg           (0x38)      // 控制管脚 AUX1 和 AUX2
#define TestDAC1Reg             (0x39)      // 定义 TestDAC1 的测试值
#define TestDAC2Reg             (0x3A)      // 定义 TestDAC2 的测试值
#define TestADCReg              (0x3B)      // 显示 ADC I 和 Q 通道的实际值
#define RFU3C                   (0x3C)      // 保留用于产品测试
#define RFU3D                   (0x3D)      // 保留用于产品测试
#define RFU3E                   (0x3E)      // 保留用于产品测试
#define RFU3F		            (0x3F)      // 保留用于产品测试



#define     REQ_ALL               0x52
#define     KEYA                  0x60
#define     KEYB                  0x61


#define MI_OK                          (char)0
#define MI_NOTAGERR                    (char)(-1)
#define MI_ERR                         (char)(-2)

#endif

如果遇到寄存器读写失败,可以在读写后加上延时函数

所遇到的问题 

由于一开始在网上下载的实例程序读写的是扇区1,但是一直都是读写失败,后来试了其他的区域进行读写显示成功,导致耽误很多时间,现在读写扇区1时也是不行,希望有了解的大佬可以解决一下。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值