zoukankan      html  css  js  c++  java
  • 4412--SPI驱动

    Linux主机驱动和外设驱动分离思想

    SPI驱动总线架构:SPI核心层(x),SPI控制器驱动层(x),SPI设备驱动层(√)

     

    2 Linux SPI驱动总体架构
          在2.6的linux内核中,SPI的驱动架构可以分为如下三个层次:SPI 核心层、SPI控制器驱动层和SPI设备驱动层。
          Linux 中SPI驱动代码位于drivers/spi目录。
    2.1 SPI核心层
          SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线控制器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便SPI设备驱动通过总线控制器进行数据收发。
          Linux中,SPI核心层的代码位于driver/spi/ spi.c。由于该层是平台无关层,本文将不再叙述,有兴趣可以查阅相关资料。
    2.2 SPI控制器驱动层
          SPI控制器驱动层,每种处理器平台都有自己的控制器驱动,属于平台移植相关层。它的职责是为系统中每条SPI总线实现相应的读写方法。在物理上,每个SPI控制器可以连接若干个SPI从设备。
          在系统开机时,SPI控制器驱动被首先装载。一个控制器驱动用于支持一条特定的SPI总线的读写。一个控制器驱动可以用数据结构struct spi_master来描述。

    3.SPI相关的数据结构

      3.1 struct spi_master 用于描述一个SPI控制器

    //在include/liunx/spi/spi.h文件中,在数据结构struct spi_master定义如下:
    
    struct spi_master {  
        struct device   dev;  
        s16         bus_num;  
        u16         num_chipselect;  
        int         (*setup)(struct spi_device *spi);  
        int         (*transfer)(struct spi_device *spi, struct spi_message *mesg);  
        void        (*cleanup)(struct spi_device *spi);  
    };  

         bus_num为该控制器对应的SPI总线号。
          num_chipselect 控制器支持的片选数量,即能支持多少个spi设备 
          setup函数是设置SPI总线的模式,时钟等的初始化函数, 针对设备设置SPI的工作时钟及数据传输模式等。在spi_add_device函数中调用。 
          transfer函数是实现SPI总线读写方法的函数。实现数据的双向传输,可能会睡眠

      cleanup 注销的时候调用

      3.2  SPI设备驱动层

          SPI设备驱动层为用户接口层,其为用户提供了通过SPI总线访问具体设备的接口。
          SPI设备驱动层可以用两个模块来描述,struct spi_driver和struct spi_device。
          相关的数据结构如下:

    struct spi_driver 用来描述一个SPI设备的驱动信息
    struct spi_driver {  
        int         (*probe)(struct spi_device *spi);  
        int         (*remove)(struct spi_device *spi);  
        void            (*shutdown)(struct spi_device *spi);  
        int         (*suspend)(struct spi_device *spi, pm_message_t mesg);  
        int         (*resume)(struct spi_device *spi);  
        struct device_driver    driver;  
    }; 

      Driver是为device服务的,spi_driver注册时会扫描SPI bus上的设备,进行驱动和设备的绑定,probe函数用于驱动和设备匹配时被调用。从上面的结构体注释中我们可以知道,SPI的通信是通过消息队列机制,而不是像I2C那样通过与从设备进行对话的方式。

    struct spi_device 用来描述一个SPI总线上的从设备
    通常来说spi_device对应着SPI总线上某个特定的slave。并且spi_device封装了一个spi_master结构体。
    spi_device结构体包含了私有的特定的slave设备特性,包括它最大的频率,片选那个,输入输出模式等等
    struct spi_device {  
        struct device       dev;  
        struct spi_master   *master;  
        u32         max_speed_hz;  
        u8          chip_select;  
        u8          mode;    
        u8          bits_per_word;  
        int         irq;  
        void            *controller_state;  
        void            *controller_data;  
        char            modalias[32];   
    }; 

    4 spi_device以下一系列的操作是在platform板文件中完成!

    spi_device的板信息用spi_board_info结构体来描述:

      spi_board_info参数

    .modalias = "rc522",    //初始化设备的名称
    .platform_data = NULL,    
    .max_speed_hz = 10*1000*1000,    //初始化传输速率
    .bus_num = 2,    //控制器编号
    .chip_select = 0,    //控制器片选的编号
    .mode = SPI_MODE_0,    //spi的模式 CPOL=0, CPHA=0 此处选择具体数据传输模式
    .controller_data = &spi2_csi[0],    //片选IO的信息

    spi2_board_info设备描述结构体,设备注册函数spi_register_board_info

    而这个info在init函数调用的时候会初始化:

    spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));//注册spi_board_info。

    这个代码会把spi_board_info注册到链表board_list上。

    spi_device封装了一个spi_master结构体,事实上spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_boardinfo扫描board_list,找到挂接在它上面的spi设备,然后创建并注册spi_device。

    至此spi_device就构建并注册完成了!

    5 spi_driver的构建与注册

    driver有几个重要的结构体:spi_driver、spi_transfer、spi_message

    driver有几个重要的函数    :spi_message_init、spi_message_add_tail、spi_sync

       //spi_driver的构建

    static struct spi_driver   m25p80_driver = { 
    
    .driver = {
            .name   ="m25p80",
            .bus    =&spi_bus_type,
            .owner  = THIS_MODULE,
        },
        .probe  = m25p_probe,
        .remove =__devexit_p(m25p_remove),
    
    };

    //spidriver的注册

    spi_register_driver(&m25p80_driver);

    在有匹配的spi_device时,会调用m25p_probe

    probe里完成了spi_transfer、spi_message的构建;

    spi_message_init、spi_message_add_tail、spi_sync、spi_write_then_read函数的调用

    在SPI总线上是通过封装一系列的spi_transfer到一个spi_message中,然后将spi_message提交到SPI子系统去。

    下面是spi_transfer结构:

    struct spi_transfer {  
        const void*tx_buf;  //驱动提供的发送缓冲区dma,  
        void *rx_buf;    //接收缓冲区  
        unsigned len;  //长度一般是8位
        dma_addr_ttx_dma;   //发送dma,controller使用  
        dma_addr_t rx_dma;  //接收dma  
        unsigned cs_change:1;   //片选位   
        u8 bits_per_word;   //每字长度  
        u16 delay_usecs;    //延迟  
        u32 speed_hz;    //速度  
        struct list_headtransfer_list;  //transfer 链表  
    };  

    在spi_transfer中时常更改的域也许只有len,tx_buf和rx_buf。剩下的当以0来初始化。

    单个spi_transfer可表示一次读,一次写或者是一次读写。在SPIcontroller驱动下,所有操作常是全双工的。向spi_transfer中rx_buf传递一个NULL,这就是一次只写操作,会丢弃MISO线上的数据。同样向tx_buf传递一个NULL,这就是一次只读操作了。spi_transfer中len域代表(已经多少字节数据流过总线了)howmany bytes to clock the bus

    spi_message结构:

    struct spi_message {  
            struct list_head transfers;  
            struct spi_device *spi;  
            unsigned is_dma_mapped:1;  
            void (*complete)(void*context);  
            void *context;  
            unsigned actual_length;  
            int status;  
            struct list_head queue;  
            void *state;  
    }; 

    transfer这个spi_message所包含有的spi_transfer链表头。

    is_dma_mappedspi_transfer中tx_dma和rx_dma是否已经mapped

    complete回调函数

    context 提供给complete的可选参数

    actual_lengthspi_message已经传输了的字节数

    status 出错与否,错误时返回errorcode

    queue 和state 供controller驱动内部使用

    在每次使用spi_message可以使用函数void spi_message_init(structspi_message *m);来初始化。

    向spi_message添加transfers可以使用spi_message_add_tail()函数:

    void spi_message_add_tail(structspi_transfer *t, struct spi_message *m);

    一旦你准备好了spi_message,就可以使用spi_async()来向SPI系统提交了:

    int spi_async(struct spi_device *spi,struct spi_message *message);

    因为是异步的,一提交就立马返回了,这也就是说需要同步机制(complete就是了)。他确保不会睡眠,可安全的在中断handler或其他不可休眠的代码中调用。稍后会念念他的好的。

    使用spi_async()需要注意的是,在complete()未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。

    使用完成回调机制稍显复杂,可以使用SPI系统提供的另一个同步版本:spi_sync():

    int spi_sync(struct spi_device *spi,struct spi_message *message);

    因为是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()在drivers/spi/spi.c中实现,其调用了spi_async(),并休眠直至complete返回。

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/ioctl.h>
      4 #include <linux/fs.h>
      5 #include <linux/device.h>
      6 #include <linux/err.h>
      7 #include <linux/list.h>
      8 #include <linux/errno.h>
      9 #include <linux/mutex.h>
     10 #include <linux/slab.h>
     11 #include <linux/compat.h>
     12 #include <linux/spi/spi.h>
     13 #include <linux/spi/spidev.h>
     14 #include <asm/uaccess.h>
     15 #include <linux/gpio.h>
     16 #include <mach/gpio.h>
     17 #include <plat/gpio-cfg.h>
     18 #include <linux/delay.h>
     19 #include <linux/miscdevice.h>
     20 
     21 struct spi_device *my_spi;
     22 
     23 #define RC522_RESET_PIN    EXYNOS4_GPK1(0)
     24 
     25 void my_rc522_reset()    // 驱动初始化 (IO部分)
     26 {
     27     //printk("************************ %s
    ", __FUNCTION__);
     28     if(gpio_request_one(RC522_RESET_PIN, GPIOF_OUT_INIT_HIGH, "RC522_RESET"))
     29                 pr_err("failed to request GPK1_0 for RC522 reset control
    ");
     30 
     31         s3c_gpio_setpull(RC522_RESET_PIN, S3C_GPIO_PULL_UP);
     32         gpio_set_value(RC522_RESET_PIN, 0);
     33 
     34         mdelay(5);
     35 
     36         gpio_set_value(RC522_RESET_PIN, 1);
     37         gpio_free(RC522_RESET_PIN);
     38 }
     39 
     40 //static ssize_t rc522_write(unsigned char *buffer, int len)
     41 static ssize_t rc522_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
     42 {
     43     int status;
     44     unsigned char tx_buf[2];
     45     
     46     status = copy_from_user(tx_buf,buf,count);
     47     
     48     struct spi_transfer    t = {
     49         .tx_buf        = tx_buf,
     50         .len        = count,
     51     };
     52     struct spi_message    m;
     53     spi_message_init(&m);
     54     spi_message_add_tail(&t, &m);
     55     DECLARE_COMPLETION_ONSTACK(done);
     56     m.complete = complete;
     57     m.context = &done;
     58     
     59     printk("spi_async send begin!
    ");
     60     status = spi_async(my_spi,&m);
     61     if(status == 0){
     62         wait_for_completion(&done);
     63         status = m.status;
     64         if (status == 0)
     65             status = m.actual_length;
     66     }
     67     return status;
     68 }
     69 
     70 
     71 //static ssize_t rc522_read(unsigned char *buffer, int len)
     72 static ssize_t rc522_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
     73 {
     74     // 驱动读函数的底层部分
     75     int status;
     76     unsigned char *rx_buf;
     77     
     78     struct spi_transfer    t = {
     79         .rx_buf        = &rx_buf,
     80         .len        = count,
     81     };
     82     struct spi_message    m;
     83     spi_message_init(&m);//初始化一个spi_message/一个不可打断的SPI传输过程:CS=0,传数据,cs=1/ 
     84     spi_message_add_tail(&t, &m);//spi_transfer是spi上传输的单方向一个或者多个字节
     85     DECLARE_COMPLETION_ONSTACK(done);////声明并初始化一个完成量done      启动传输并等待完成
     86     m.complete = complete; //回调函数
     87     m.context = &done; //提供给complete的可选参数
     88     
     89     printk("spi_async read begin!
    ");
     90     status = spi_async(my_spi,&m); //向SPI系统提交 spi_message
     91     if(status == 0){
     92         wait_for_completion(&done);//这个函数进行一个不可打断的等待. 如果你的代码调用 wait_for_completion 并且
     93                                 //没有人完成这个任务, 结果会是一个不可杀死的进程
     94         status = m.status;
     95         if (status == 0)
     96             status = m.actual_length;
     97     }
     98     
     99     status = copy_to_user(buf,&rx_buf,status);
    100     
    101     return status;
    102 }
    103 
    104 int rc522_open(struct inode *inode,struct file *filp)
    105 {
    106     return 0;
    107 }
    108 
    109 
    110 
    111 static struct file_operations rc522_ops = {  //驱动对应的结构体
    112     .owner     = THIS_MODULE,
    113     .open     = rc522_open,
    114     .read    = rc522_read,
    115     .write     = rc522_write,
    116 };
    117 
    118 static struct miscdevice rc522_dev = { // rc522作为一个杂项设备存在
    119     .minor    = MISC_DYNAMIC_MINOR,
    120     .fops    = &rc522_ops,
    121     .name    = "rc522",
    122 };
    123 
    124 static int __devinit my_rc522_probe(struct spi_device *spi) // 说明驱动名 == 设备名,进入到probe驱动函数
    125 {
    126     
    127     printk("my_rc522_probe!
    ");
    128     
    129     /* reset */
    130     my_rc522_reset();
    131     my_spi = spi;
    132     
    133     misc_register(&rc522_dev);
    134     
    135     return 0;
    136 }
    137 
    138 static int __devexit my_rc522_remove(struct spi_device *spi)
    139 {
    140     printk("my_rc522_remove!
    ");
    141     misc_deregister(&rc522_dev);    
    142     return 0;
    143 }
    144 
    145 static struct spi_driver my_rc522_spi_driver = {   //  用来描述一个SPI设备的驱动信息
    146     .driver = {
    147         .name  = "my_rc522",
    148         .owner = THIS_MODULE,
    149     },
    150     .probe =    my_rc522_probe,
    151     .remove = __devexit_p(my_rc522_remove),
    152 
    153     /* NOTE:  suspend/resume methods are not necessary here.
    154      * We don't do anything except pass the requests to/from
    155      * the underlying controller.  The refrigerator handles
    156      * most issues; the controller driver handles the rest.
    157      */
    158 };
    159 
    160 
    161 static int __init my_rc522_init(void)
    162 {
    163     spi_register_driver(&my_rc522_spi_driver); // 注册SPI驱动
    164     return 0;
    165 }
    166 
    167 static void __exit my_rc522_exit(void)
    168 {
    169     spi_unregister_driver(&my_rc522_spi_driver); // 卸载驱动
    170 }
    171 
    172 module_exit(my_rc522_exit);
    173 module_init(my_rc522_init);
    174 
    175 
    176 MODULE_AUTHOR("topeet: rty");
    177 MODULE_LICENSE("GPL");
    myrc522.c
      1 /*
      2  * SPI testing utility (using spidev driver)
      3  *
      4  * Copyright (c) 2007  MontaVista Software, Inc.
      5  * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
      6  *
      7  * This program is free software; you can redistribute it and/or modify
      8  * it under the terms of the GNU General Public License as published by
      9  * the Free Software Foundation; either version 2 of the License.
     10  *
     11  * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
     12  */
     13 
     14 #include <stdint.h>
     15 #include <unistd.h>
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <getopt.h>
     19 #include <fcntl.h>
     20 #include <sys/ioctl.h>
     21 #include <linux/types.h>
     22 
     23 #include "spidev.h"
     24 #include "spidev_test.h"
     25 
     26 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
     27 
     28 static void pabort(const char *s)
     29 {
     30     perror(s);
     31     
     32     abort();
     33 }
     34 
     35 static const char *device = "/dev/rc522";
     36 static uint8_t mode;
     37 static uint8_t bits = 8;
     38 static uint32_t speed = 400 * 1000;//500000;
     39 static uint16_t delay;
     40 
     41 int g_SPI_Fd = 0;
     42 
     43 unsigned char UID[5], Temp[4];
     44 
     45 /*******************************************
     46 函数名称:tochar
     47 功    能:处理16进制函数
     48 参    数:id
     49 返回值  :无
     50 ********************************************/
     51 #if 0
     52 void tochar(unsigned char id)
     53 {
     54     switch(id) 
     55     {
     56     case 0x00:printf("00");break;
     57     case 0x01:printf("01");break;
     58     case 0x02:printf("02");break;
     59     case 0x03:printf("03");break;
     60     case 0x04:printf("04");break;
     61     case 0x05:printf("05");break;
     62     case 0x06:printf("06");break;
     63     case 0x07:printf("07");break;
     64     case 0x08:printf("08");break;
     65     case 0x09:printf("09");break;
     66     case 0x0a:printf("0a");break;
     67     case 0x0b:printf("0b");break;
     68     case 0x0c:printf("0c");break;
     69     case 0x0d:printf("0d");break;
     70     case 0x0e:printf("0e");break;
     71     case 0x0f:printf("0f");break;
     72     case 0x10:printf("10");break;
     73     case 0x11:printf("11");break;
     74     case 0x12:printf("12");break;
     75     case 0x13:printf("13");break;
     76     case 0x14:printf("14");break;
     77     case 0x15:printf("15");break;
     78     case 0x16:printf("16");break;
     79     case 0x17:printf("17");break;
     80     case 0x18:printf("18");break;
     81     case 0x19:printf("19");break;
     82     case 0x1a:printf("1a");break;
     83     case 0x1b:printf("1b");break;
     84     case 0x1c:printf("1c");break;
     85     case 0x1d:printf("1d");break;
     86     case 0x1e:printf("1e");break;
     87     case 0x1f:printf("1f");break;
     88     case 0x20:printf("20");break;
     89     case 0x21:printf("21");break;
     90     case 0x22:printf("22");break;
     91     case 0x23:printf("23");break;
     92     case 0x24:printf("24");break;
     93     case 0x25:printf("25");break;
     94     case 0x26:printf("26");break;
     95     case 0x27:printf("27");break;
     96     case 0x28:printf("28");break;
     97     case 0x29:printf("29");break;
     98     case 0x2a:printf("2a");break;
     99     case 0x2b:printf("2b");break;
    100     case 0x2c:printf("2c");break;
    101     case 0x2d:printf("2d");break;
    102     case 0x2e:printf("2e");break;
    103     case 0x2f:printf("2f");break;
    104     case 0x30:printf("30");break;
    105     case 0x31:printf("31");break;
    106     case 0x32:printf("32");break;
    107     case 0x33:printf("33");break;
    108     case 0x34:printf("34");break;
    109     case 0x35:printf("35");break;
    110     case 0x36:printf("36");break;
    111     case 0x37:printf("37");break;
    112     case 0x38:printf("38");break;
    113     case 0x39:printf("39");break;
    114     case 0x3a:printf("3a");break;
    115     case 0x3b:printf("3b");break;
    116     case 0x3c:printf("3c");break;
    117     case 0x3d:printf("3d");break;
    118     case 0x3e:printf("3e");break;
    119     case 0x3f:printf("3f");break;
    120     case 0x40:printf("40");break;
    121     case 0x41:printf("41");break;
    122     case 0x42:printf("42");break;
    123     case 0x43:printf("43");break;
    124     case 0x44:printf("44");break;
    125     case 0x45:printf("45");break;
    126     case 0x46:printf("46");break;
    127     case 0x47:printf("47");break;
    128     case 0x48:printf("48");break;
    129     case 0x49:printf("49");break;
    130     case 0x4a:printf("4a");break;
    131     case 0x4b:printf("4b");break;
    132     case 0x4c:printf("4c");break;
    133     case 0x4d:printf("4d");break;
    134     case 0x4e:printf("4e");break;
    135     case 0x4f:printf("4f");break;
    136     case 0x50:printf("50");break;
    137     case 0x51:printf("51");break;
    138     case 0x52:printf("52");break;
    139     case 0x53:printf("53");break;
    140     case 0x54:printf("54");break;
    141     case 0x55:printf("55");break;
    142     case 0x56:printf("56");break;
    143     case 0x57:printf("57");break;
    144     case 0x58:printf("58");break;
    145     case 0x59:printf("59");break;
    146     case 0x5a:printf("5a");break;
    147     case 0x5b:printf("5b");break;
    148     case 0x5c:printf("5c");break;
    149     case 0x5d:printf("5d");break;
    150     case 0x5e:printf("5e");break;
    151     case 0x5f:printf("5f");break;
    152     case 0x60:printf("60");break;
    153     case 0x61:printf("61");break;
    154     case 0x62:printf("62");break;
    155     case 0x63:printf("63");break;
    156     case 0x64:printf("64");break;
    157     case 0x65:printf("65");break;
    158     case 0x66:printf("66");break;
    159     case 0x67:printf("67");break;
    160     case 0x68:printf("68");break;
    161     case 0x69:printf("69");break;
    162     case 0x6a:printf("6a");break;
    163     case 0x6b:printf("6b");break;
    164     case 0x6c:printf("6c");break;
    165     case 0x6d:printf("6d");break;
    166     case 0x6e:printf("6e");break;
    167     case 0x6f:printf("6f");break;
    168     case 0x70:printf("70");break;
    169     case 0x71:printf("71");break;
    170     case 0x72:printf("72");break;
    171     case 0x73:printf("73");break;
    172     case 0x74:printf("74");break;
    173     case 0x75:printf("75");break;
    174     case 0x76:printf("76");break;
    175     case 0x77:printf("77");break;
    176     case 0x78:printf("78");break;
    177     case 0x79:printf("79");break;
    178     case 0x7a:printf("7a");break;
    179     case 0x7b:printf("7b");break;
    180     case 0x7c:printf("7c");break;
    181     case 0x7d:printf("7d");break;
    182     case 0x7e:printf("7e");break;
    183     case 0x7f:printf("7f");break;
    184     case 0x80:printf("80");break;
    185     case 0x81:printf("81");break;
    186     case 0x82:printf("82");break;
    187     case 0x83:printf("83");break;
    188     case 0x84:printf("84");break;
    189     case 0x85:printf("85");break;
    190     case 0x86:printf("86");break;
    191     case 0x87:printf("87");break;
    192     case 0x88:printf("88");break;
    193     case 0x89:printf("89");break;
    194     case 0x8a:printf("8a");break;
    195     case 0x8b:printf("8b");break;
    196     case 0x8c:printf("8c");break;
    197     case 0x8d:printf("8d");break;
    198     case 0x8e:printf("8e");break;
    199     case 0x8f:printf("8f");break;
    200     case 0x90:printf("90");break;
    201     case 0x91:printf("91");break;
    202     case 0x92:printf("92");break;
    203     case 0x93:printf("93");break;
    204     case 0x94:printf("94");break;
    205     case 0x95:printf("95");break;
    206     case 0x96:printf("96");break;
    207     case 0x97:printf("97");break;
    208     case 0x98:printf("98");break;
    209     case 0x99:printf("99");break;
    210     case 0x9a:printf("9a");break;
    211     case 0x9b:printf("9b");break;
    212     case 0x9c:printf("9c");break;
    213     case 0x9d:printf("9d");break;
    214     case 0x9e:printf("9e");break;
    215     case 0x9f:printf("9f");break;
    216     case 0xa0:printf("a0");break;
    217     case 0xa1:printf("a1");break;
    218     case 0xa2:printf("a2");break;
    219     case 0xa3:printf("a3");break;
    220     case 0xa4:printf("a4");break;
    221     case 0xa5:printf("a5");break;
    222     case 0xa6:printf("a6");break;
    223     case 0xa7:printf("a7");break;
    224     case 0xa8:printf("a8");break;
    225     case 0xa9:printf("a9");break;
    226     case 0xaa:printf("aa");break;
    227     case 0xab:printf("ab");break;
    228     case 0xac:printf("ac");break;
    229     case 0xad:printf("ad");break;
    230     case 0xae:printf("ae");break;
    231     case 0xaf:printf("af");break;
    232     case 0xb0:printf("b0");break;
    233     case 0xb1:printf("b1");break;
    234     case 0xb2:printf("b2");break;
    235     case 0xb3:printf("b3");break;
    236     case 0xb4:printf("b4");break;
    237     case 0xb5:printf("b5");break;
    238     case 0xb6:printf("b6");break;
    239     case 0xb7:printf("b7");break;
    240     case 0xb8:printf("b8");break;
    241     case 0xb9:printf("b9");break;
    242     case 0xba:printf("ba");break;
    243     case 0xbb:printf("bb");break;
    244     case 0xbc:printf("bc");break;
    245     case 0xbd:printf("bd");break;
    246     case 0xbe:printf("be");break;
    247     case 0xbf:printf("bf");break;
    248     case 0xc0:printf("c0");break;
    249     case 0xc1:printf("c1");break;
    250     case 0xc2:printf("c2");break;
    251     case 0xc3:printf("c3");break;
    252     case 0xc4:printf("c4");break;
    253     case 0xc5:printf("c5");break;
    254     case 0xc6:printf("c6");break;
    255     case 0xc7:printf("c7");break;
    256     case 0xc8:printf("c8");break;
    257     case 0xc9:printf("c9");break;
    258     case 0xca:printf("ca");break;
    259     case 0xcb:printf("cb");break;
    260     case 0xcc:printf("cc");break;
    261     case 0xcd:printf("cd");break;
    262     case 0xce:printf("ce");break;
    263     case 0xcf:printf("cf");break;
    264     case 0xd0:printf("d0");break;
    265     case 0xd1:printf("d1");break;
    266     case 0xd2:printf("d2");break;
    267     case 0xd3:printf("d3");break;
    268     case 0xd4:printf("d4");break;
    269     case 0xd5:printf("d5");break;
    270     case 0xd6:printf("d6");break;
    271     case 0xd7:printf("d7");break;
    272     case 0xd8:printf("d8");break;
    273     case 0xd9:printf("d9");break;
    274     case 0xda:printf("da");break;
    275     case 0xdb:printf("db");break;
    276     case 0xdc:printf("dc");break;
    277     case 0xdd:printf("dd");break;
    278     case 0xde:printf("de");break;
    279     case 0xdf:printf("df");break;
    280     case 0xe0:printf("e0");break;
    281     case 0xe1:printf("e1");break;
    282     case 0xe2:printf("e2");break;
    283     case 0xe3:printf("e3");break;
    284     case 0xe4:printf("e4");break;
    285     case 0xe5:printf("e5");break;
    286     case 0xe6:printf("e6");break;
    287     case 0xe7:printf("e7");break;
    288     case 0xe8:printf("e8");break;
    289     case 0xe9:printf("e9");break;
    290     case 0xea:printf("ea");break;
    291     case 0xeb:printf("eb");break;
    292     case 0xec:printf("ec");break;
    293     case 0xed:printf("ed");break;
    294     case 0xee:printf("ee");break;
    295     case 0xef:printf("ef");break;
    296     case 0xf0:printf("f0");break;
    297     case 0xf1:printf("f1");break;
    298     case 0xf2:printf("f2");break;
    299     case 0xf3:printf("f3");break;
    300     case 0xf4:printf("f4");break;
    301     case 0xf5:printf("f5");break;
    302     case 0xf6:printf("f6");break;
    303     case 0xf7:printf("f7");break;
    304     case 0xf8:printf("f8");break;
    305     case 0xf9:printf("f9");break;
    306     case 0xfa:printf("fa");break;
    307     case 0xfb:printf("fb");break;
    308     case 0xfc:printf("fc");break;
    309     case 0xfd:printf("fd");break;
    310     case 0xfe:printf("fe");break;
    311     case 0xff:printf("ff");break;
    312     default:
    313               ;  
    314     }
    315 }
    316 #endif
    317 
    318 int WriteRawRC(int addr, int data) //向RC522 传数据
    319 {
    320     int ret;
    321     int fd = g_SPI_Fd;
    322     unsigned char  TxBuf[2];
    323 
    324     //bit7:MSB=0,bit6~1:addr,bit0:RFU=0
    325     TxBuf[0] = ((unsigned char)addr << 1)&0x7E;
    326     //TxBuf[0] &= 0x7E;
    327 
    328     TxBuf[1] = (unsigned char)data;
    329     
    330     ret = write(fd, TxBuf, 2);
    331     if (ret < 0)
    332         printf("spi:SPI Write error
    ");
    333 
    334     usleep(10);
    335 
    336     return ret;
    337 }
    338 
    339 unsigned char ReadRawRC(int addr) //向RC522 读数据
    340 {
    341     int ret;
    342     int fd = g_SPI_Fd;
    343     unsigned char  ReData;
    344     unsigned char  Address;
    345     
    346     Address  = (unsigned char)addr << 1;
    347     Address |= (1 << 7);
    348     Address &= ~(1 << 0);
    349     
    350     ret = write(fd, &Address, 1);
    351     if (ret < 0)
    352         printf("spi:SPI Write error
    ");
    353 
    354     usleep(100);
    355 
    356     ret = read(fd, &ReData, 1);
    357     if (ret < 0)
    358         printf("spi:SPI Read error
    ");
    359 
    360     return ReData;
    361 }
    362 
    363 void SetBitMask(unsigned char reg,unsigned char mask)  
    364 {
    365       char tmp = 0x0;
    366     
    367       tmp = ReadRawRC(reg) | mask;
    368     
    369       WriteRawRC(reg,tmp | mask);
    370 }
    371 
    372 //******************************************************************/
    373 //功    能:清RC522寄存器位
    374 //参数说明:reg[IN]:寄存器地址
    375 //          mask[IN]:清位值
    376 //******************************************************************/
    377 void ClearBitMask(unsigned char reg, unsigned char mask)  
    378 {
    379     char tmp = 0x0;
    380     
    381     tmp = ReadRawRC(reg)&(~mask);
    382     
    383     WriteRawRC(reg, tmp);  // clear bit mask
    384 }
    385 
    386 int rc522_init()
    387 {
    388     int ret;
    389     char version = 0;
    390 
    391     //reset
    392     WriteRawRC(CommandReg, PCD_RESETPHASE);
    393     usleep(10);
    394     WriteRawRC(ModeReg, 0x3D);
    395     WriteRawRC(TReloadRegL, 30);
    396     WriteRawRC(TReloadRegH, 0);
    397     WriteRawRC(TModeReg, 0x8D);
    398     WriteRawRC(TPrescalerReg, 0x3E);
    399 
    400     version = ReadRawRC(VersionReg);
    401     printf("Chip Version: 0x%x
    ", version);
    402     usleep(50000);
    403 
    404     return 0;
    405 }
    406 
    407 void PcdAntennaOn()
    408 {
    409     unsigned char i;
    410   
    411     WriteRawRC(TxASKReg, 0x40);
    412       usleep(20);
    413   
    414     i = ReadRawRC(TxControlReg);
    415       if(!(i&0x03))
    416             SetBitMask(TxControlReg, 0x03);
    417       
    418     i = ReadRawRC(TxASKReg);
    419 }
    420 
    421 static void print_usage(const char *prog)
    422 {
    423     printf("Usage: %s [-DsbdlHOLC3]
    ", prog);
    424     puts("  -D --device   device to use (default /dev/spidev1.1)
    "
    425          "  -s --speed    max speed (Hz)
    "
    426          "  -d --delay    delay (usec)
    "
    427          "  -b --bpw      bits per word 
    "
    428          "  -l --loop     loopback
    "
    429          "  -H --cpha     clock phase
    "
    430          "  -O --cpol     clock polarity
    "
    431          "  -L --lsb      least significant bit first
    "
    432          "  -C --cs-high  chip select active high
    "
    433          "  -3 --3wire    SI/SO signals shared
    ");
    434     exit(1);
    435 }
    436 
    437 static void parse_opts(int argc, char *argv[])
    438 {
    439     while (1) {
    440         static const struct option lopts[] = {
    441             { "device",  1, 0, 'D' },
    442             { "speed",   1, 0, 's' },
    443             { "delay",   1, 0, 'd' },
    444             { "bpw",     1, 0, 'b' },
    445             { "loop",    0, 0, 'l' },
    446             { "cpha",    0, 0, 'H' },
    447             { "cpol",    0, 0, 'O' },
    448             { "lsb",     0, 0, 'L' },
    449             { "cs-high", 0, 0, 'C' },
    450             { "3wire",   0, 0, '3' },
    451             { "no-cs",   0, 0, 'N' },
    452             { "ready",   0, 0, 'R' },
    453             { NULL, 0, 0, 0 },
    454         };
    455         int c;
    456 
    457         c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
    458 
    459         if (c == -1)
    460             break;
    461 
    462         switch (c) {
    463         case 'D':
    464             device = optarg;
    465             break;
    466         case 's':
    467             speed = atoi(optarg);
    468             break;
    469         case 'd':
    470             delay = atoi(optarg);
    471             break;
    472         case 'b':
    473             bits = atoi(optarg);
    474             break;
    475         case 'l':
    476             mode |= SPI_LOOP;
    477             break;
    478         case 'H':
    479             mode |= SPI_CPHA;
    480             break;
    481         case 'O':
    482             mode |= SPI_CPOL;
    483             break;
    484         case 'L':
    485             mode |= SPI_LSB_FIRST;
    486             break;
    487         case 'C':
    488             mode |= SPI_CS_HIGH;
    489             break;
    490         case '3':
    491             mode |= SPI_3WIRE;
    492             break;
    493         case 'N':
    494             mode |= SPI_NO_CS;
    495             break;
    496         case 'R':
    497             mode |= SPI_READY;
    498             break;
    499         default:
    500             print_usage(argv[0]);
    501             break;
    502         }
    503     }
    504 }
    505 
    506 //******************************************************************/
    507 //功    能:通过RC522和ISO14443卡通讯
    508 //参数说明:Command[IN]:RC522命令字
    509 //          pInData[IN]:通过RC522发送到卡片的数据
    510 //          InLenByte[IN]:发送数据的字节长度
    511 //          pOutData[OUT]:接收到的卡片返回数据
    512 //          *pOutLenBit[OUT]:返回数据的位长度
    513 //******************************************************************/
    514 char PcdComMF522(unsigned char Command, unsigned char *pInData, 
    515                                  unsigned char InLenByte, unsigned char *pOutData, 
    516                                  unsigned int  *pOutLenBit)
    517 {
    518     char status = MI_ERR;
    519     unsigned char irqEn  = 0x00;
    520     unsigned char waitFor = 0x00;
    521     unsigned char lastBits;
    522     unsigned char n;
    523     unsigned int  i;
    524     
    525     switch (Command)
    526     {
    527         case PCD_AUTHENT:
    528               irqEn   = 0x12;
    529               waitFor = 0x10;
    530               break;
    531         case PCD_TRANSCEIVE:
    532               irqEn   = 0x77;
    533               waitFor = 0x30;
    534               break;
    535         default:
    536               break;
    537     }
    538     
    539     WriteRawRC(ComIEnReg, irqEn|0x80);
    540     ClearBitMask(ComIrqReg, 0x80);
    541     WriteRawRC(CommandReg, PCD_IDLE);
    542     SetBitMask(FIFOLevelReg, 0x80); // 清空FIFO 
    543     for(i=0; i<InLenByte; i++)
    544         WriteRawRC(FIFODataReg, pInData[i]); // 数据写入FIFO 
    545         
    546     WriteRawRC(CommandReg, Command); // 命令写入命令寄存器
    547 
    548     if(Command == PCD_TRANSCEIVE)
    549         SetBitMask(BitFramingReg,0x80); // 开始发送     
    550 
    551     i = 6000; //根据时钟频率调整,操作M1卡最大等待时间25ms
    552       do 
    553     {
    554         n = ReadRawRC(ComIrqReg);
    555         i--;
    556     }
    557     while((i!=0)&&!(n&0x01)&&!(n&waitFor));
    558     
    559     ClearBitMask(BitFramingReg, 0x80);
    560 
    561     if(i!=0)
    562     {
    563         if(!(ReadRawRC(ErrorReg) & 0x1B))
    564         {
    565             status = MI_OK;
    566             if (n&irqEn&0x01)
    567                 status = MI_NOTAGERR;
    568             if(Command == PCD_TRANSCEIVE)
    569             {
    570                 n = ReadRawRC(FIFOLevelReg);
    571                 
    572                 lastBits = ReadRawRC(ControlReg) & 0x07;
    573                 if(lastBits)
    574                     *pOutLenBit = (n-1)*8 + lastBits;
    575                 else
    576                     *pOutLenBit = n*8;
    577 
    578                 if(n == 0)
    579                     n = 1;
    580                 if(n>MAXRLEN)
    581                     n = MAXRLEN;
    582 
    583                 for (i=0; i<n; i++)
    584                     pOutData[i] = ReadRawRC(FIFODataReg); 
    585             }
    586         }
    587         else
    588         {
    589             status = MI_ERR;
    590         }
    591     }
    592 
    593     SetBitMask(ControlReg, 0x80);// stop timer now
    594     WriteRawRC(CommandReg, PCD_IDLE); 
    595 
    596     return status;
    597 }
    598 
    599 char PcdRequest(unsigned char req_code, unsigned char *pTagType)
    600 {
    601     char status;  
    602     unsigned int  unLen;
    603     unsigned char ucComMF522Buf[MAXRLEN]; 
    604 
    605     ClearBitMask(Status2Reg, 0x08);
    606     WriteRawRC(BitFramingReg, 0x07);
    607     SetBitMask(TxControlReg, 0x03);
    608  
    609       ucComMF522Buf[0] = req_code;
    610 
    611       status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf,
    612                                        1, ucComMF522Buf, &unLen);
    613 
    614       if ((status == MI_OK) && (unLen == 0x10))
    615       {    
    616             *pTagType     = ucComMF522Buf[0];
    617             *(pTagType+1) = ucComMF522Buf[1];
    618       }
    619       else
    620     {
    621         status = MI_ERR;
    622       }
    623 
    624       return status;
    625 }
    626 
    627 //******************************************************************/
    628 //功    能:防冲撞                                                  /
    629 //参数说明: pSnr[OUT]:卡片序列号,4字节                             /
    630 //返    回: 成功返回MI_OK                                           /
    631 //******************************************************************/
    632 char PcdAnticoll(unsigned char *pSnr)
    633 {
    634     char status;
    635     unsigned char i, snr_check = 0;
    636     unsigned int  unLen;
    637     unsigned char ucComMF522Buf[MAXRLEN]; 
    638     
    639     ClearBitMask(Status2Reg, 0x08);
    640     WriteRawRC(BitFramingReg, 0x00);
    641     ClearBitMask(CollReg, 0x80);
    642  
    643     ucComMF522Buf[0] = PICC_ANTICOLL1;
    644     ucComMF522Buf[1] = 0x20;
    645 
    646         status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf,
    647                                 2, ucComMF522Buf, &unLen);
    648 
    649         if(status == MI_OK)
    650     {
    651         for (i=0; i<4; i++)
    652         {   
    653             *(pSnr+i)  = ucComMF522Buf[i];
    654             snr_check ^= ucComMF522Buf[i];
    655         }
    656         if (snr_check != ucComMF522Buf[i])
    657         {
    658             status = MI_ERR;
    659         }
    660     }
    661     
    662     SetBitMask(CollReg,0x80);
    663     
    664     return status;
    665 }
    666 
    667 void Find_Card(void)
    668 {
    669     if(PcdRequest(0x52, Temp) == MI_OK)
    670     {
    671           if(Temp[0]==0x04 && Temp[1]==0x00)  
    672                   printf("MFOne-S50
    ");
    673             else if(Temp[0]==0x02 && Temp[1] == 0x00)
    674                   printf("MFOne-S70
    ");
    675             else if(Temp[0]==0x44 && Temp[1]==0x00)
    676                   printf("MF-UltraLight
    ");
    677             else if(Temp[0]==0x08 && Temp[1]==0x00)
    678                   printf("MF-Pro
    ");
    679             else if(Temp[0]==0x44 && Temp[1]==0x03)
    680                   printf("MF Desire
    ");
    681             else
    682                   printf("Unknown
    ");
    683             
    684             printf("SUCCESS!
    ");
    685     }
    686     else
    687     {
    688         printf("No card!
    ");
    689     }
    690 }
    691 
    692 void Auto_Reader(void)
    693 {
    694     int i = 0;
    695     unsigned long num = 0;
    696     
    697   //    while(1)
    698     //{
    699         if(PcdRequest(0x52,Temp) == MI_OK)
    700         {
    701             if(Temp[0]==0x04 && Temp[1]==0x00)  
    702                 printf("MFOne-S50
    ");
    703             else if(Temp[0]==0x02 && Temp[1]==0x00)
    704                 printf("MFOne-S70
    ");
    705             else if(Temp[0]==0x44 && Temp[1]==0x00)
    706                 printf("MF-UltraLight
    ");
    707             else if(Temp[0]==0x08 && Temp[1]==0x00)
    708                 printf("MF-Pro
    ");
    709             else if(Temp[0]==0x44 && Temp[1]==0x03)
    710                 printf("MF Desire
    ");
    711             else
    712                 printf("Unknown
    ");
    713             
    714             if(PcdAnticoll(UID) == MI_OK)
    715             { 
    716                 printf("Card Id is(%d):", num++);
    717 #if 1
    718                 for(i=0; i<4; i++)
    719                     printf("%x", UID[i]);
    720 #else            
    721                 tochar(UID[0]);
    722                 tochar(UID[1]);
    723                 tochar(UID[2]);
    724                 tochar(UID[3]);
    725 #endif
    726                 printf("
    ");
    727                 
    728                 PcdRequest(0x52,Temp);//clear
    729             }
    730             else
    731             {
    732                 printf("no serial num read
    ");
    733             }
    734         }
    735         else
    736         {
    737             printf("No Card!
    ");
    738         }
    739 
    740         usleep(300000);
    741 //    } 
    742 }
    743 
    744 void HandleConfigMenu(unsigned char inputvalue)
    745 {
    746 #if 0
    747     switch(toupper(inputvalue)) 
    748     {
    749     case 'A':
    750               Auto_Reader();
    751               break;
    752     case 'F':
    753               Find_Card();
    754               break;
    755     default:
    756               DisplayConfigMenu();
    757     }
    758 #endif
    759 
    760     //Find_Card();
    761 
    762     Auto_Reader();
    763 }
    764 
    765 int main(int argc, char *argv[])
    766 {
    767     unsigned char i;
    768     
    769     int ret = 0;
    770     int fd;
    771 
    772     parse_opts(argc, argv);
    773 
    774     fd = open(device, O_RDWR);
    775     if (fd < 0)
    776         pabort("can't open device");
    777 
    778     g_SPI_Fd = fd;
    779 
    780 #if 0
    781     /*
    782      * spi mode
    783      */
    784     ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    785     if (ret == -1)
    786         pabort("can't set spi mode");
    787 
    788     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    789     if (ret == -1)
    790         pabort("can't get spi mode");
    791 
    792     /*
    793      * bits per word
    794      */
    795     ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    796     if (ret == -1)
    797         pabort("can't set bits per word");
    798 
    799     ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    800     if (ret == -1)
    801         pabort("can't get bits per word");
    802 
    803     /*
    804      * max speed hz
    805      */
    806     ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    807     if (ret == -1)
    808         pabort("can't set max speed hz");
    809 
    810     ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    811     if (ret == -1)
    812         pabort("can't get max speed hz");
    813 
    814     printf("spi mode: %d
    ", mode);
    815     printf("bits per word: %d
    ", bits);
    816     printf("max speed: %d Hz (%d KHz)
    ", speed, speed/1000);
    817 #endif
    818 
    819     rc522_init();
    820 
    821     PcdAntennaOn();
    822 
    823     HandleConfigMenu(i);
    824 
    825     close(fd);
    826 
    827     return ret;
    828 }
    spi_test_app
  • 相关阅读:
    【Codeforces Round #240 (Div. 1) 】E—Mashmokh's Designed Problem(Spaly)
    【Codeforces Round #240 (Div. 1) 】E—Mashmokh's Designed Problem(Spaly)
    拦路虎
    拦路虎:jQuery
    图片百分百问题 z-index问题
    惠头无忧——浏览器兼容性
    响应式设计
    老子的第一篇博客
    less 学习 (计划终于执行了啊,不再拖延了)
    工作拦路虎
  • 原文地址:https://www.cnblogs.com/hkyst/p/7768822.html
Copyright © 2011-2022 走看看