硬件平台:

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. {
  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,结果模块可以正常工作了。

                                          (转载)

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

  1. Linux Canbus调试笔记

    STM32之CAN---错误管理分析      牛人博客 http://blog.csdn.net/flydream0/article/details/8161418 CAN总线在嵌入式Linux下驱 ...

  2. HI35xx平台调试笔记

    1.音视频数据循环采集 a. 在sample_venc.c文件中,海思官方是把采集到的数据都保存到文件中,我们需要更改到缓存里,以便后面推送到rtsp/rtmp/hls服务端. ; i < s3 ...

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

    简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中.接着,在Ubuntu上为Android系统编写Linux内核驱动程序(老罗学习笔记1)一文中举例子说明了如何在 ...

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

    Linux平台MYSQL的C语言API全列表 - 第三只眼的专栏 - 博客频道 - CSDN.NET - Google Chrome (2013/8/18 22:28:58)   Linux平台MYS ...

  5. 在 Linux 平台中调试 C/C++ 内存泄漏方法(转)

    由于 C 和 C++ 程序中完全由程序员自主申请和释放内存,稍不注意,就会在系统中导入内存错误.同时,内存错误往往非常严重,一般会带来诸如系统崩溃,内存耗尽这样严重的后果.本文将从静态分析和动态检测两 ...

  6. linux 下camera调试笔记【转】

    转自:https://blog.csdn.net/kevinx_xu/article/details/8801931 linux camera调试 2011-10-23 10:43:37|  分类:  ...

  7. linux内核调试指南

    linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 ...

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

    http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级 ...

  9. USB wifi调试笔记

    本文以realtek 8192CU WiFi模块为例,介绍USB wifi在Jelly Bean 4.1的调试笔记. 1.WIFI打不开现象概述 WiFi打不开是指您在UI的settings下选中Wi ...

随机推荐

  1. 【Mysql】 case ... when ... 用法

    sql语句查询时给某个空字段赋值 SELECT CASE WHEN field= '' THEN ' WHEN fieldIS NULL THEN ' ELSE field END FROM tabl ...

  2. C++ 初始化函数的实现

    http://www.cppblog.com/xlshcn/archive/2007/11/21/37088.aspx

  3. Python老王视频习题答案

    基础篇2:一切变量都是数据对象的引用sys.getrefcount('test') 查看引用计数变量命名不能以数字开头编码:ascii.unicode.utf-81.阅读str对象的help文档,并解 ...

  4. mysql查杀会话

    root登陆mysql,查看会话(show processlist\G;): mysql> kill

  5. thinkphp---数据表更新字段开发模式可更新生产模式不能更新!

    这里认为是坑的主要原因:这个问题我调试了一天,才发现是缓存的问题. 问题原因:在做一thinkphp的项目,在后期要进行修改.修改的时候,数据表里面添加了两个字段,然后前台修改模板,将添加的字段提交上 ...

  6. angular -- get请求该如何使用?

    在做 angualr 的开发过程中,经常会用到的就是 ajax 请求.下面是 get 请求示例: 如果存在多个 get 请求可以考虑进行封装下: // get 携参数访问 ajaxGet(getUrl ...

  7. 170725、Kafka原理与技术

    本文转载自:http://www.linkedkeeper.com/detail/blog.action?bid=1016 Kafka的基本介绍 Kafka最初由Linkedin公司开发,是一个分布式 ...

  8. Guava增强for循环

    Guava的前身是Google Collections,是Google开发出的一个开源Java常用类库,包含了一些集合的便捷操作API.本文通过一些常用的例子来剖析Guava的奇妙之处. Guava是 ...

  9. PL/SQL编程基础(一):PL/SQL语法简介(匿名PL/SQL块)

    PL/SQL PL/SQL是Oracle在关系数据库结构化查询语言SQL基础上扩展得到的一种过程化查询语言. SQL与编程语言之间的不同在于,SQL没有变量,SQL没有流程控制(分支,循环).而PL/ ...

  10. 【asm】64位编译32位汇编需要注意的

    汇编语言在32位和64位下有区别    32位的汇编在代码前增加.code32    as可以通过--32指定生成32位汇编 在64位系统下ld链接生成32位程序:    ld: i386 archi ...