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 */
};