Chinaunix首页 | 论坛 | 博客
  • 博客访问: 485796
  • 博文数量: 135
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 905
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-24 19:31
文章分类

全部博文(135)

文章存档

2010年(135)

我的朋友
I2C

分类: LINUX

2010-07-21 23:33:38

1:
       i2c总线(串行总线),用于CPU与外设直接进行通信。只有两条线:数据线SDA总线),用于CPU与外设直接进行通信。只有两条线:数据线SDA, 控制线SCL。 具有简单性,有效性,"最主要优点"是:多主控,即可以连接多个设备,但同一时刻只有一个设备成为主设备与CPU通信。为主设备时,可以自己控制当前总线的时钟频率及数据传输。

2:

2.1 总线的构成及信号类型 
       I2C 总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率 100kbps。各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程 中,I2C总线上并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能。CPU发出的控制信号分为地址码和控制 量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对比度、亮度等)及需要调整的量。这样,各控制电路虽然挂 在同一条总线上,却彼此独立,互不相关。

      I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
      开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
      结束信号:SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。 
      应 答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元 发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。 
  目前有很多半导体集成电路上都集成了I2C接口。

 2.2
       i2c总线是两条线连接多个设备,inter ic. 
       寻址是通过在scl线上发出寻址信号: 起始,7/10位 地址 + 1位(读/写),(多个后续的数据),终止位。  而地址是由设备的脚决定,一般会有几个固定脚与几个可编程脚。通过编程可以确定设备的地址。当设备收到寻址信号后,判断是不是其地址。

7位寻址,被I2C协会保留,所以一般用10位寻址:s,1111 0xx (R/W) ACK xxxxxxxx  
 若(R/W) = 0, 则为从MASTER > slave,写 所以10个x为地址
 若(R/W) = 1,则为 从 SLAVE > MASTER, 读, 此时先前被寻址了的SLAVE就会发送数据给MASTER。

2.3
i2c是基于8位的
SCL时钟线,由主机提供时钟。
起始位: sda下降,scl保持高
结束位: sda上升,scl保持高。
地址位,一般是10位,被拆分为 xx (r/w) ack xxxxxxxx
数据: 每个字节必须是8位,先传MSB。每个字节后必须跟一个响应位(从机发)
每次从机接收时,可以使SCL为低,从而让主机进入等待状态。


3:"linuxi2c体系结构"
三个层次:
 1,i2c核心,内核完成 i2c-core.c
 2, i2c总线驱动, 实现 i2c_adapter(总线适配器),i2c_algorithm(通信方法)
 3, i2c设备驱动,实现 i2c_driver, i2c_client
通信方法:
 通过i2c_msg来表示每次的通信。每次可以收发多个i2c_msg.



//adapter注册,当成是一个platform_bus总线下的设备。
int i2c_add_adapter(struct i2c_adapter *adapter)
 res = idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id);
 i2c_register_adapter(adapter);
static int i2c_register_adapter(struct i2c_adapter *adap)
{
 if (adap->dev.parent == NULL) 
 adap->dev.parent = &platform_bus;
 adap->dev.release = &i2c_adapter_dev_release;
 adap->dev.class = &i2c_adapter_class;
 res = device_register(&adap->dev);
}
//i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分析一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,


//i2c_driver注册, 即driver先匹配所有adapter,找到正确的,然后检测硬件,生成对应的i2c_client, 然后把i2c_client注册到adapter上。
当 i2c_driver向内核注册时,会被调用attach_adatper,先匹配当前系统中所有adapter,再去检测硬件,当确定硬件存在,则会生 成匹配i2c_client?, 把i2c_client的driver指针指向自己(driver),adapter指针指向其adapter.然后会让这个adapter调用 其client_register. 

注册:
static inline int i2c_add_driver(struct i2c_driver *driver)
{
 return i2c_register_driver(THIS_MODULE, driver);
}
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
 driver->driver.owner = owner;
 driver->driver.bus = &i2c_bus_type;
 res = driver_register(&driver->driver);  //注册代表本 i2c_driver的 内部 driver
 class_for_each_device(&i2c_adapter_class, NULL, driver, __attach_adapter); //从目前系统中所的adapter中去匹配 对应的 adapter.
}
static int __attach_adapter(struct device *dev, void *da ta)
{
 struct i2c_adapter *adapter = to_i2c_adapter(dev);
 struct i2c_driver *driver = da ta;

 i2c_detect(adapter, driver);  //检测硬件

 /* Legacy drivers scan i2c busses directly */
 if (driver->attach_adapter)
 driver->attach_adapter(adapter); //生成client 并加入到adapter 中。
 return 0;
}
而一般 i2c_driver的实现时是:
static int yy_attach_adapter(struct i2c_adapter *adapter)
{
 return i2c_probe(adapter, &addr_da ta, yy_detect);
}

static int yy_detect (struct i2c_adapter * adapter, int address, int kind)
{
 struct yy_da ta da ta = kzalloc(sizeof(struct yy_da ta), GFP_KERNEL);
 i2c_client new_client = da ta->client;
 err = i2c_attach_client(new_client);
}

/*
 * The following structs are for those who like to implement new bus drivers:
 * i2c_algorithm is the interface to a class of hardware solutions which can
 * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
 * to name two of the most common.
 */
struct i2c_algorithm {
 /* If an adapter algorithm can't do I2C-level access, set master_xfer
   to NULL. If an adapter algorithm can do SMBus access, set
   smbus_xfer. If set to NULL, the SMBus protocol is simulated
   using common I2C messages */
 /* master_xfer should return the number of messages successfully
   processed, or a negative value on error */
 int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,   "i2c传输函数"
   int num);
 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,  "smbus传输函数"
   unsigned short flags, char read_write,
   u8 command, int size, union i2c_smbus_da ta *da ta);

 /* To determine what the adapter supports */
 u32 (*functionality) (struct i2c_adapter *);     "返回适配器支持的功能"
};
/*
 * i2c_adapter is the structure used to identify a physical i2c bus along
 * with the access algorithms necessary to access it.
 */
struct i2c_adapter {  "代表 一个物理的I2C总线"
 struct module *owner;
 unsigned int id;
 unsigned int class;   /* classes to allow probing for */
 const struct i2c_algorithm *algo; /* the algorithm to access the bus */
 void *algo_da ta;

 /* --- administration stuff. */
 int (*client_register)(struct i2c_client *);
 int (*client_unregister)(struct i2c_client *);

 /* da ta fields that are valid for all devices  */
 u8 level;   /* nesting level for lockdep */
 struct mutex bus_lock;
 struct mutex clist_lock;

 int timeout;  /* in jiffies */
 int retries;
 struct device dev;  /* the adapter device */

 int nr;
 struct list_head clients;  /* DEPRECATED */
 char name[48];
 struct completion dev_released;
};

/**
 * struct i2c_driver - represent an I2C device driver
 * @id: Unique driver ID (optional)
 * @class: What kind of i2c device we instantiate (for detect)
 * @attach_adapter: Callback for bus addition (for legacy drivers)
 * @detach_adapter: Callback for bus removal (for legacy drivers)
 * @detach_client: Callback for device removal (for legacy drivers)
 * @probe: Callback for device binding (new-style drivers)
 * @remove: Callback for device unbinding (new-style drivers)
 * @shutdown: Callback for device shutdown
 * @suspend: Callback for device suspend
 * @resume: Callback for device resume
 * @command: Callback for bus-wide signaling (optional)
 * @driver: Device driver model driver
 * @id_table: List of I2C devices supported by this driver
 * @detect: Callback for device detection
 * @address_da ta: The I2C addresses to probe, ignore or force (for detect)
 * @clients: List of detected clients we created (for i2c-core use on ly)
 *
 * The driver.owner field should be set to the module owner of this driver.
 * The driver.name field should be set to the name of this driver.
 *
 * For automatic device detection, both @detect and @address_da ta must
 * be defined. @class should also be set, otherwise on ly devices forced
 * with module parameters will be created. The detect function must
 * fill at least the name field of the i2c_board_info structure it is
 * handed upon successful detection, and possibly also the flags field.
 *
 * If @detect is missing, the driver will still work fine for enumerated
 * devices. Detected devices simply won't be supported. This is expected
 * for the many I2C/SMBus devices which can't be detected reliably, and
 * the on es which can always be enumerated in practice.
 *
 * The i2c_client structure which is handed to the @detect callback is
 * not a real i2c_client. It is initialized just enough so that you can
 * call i2c_smbus_read_byte_da ta and friends on it. Don't do anything
 * else with it. In particular, calling dev_dbg and friends on it is
 * not allowed.
 */
struct i2c_driver {
 int id;
 unsigned int class;

 /* Notifies the driver that a new bus has appeared. This routine
 * can be used by the driver to test if the bus meets its conditions
 * & seek for the presence of the chip(s) it supports. If found, it
 * registers the client(s) that are on the bus to the i2c admin. via
 * i2c_attach_client.  (LEGACY I2C DRIVERS ON LY)
 */
 int (*attach_adapter)(struct i2c_adapter *);
 int (*detach_adapter)(struct i2c_adapter *);

 /* tells the driver that a client is about to be deleted & gives it
 * the chance to remove its private da ta. Also, if the client struct
 * has been dynamically allocated by the driver in the function above,
 * it must be freed here.  (LEGACY I2C DRIVERS ON LY)
 */
 int (*detach_client)(struct i2c_client *) __deprecated;

 /* Standard driver model interfaces, for "new style" i2c drivers.
 * With the driver model, device enumeration is NEVER done by drivers;
 * it's done by infrastructure.  (NEW STYLE DRIVERS ON LY)
 */
 int (*probe)(struct i2c_client *, const struct i2c_device_id *);
 int (*remove)(struct i2c_client *);

 /* driver model interfaces that don't relate to enumeration  */
 void (*shutdown)(struct i2c_client *);
 int (*suspend)(struct i2c_client *, pm_message_t mesg);
 int (*resume)(struct i2c_client *);

 /* a ioctl like command that can be used to perform specific functions
 * with the device.
 */
 int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);  "类似ioctl"

 struct device_driver driver;
 const struct i2c_device_id *id_table;    "与本驱动 匹配的 设备id"

 /* Device detection callback for automatic device creation */
 int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *); "设备检测"
 const struct i2c_client_address_da ta *address_da ta;
 struct list_head clients;
};

/**
 * struct i2c_client - represent an I2C slave device
 * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
 *  I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
 * @addr: Address used on the I2C bus connected to the parent adapter.
 * @name: Indicates the type of the device, usually a chip name that's
 *  generic enough to hide second-sourcing and compatible revisions.
 * @adapter: manages the bus segment hosting this I2C device
 * @driver: device's driver, hence pointer to access routines
 * @dev: Driver model device node for the slave.
 * @irq: indicates the IRQ generated by this device (if any)
 * @list: list of active/busy clients (DEPRECATED)
 * @detected: member of an i2c_driver.clients list
 * @released: used to synchronize client releases & detaches and references
 *
 * An i2c_client identifies a single device (i.e. chip) connected to an
 * i2c bus. The behaviour exposed to Linux is defined by the driver
 * managing the device.
 */
struct i2c_client {
 unsigned short flags;  /* div., see below  */
 unsigned short addr;  /* chip address - NOTE: 7bit  */
 /* addresses are stored in the  */
 /* _LOWER_ 7 bits  */
 char name[I2C_NAME_SIZE];
 struct i2c_adapter *adapter;  /* the adapter we sit on  */
 struct i2c_driver *driver;  /* and our access routines  */
 struct device dev;  /* the device structure  */
 int irq;  /* irq issued by device  */
 struct list_head list;  /* DEPRECATED */
 struct list_head detected;
 struct completion released;
};


/**
 * struct i2c_board_info - template for device creation
 * @type: chip type, to initialize i2c_client.name
 * @flags: to initialize i2c_client.flags
 * @addr: stored in i2c_client.addr
 * @platform_da ta: stored in i2c_client.dev.platform_da ta
 * @archdata: copied into i2c_client.dev.archdata
 * @irq: stored in i2c_client.irq
 *
 * I2C doesn't actually support hardware probing, although controllers and
 * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
 * a device at a given address.  Drivers commonly need more information than
 * that, such as chip type, configuration, associated IRQ, and so on.
 *
 * i2c_board_info is used to build tables of information listing I2C devices
 * that are present.  This information is used to grow the driver model tree
 * for "new style" I2C drivers.  For mainboards this is done statically using
 * i2c_register_board_info(); bus numbers identify adapters that aren't
 * yet available.  For add-on boards, i2c_new_device() does this dynamically
 * with the adapter already known.
 */
struct i2c_board_info {
 char  type[I2C_NAME_SIZE];
 unsigned short  flags;
 unsigned short  addr;
 void  *platform_da ta;
 struct dev_archdata  *archdata;
 int  irq;
};
struct i2c_devinfo {
 struct list_head  list;
 int  busnum;
 struct i2c_board_info  board_info;
};

//***************************************************************//
struct i2c_msg {
 __u16 addr;  /* slave address  */
 __u16 flags;
#define I2C_M_TEN  0x0010  /* this is a ten bit chip address */
#define I2C_M_RD  0x0001  /* read da ta, from slave to master */
#define I2C_M_NOSTART  0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK  0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK  0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN  0x0400  /* length will be first received byte */
 __u16 len;  /* msg length  */
 __u8 *buf;  /* pointer to msg da ta  */
};
阅读(1591) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~