zoukankan      html  css  js  c++  java
  • RC 522模块在LINUX平台调试笔记

    硬件平台:

    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 ", __DATE__, __TIME__); 
    26.          
    27.          printf("test: before open rc522_fd "); 
    28.          rc522_fd = open("/dev/rfid_rc522_dev", O_RDWR); 
    29.          
    30.          printf("test: rc522_fd=%d ", rc522_fd); 
    31.          if(rc522_fd == -1) 
    32.          { 
    33.                    printf("test: Error Opening rc522 "); 
    34.                    return(-1); 
    35.          } 
    36. printf("test: wait 01 "); 
    37.          sleep(1); //wait 
    38. printf("test: wait 02 "); 
    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(" "); 
    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! "); 
    66.          
    67.          char buf[11] = "186653803xx"; 
    68.          if(write(rc522_fd, buf,sizeof(buf))) 
    69.          { 
    70.                    printf("write error "); 
    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] The number you just writed is: %s ", r); 
    77.          printf("test: close rc522_fd "); 
    78.          close(rc522_fd); 
    79.          printf("test: exit rc522_fd "); 
    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,结果模块可以正常工作了。

                                              (转载)

  • 相关阅读:
    Eclipse生成部署描述符(web.xml)
    异步Servlet和异步过虑器
    安装 R 及 R 包
    Servlet封装类
    设计模式——装饰者模式
    Eclipse快速生成覆盖方法、Getter、Setter的方法
    查看CPU核数和内存
    Filter 过滤器
    Listener 监听器
    Tag file
  • 原文地址:https://www.cnblogs.com/Ph-one/p/4177754.html
Copyright © 2011-2022 走看看