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权限和系统可读写权限:

[email protected]:/ $ su root

[email protected]:/ # mount -o remount -rw /system

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

[email protected]:/ #

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

加载驱动:

[email protected]:/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. {
  23. int rc522_fd;
  24. int i, read_num;
  25. char r[256];
  26. printf("test: rc522 %s %s\n", __DATE__, __TIME__);
  27. printf("test: before open rc522_fd\n");
  28. rc522_fd = open("/dev/rfid_rc522_dev", O_RDWR);
  29. printf("test: rc522_fd=%d\n", rc522_fd);
  30. if(rc522_fd == -1)
  31. {
  32. printf("test: Error Opening rc522\n");
  33. return(-1);
  34. }
  35. printf("test: wait 01\n");
  36. sleep(1); //wait
  37. printf("test: wait 02\n");
  38. /******* Never to open ********/
  39. #if 0
  40. // change password as:020202020202
  41. ioctl(rc522_fd, CHANGE_BLOCK, 0);//参数3:选第0块
  42. ioctl(rc522_fd, CHANGE_PASSWD, 0);
  43. char bufpw1[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
  44. write(rc522_fd, bufpw1, sizeof(bufpw1));
  45. #endif
  46. ioctl(rc522_fd, CHANGE_BLOCK, 0);//参数3:选第0块
  47. ioctl(rc522_fd, READ_CARD, 0);//参数3没用
  48. for(i = 0; i < 3; i++) //读三次卡号
  49. {
  50. read_num = read(rc522_fd, r, 0);
  51. printf("test: i=%d read_num=%d ", i, read_num);
  52. if(read_num > 0){
  53. printf("r=[0x%.2X]", r[0]);
  54. }
  55. printf("\n");
  56. sleep(1);
  57. }
  58. // write something to the card
  59. ioctl(rc522_fd, CHANGE_BLOCK, 1);//参数3:选第2块
  60. ioctl(rc522_fd, WRITE_CARD, 1);
  61. printf("before write card!\n");
  62. char buf[11] = "186653803xx";
  63. if(write(rc522_fd, buf,sizeof(buf)))
  64. {
  65. printf("write error\n");
  66. }
  67. // read block[1], just writed with
  68. ioctl(rc522_fd, CHANGE_BLOCK, 1);//参数3:选第1块
  69. ioctl(rc522_fd, READ_CARD, 0);//参数3没用
  70. read_num = read(rc522_fd, r, 0);
  71. printf("read block[1]\n\n\n The number you just writed is: %s\n\n\n", r);
  72. printf("test: close rc522_fd\n");
  73. close(rc522_fd);
  74. printf("test: exit rc522_fd\n");
  75. return 0;
  76. }

应用程序编译的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. cp:
  20. cp -f test_rc522 $(DEST_BIN_DIR)
  21. mv:
  22. mv -f test_rc522 $(DEST_BIN_DIR)
  23. test:
  24. arm-linux-gcc $(CFLAGS) $(LDFLAGS) -O2 test_rc522.c -o test_rc522
  25. depend .depend dep:
  26. $(CC) $(CFLAGS) -M *.c > .depend
  27. ifeq (.depend,$(wildcard .depend))
  28. include .depend
  29. 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,结果模块可以正常工作了。

                                          (转载)

时间: 2024-10-10 04:26:08

RC 522模块在LINUX平台调试笔记的相关文章

Linux Canbus调试笔记

STM32之CAN---错误管理分析      牛人博客 http://blog.csdn.net/flydream0/article/details/8161418 CAN总线在嵌入式Linux下驱动程序的实现 http://www.21ic.com/app/embed/200911/49216.htm Socke Can设置波特率 找到其中一个方法使用IP命令,BUSYBOX制作的IP好像不支持对socketcan的设置,必须要自己去下载iproute2的源代码自己编译.得到IP命令,拷贝到

LINUX设备驱动程序笔记(二)构造和运行模块

         <一>:设置测试系统 首先准备好一个内核源码树,构造一个新内核,然后安装到自己的系统中.           <二>:HelloWorld模块 #include <linux/init.h> //定义了驱动的初始化和退出相关的函数 #include <linux/module.h> //定义了内核模块相关的函数.变量及宏 MODULE_LICENSE("Dual BSD/GPL"); //该宏告诉内核,该模块采用自由许可

笔记整理--Linux平台MYSQL的C语言

Linux平台MYSQL的C语言API全列表 - 第三只眼的专栏 - 博客频道 - CSDN.NET - Google Chrome (2013/8/18 22:28:58) Linux平台MYSQL的C语言API全列表 2013-02-19 15:17 78人阅读 评论(0) 收藏 举报 1.mysql_affected_rows()            //返回上次UPDATE.DELETE或INSERT查询更改/删除/插入的行数. 2.mysql_autocommit()        

记一次在linux 平台上的优化调试

Author:DriverMonkey Mail:[email protected] Phone:13410905075 QQ:196568501 测试平台:AM335X 优化前状态:采样速度  105次/S 优化目标:速度为 130次/S 以上(注:根据ADC的采样率理论上可以达到 330次/S) 优化步骤: 1)代码框架可分为四大模块(UI, 业务逻辑管理,设备管理,远程管理)共10个线程 模块间有项目依赖关系,不能一下全部停掉,先去掉一些辅助功能线程(如:按键扫描线程,远程命令处理线程等)

Linux netfilter 学习笔记 之十二 ip层netfilter的NAT模块代码分析

本节主要是分析NAT模块相关的hook函数与target函数,主要是理清NAT模块实现的原理等. 1.NAT相关的hook函数分析 NAT模块主要是在NF_IP_PREROUTING.NF_IP_POSTROUTING.NF_IP_LOCAL_OUT.NF_IP_LOCAL_IN四个节点上进行NAT操作,在上一节中我们知道nat表中只有PREROUTING.POSTROUTING.LOCAL_OUT三条链,而没有NF_IP_LOCAL_IN链,所以不能创建在LOCAL_IN hook点的SNAT

嵌入式 Linux 的调试技术读书笔记

对于复杂的 Linux 驱动及 HAL等程序库,需要使用各种方法对其进行调试. 例如,设置断点. 逐步跟踪代码.-输出调试值息等.虽然撒入式Linux在调试方面并没有 Visual Studio. Delphi. Eclipse 这些可视偌工其荒便,但学习一些这方面的技术无疑更奇脚手亮发强款而稳定的 Linux 内核模块对于嵌入式 Linux 俞核模块.可fA,衍程庄. 央事库的调试可能要更复杂一些.因为在失多赞时候需要至 少两台机器开发机和目标机. 在 Linux 文件系统中, /proc 经

在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序(老罗学习笔记3)

在Android硬件抽象层(HAL)概要介绍和学习计划一文中,我们简要介绍了在Android系统为为硬件编写驱动程序的方法.简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中.接着,在Ubuntu上为Android系统编写Linux内核驱动程序一文中举例子说明 了如何在Linux内核编写驱动程序.在这一篇文章中,我们将继续介绍Android系统硬件驱动程序的另一方面实现,即如何在硬件抽象层中增加硬件模块来和内核驱动程序交互.在这篇文章中,我们还将学习到如何在

Linux Kernel - Debug Guide (Linux内核调试指南 )

http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 建立调试环境 发行版的选择和安装 安装交叉编译工具 bin工具集的使用 qemu的使用 initrd.img的原理与制作 x86虚拟调试环境的建立 arm虚拟调试环境的建立 arm开发板调试环

linux内核调试指南

linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 建立调试环境 发行版的选择和安装 安装交叉编译工具 bin工具集的使用 qemu的使用 initrd.img的原理与制作 x86虚拟调试环境的建立 arm虚拟调试环境的建立 arm开发板调试环境的建立 gdb基础 基本命令 gdb之gui gdb技巧 gdb宏 汇编基础--X86篇 用户手册 AT&