IIC总线 学习总结

1,IIC软件(驱动)框架

user层:open、read、write、ioctl、close

kernel:设备驱动层:驱动工程师编写,编写字符设备驱动给应用层提供访问接口;

    封装本次读写的数据包,交给总线驱动,完成硬件的访问。(i2c-dev.c通用的设备驱动) 

    1,分配对象初始化

    struct i2c_driver mma8451q;

    struct i2c_driver{

      int (*probe)(struct i2c_client *,   const struct i2c_device_id *);

      //匹配成功后执行的函数

      int(*remove)(struct i2c_client *);

      struct device_driver  driver;//.name = "hello"; .owner = THIS_MODULE

      const struct i2c_device_id *id_table;//idtable 匹配方式

    };

    2,注册、注销

      #define i2c_add_driver(driver)/ i2c_register_driver(THIS_MODULE, driver)

      void i2c_del_driver(struct i2c_driver *);

    3,总线驱动端名字如何提交

      struct i2c_board_info {

        char                     type[i2c_name_size];//用户匹配的名字

        unsigned short   flags; //读写的标志位,一般不用

        unsigned short   addr;  //从机地址(SA0--0x1c\SA1---0x1d);

      };  

      int i2c_register_board_info(int busnum,struct i2c_board_info const *info,

        unsigned len);

      功能:将i2c_board_info 的结构体放到内核的链表上,由总线驱动解析这条链表

      参数:总线号、i2c_board_info结构体指针、传递结构体个数

           返回值:  成功:0;失败:错误码

    4,存放设备信息的驱动文件:(mach-s5p6818)

         kernel-3.4.39/arch/arm/mach-s5p6818/fs6818$ vi  device.c

      #include <linux/i2c.h>

      static struct i2c_board_info mma8451q = {

        .type = "mma8451q",

        .addr = 0x1c,

      };

    5,重新编译内核 make uImage

    6,数据的封装和数据的发送

      #define I2C_M_RD    0x0001 //read data, from slave to master

      当总线驱动和设备驱动匹配成功的时候创建的对象,传递给驱动的的probe函数

      struct i2c_client {

        unsigned short addr;  //从机地址

        char  name[I2C_NAME_SIZE];//名字

        struct i2c_adapter  *adapter;  //总线驱动的对象

        struct i2c_driver  *driver;  //设备驱动的对象

      };

      消息的结构体

      struct i2c_msg {

        __u16  addr;  //从机地址 client->addr

        __u16 flags;  //读1写0标志    

        __u16 len;  //数据的长度,字节为单位

        __u8  *buf;  //数据的首地址

      };

      备注:有多少起始位就有多少个消息,消息的长度是以字节来表示

      a,封装写的函数

        int i2c_write_reg(char reg, char data)

        {

          char w_buf[] = {reg, data};

          //消息的封装

          struct i2c_msg w_msg[] = {

            [0] = {

              .addr = client->addr,

              .flags = 0,

              .len = ARRAY_SIZE(w_buf),

              .buf = w_buf,

            },

          };

          //消息的发送

          ret = i2c_transfer(client->adapter, w_msg, ARRAY_SIZE(w_msg))

          if(ret != 1) {

            printk("write msg send error\n");

            return -EAGAIN;

          }

          return 0;

        }

      

      a,封装读的函数

        int i2c_read_reg(char reg)

        {

          int ret;

          chr val;

          char r_buf[] = {reg};

          //消息的封装

          struct i2c_msg r_msg[] = {

            [0] = {

              .addr = client->addr,

              .flags = 0,

              .len = ARRAY_SIZE(r_buf),

              .buf = r_buf,

            },

            [1] = {

              .addr = client->addr,

              .flags = I2C_M_RD,

              .len = 1,

              .buf = &val,

            },

          };

          //消息的发送

          ret = i2c_transfer(client->adapter, w_msg, ARRAY_SIZE(w_msg))

          if(ret != 2) {

            printk("read msg send error\n");

            return -EAGAIN;

          }

          return val;

        }

      将消息包发送给总线驱动

      int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

      参数:adap:总线驱动的对象;msgs:消息的首地址;num:消息的个数;

      返回值:成功返回发送消息的个数,失败(成功取反)

    核心层:内核实现,提供总线驱动和设备驱动的注册和注销方法,完成设备驱动

    总线驱动匹配的过程。(i2c-core.c)

    总线驱动(控制驱动层):厂商实现,已经封装好了数据收发时序。(i2c-3c2410.c)

IIC工作原理:

1,上拉电阻:当芯片不控制管脚时,管脚处于悬空状态(高阻态),即总线默认为高电平;

2,工作原理:主机发送从机地址前,发送起始信号,从机发送应答到主机;主机发送读写位,

  再发送从机地址,从机发送应答到主机;写数据,从机发送应答到主机;主机发送停止信号;

3,起始信号:SCL高、SDA从高到低;停止信号:SCL高、SDA从低到高;

  应答信号:从机给主机发送信号,SDA从高到低;

4,写时序:起始信号(1位)、设备地址(7位)、写位0、应答位(1位)、

  寄存器地址(8位)、应答位、数据(8位)、应答位、停止位(1位)

5,读时序:起始信号(1位)、设备地址(7位)、写位0、应答位(1位)、

  寄存器地址(8位)、应答位、/起始信号(1位)、设备地址(7位)、读位1

  、应答位(1位)、数据(8位)、无应答位、停止位(1位)

6,SCL为高电平的时候改变数据,低电平时不允许修改数据

 备注:kmalloc、kzalloc:分配连续的内存空间,最大时128k,分配内存必须是2的整数倍

    vmalloc:分配的内存大小没有限制,分配的内存不一定连续;

       get_free_page(gfp_mask) 分配一个页的大小4096 GFP_KERNEL  GFP_ATOMIC

     get_free_pages(gfp_mask, 0)分配多个页

猜你喜欢

转载自www.cnblogs.com/device/p/11408761.html