RC 522模块在LINUX平台调试笔记

来源:互联网 发布:matlab计算矩阵行列式 编辑:程序博客网 时间:2024/05/01 22:09

硬件平台:

1 主控:SMDK Exynos4412 POP S5M8767A

2 RFID模块:君盾集团提供的RC522模块

3 通信接口:SPI

软件平台:Android ICS & kernel version 3.0.15

 

一,使能主控端SPI

1 硬件使能:

从SMDK原理图上可以看到SPI0与I2C共用,SPI1已经连接到其它设备,SPI2未用,故这里选用SPI2。

 

2 软件使能:

SMDK Exynos4412 主控端已经配置好了SPI接口,使用时只需打开宏CONFIG_S3C64XX_DEV_SPI即可。

         打开方式:make menuconfigàDevice DriversàSPI supportàSamsung S3C64XX series type SPI.

编译后生成zImage,烧录进开发板。

 

二,测试主控端SPI

主控端SPI已经打开,接下来可以用一个通用的SPI驱动来测试主控端SPI硬件是否能正常工作。

以模块的方式编译:drivers/spi/spidev.c,生成spidev.ko,便是通用的设备端SPI驱动程序。

编译测试程序:Documentation/spi/spidev_test.c,先修改第32行: static const char *device = "/dev/spidev1.1"的设备为“/dev/spidev2.0”,然后再以应用程序的方式来编译,生成spidev_test,即为对应SPI的测试程序。

通过串口,赋予root权限和系统可读写权限:

shell@android:/ $ su root

shell@android:/ # mount -o remount -rw /system

[  391.423930] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)

shell@android:/ #

通过adb把spidev.ko和spidev_test push到开发板:

 

加载驱动:

shell@android:/system # insmod spidev.ko

把MISO和MOSI短路,即自发自收,然后再执行测试程序:

 

如上图所示,说明能通过SPI收发数据;如果全部显示为0,则说明SPI未正常工作。接下来可以放心地去调试我们的RC522模块了。

 

三,RC522设备端驱动调试

上面的实验已经证明了主控的SPI可以正常工作,接下来可以正式调试RC522了。――这里假设你的rfid_rc522驱动已经写好,现在只需要去调试――如果驱动没有写好,请看另一篇Blog。

1 打开与开发板相关的文件:arch/arm/mach-exynos/mach-smdk4x12.c

由于使用的spi2,故要修改board_info里的modalias = “rfid_rc522”,与驱动里的spi_drviver.name相匹配,否则probe函数不成功。

 

点击(此处)折叠或打开

  1. 988 static struct spi_board_info spi2_board_info[] __initdata = { 
  2.  989 { 
  3.  990 .modalias = "rfid_rc522", 
  4.  991 .platform_data = NULL, 
  5.  992 .max_speed_hz = 10*1000*1000, 
  6.  993 .bus_num = 2, 
  7.  994 .chip_select = 0, 
  8.  995 .mode = SPI_MODE_0, 
  9.  996 .controller_data = &spi2_csi[0], 
  10.  997 } 
  11.  998 };


2 重新编译内核,并烧录到开发板。

 

3 编译rc522驱动程序,并通过adb usb把生成的rfid_rc522.ko copy到开发板系统的/system目录下,然后 insmod rfid_rc522.ko, 这样驱动就以模块的形式加载进了内核系统。加载成功后,在/dev 目录下就会有rfid_rc522_dev这个目录。

 

 

四,应用程序

驱动中的write函数为:

rc522_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos);

用户空间的应用程序write函数为:

write(rc522_fd, bufpw1, sizeof(bufpw1));

二者如何联系的呢?

其实应用程序中的write函数通过调用操作系统中的核心函数sys_write(unsigned int fd, const char * buf, size_t count)来实现,而sys_write()函数又对驱动中的rc522_write()进行了封装。

//摘自论坛开始

下面以字符设备驱动来具体说明:

1,insmod驱动程序。驱动程序申请次设备名和主设备号,这些可以在/proc/devieces中获得。

2,从/proc/devices中获得主设备号,并使用mknod命令建立设备节点文件。这是通过主设备号将设备节点文件和设备驱动程序联系在一起。设备节点文件中的file属性中指明了驱动程序中fops方法实现的函数指针。

3,用户程序使用open打开设备节点文件,这时操作系统内核知道该驱动程序工作了,就调用fops方法中的open函数进行相应的工作。open方法一般返回的是文件标示符,实际上并不是直接对它进行操作的,而是有操作系统的系统调用在背后工作。

4,当用户使用write函数操作设备文件时,操作系统调用sys_write函数,该函数首先通过文件标示符得到设备节点文件对应的inode指针和flip指针。inode指针中有设备号信息,能够告诉操作系统应该使用哪一个设备驱动程序,flip指针中有fops信息,可以告诉操作系统相应的fops方法函数在那里可以找到。

5,然后这时sys_write才会调用驱动程序中的write方法来对设备进行写的操作。

其中1-3都是在用户空间进行的,4-5是在内核空间进行的。用户的write函数和操作系统的write函数通过系统调用sys_write联系在了一起。

注意:

对于块设备来说,还存在写的模式的问题,这应该是由GNU C库来解决的,这里不予讨论,因为我没有看过GNU C库的源代码。

//摘自论坛结束

 

         应用程序源码如下:

 

 

点击(此处)折叠或打开

  1. #include <stdio.h> 
  2. #include <string.h> 
  3. #include <stdlib.h> 
  4. #include <sys/types.h> 
  5. #include <unistd.h> 
  6. #include <errno.h> 
  7. #include <arpa/inet.h> 
  8. #include <sys/time.h> 
  9. #include <sys/types.h> 
  10. #include <sys/stat.h> 
  11. #include <fcntl.h> 
  12. #include <sys/ioctl.h> 
  13. #include <math.h> 
  14. static enum IO_CMD { 
  15.     READ_CARD = 0, 
  16.     CHANGE_PASSWD = 1, 
  17.     CHANGE_BLOCK = 3, 
  18.     SET_RW_TIME = 4, 
  19.     WRITE_CARD = 5, 
  20. }; 
  21. int main(int argc, char** argv) 
  22.          int rc522_fd; 
  23.          int i, read_num; 
  24.          char r[256]; 
  25.          printf("test: rc522 %s %s\n", __DATE__, __TIME__); 
  26.          
  27.          printf("test: before open rc522_fd\n"); 
  28.          rc522_fd = open("/dev/rfid_rc522_dev", O_RDWR); 
  29.          
  30.          printf("test: rc522_fd=%d\n", rc522_fd); 
  31.          if(rc522_fd == -1) 
  32.          { 
  33.                    printf("test: Error Opening rc522\n"); 
  34.                    return(-1); 
  35.          } 
  36. printf("test: wait 01\n"); 
  37.          sleep(1); //wait 
  38. printf("test: wait 02\n"); 
  39. /******* Never to open ********/ 
  40. #if 0 
  41. // change password as:020202020202 
  42.          ioctl(rc522_fd, CHANGE_BLOCK, 0);//参数3:选第0块 
  43.          ioctl(rc522_fd, CHANGE_PASSWD, 0); 
  44.          char bufpw1[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; 
  45.          
  46.          write(rc522_fd, bufpw1, sizeof(bufpw1)); 
  47. #endif 
  48.          ioctl(rc522_fd, CHANGE_BLOCK, 0);//参数3:选第0块 
  49.          ioctl(rc522_fd, READ_CARD, 0);//参数3没用 
  50.          for(i = 0; i < 3; i++) //读三次卡号 
  51.          { 
  52.                             read_num = read(rc522_fd, r, 0); 
  53.                             printf("test: i=%d read_num=%d ", i, read_num); 
  54.                             if(read_num > 0){ 
  55.                                      printf("r=[0x%.2X]", r[0]); 
  56.                             } 
  57.                             
  58.                             printf("\n"); 
  59.                             sleep(1); 
  60.          } 
  61.          
  62. // write something to the card 
  63.          ioctl(rc522_fd, CHANGE_BLOCK, 1);//参数3:选第2块 
  64.          ioctl(rc522_fd, WRITE_CARD, 1); 
  65.          printf("before write card!\n"); 
  66.          
  67.          char buf[11] = "186653803xx"; 
  68.          if(write(rc522_fd, buf,sizeof(buf))) 
  69.          { 
  70.                    printf("write error\n"); 
  71.          } 
  72. // read block[1], just writed with 
  73.          ioctl(rc522_fd, CHANGE_BLOCK, 1);//参数3:选第1块 
  74.          ioctl(rc522_fd, READ_CARD, 0);//参数3没用 
  75.          read_num = read(rc522_fd, r, 0); 
  76.          printf("read block[1]\n\n\n The number you just writed is: %s\n\n\n", r); 
  77.          printf("test: close rc522_fd\n"); 
  78.          close(rc522_fd); 
  79.          printf("test: exit rc522_fd\n"); 
  80.          return 0; 
  81. }


应用程序编译的Makefile 如下:

 

 

点击(此处)折叠或打开

  1. # Comment/uncomment the following line to disable/enable debugging 
  2. #DEBUG = y 
  3. DEST_BIN_DIR= drivers/ 
  4. EXTRA_CFLAGS += -D_V3 
  5. #TESTFLAGS = -D_V3 
  6. # Add your debugging flag (or not) to CFLAGS 
  7. ifeq ($(DEBUG),y) 
  8.   DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines 
  9. else 
  10.   DEBFLAGS = -O2 
  11. endif 
  12. EXTRA_CFLAGS += $(DEBFLAGS) 
  13. EXTRA_CFLAGS += -I$(LDDINC) 
  14. EXTRA_CFLAGS += -DREV_VERSION=$(REV_VERSION) 
  15. LDFLAGS += --static 
  16. all: test 
  17. clean: 
  18.          rm -rf test_rc522 
  19.          
  20. cp: 
  21.          cp -f test_rc522 $(DEST_BIN_DIR) 
  22. mv: 
  23.          mv -f test_rc522 $(DEST_BIN_DIR) 
  24. test: 
  25.          arm-linux-gcc $(CFLAGS) $(LDFLAGS) -O2 test_rc522.c -o test_rc522 
  26. depend .depend dep: 
  27.          $(CC) $(CFLAGS) -M *.c > .depend 
  28. ifeq (.depend,$(wildcard .depend)) 
  29. include .depend 
  30. endif


测试时,把卡靠近RC522的天线区域,即可正常读到卡ID。

 

 

 

五,总结

本次调试比较顺利,遇到几个比较大的问题如下:

1 SMDK开发板SPI0通信有问题,开始一直以为驱动的问题,也不知道应该如何测试开发板SPI接口是否OK,在网上找了一些资料后发现SPI驱动可以通过内核自带的驱动模块和应用程序进行测试。

2 应用程序(测试程序)无法在开发板系统上运行,原因是链接库未设置成静态。

3 RC522中的VCC供电需要3.3V,MOSI,CLK等TTL高电平也是3.3V。但4412主控的GPIO输出的高电平全部是1.8V,故模块无法正常工作。由于是调试,故不可能加一个TTL电平转换的IC了。后来试着把VCC调低到2.6V,结果模块可以正常工作了。

 

                                          (转载)

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 齐鲁医院挂的号晚了怎么办 手机微信安装后注册失败怎么办 舞蹈基本功胸怎么都转不动怎么办 饥荒手机版第10天遇到的狗怎么办 饥荒海难手游石墙老是放歪怎么办 小燕子从窝里掉下来了怎么办 二岁宝宝晚上睡觉不踏实怎么办 脚扭伤了有点痛但没肿该怎么办 落地扇的机头摇摆的地方坏了怎么办 跌倒在楼梯上右侧肋骨骆上怎么办 1岁3个月害怕自己不敢走路怎么办 苹果手机没开定位丢了怎么办 我和我老婆每天都吵架怎么办 现在在学注册消防师好枯燥怎么办 店铺台阶太高顾客不愿进来怎么办? 上古卷轴5跑步要沉下去怎么办 1岁半宝宝半夜醒来不睡觉怎么办 上古卷轴5不小心偷了东西怎么办 47牙缺失17号长长了怎么办 碎纸机过热件亮了卡住纸了怎么办 汽车买贵了2万多怎么办 宝宝眼皮被蚊子咬肿了怎么办 一岁宝宝撞头咬到舌头有伤口怎么办 二胎快生了老大特别粘人怎么办 生二胎不舍得大宝跟奶奶睡怎么办 怀二胎婆婆不帮忙带孩子怎么办 注册过的高铁用户名忘了怎么办 硕士延期毕业找好的工作怎么办 竞彩足球绑定信用卡提不了现怎么办 qq启动出现问题请卸载重装怎么办 u盘有文件打开后却是空的怎么办 王者荣耀不记得所在的区服怎么办 交易猫出售游戏账号是微信号怎么办 网银密码输错3次怎么办 无线网卡信号很好就是没网速怎么办 红米2a忘了登陆账号怎么办 qq封了密保手机没用了怎么办 乐视手机重置账号密码忘了怎么办 此版本的ios不支持银联怎么办 单反m档拍出来照片是黑色怎么办 从兴趣部落老发骚扰信息怎么办