本帖最后由 Willian.Mo 于 2015-7-28 17:18 编辑
准备
对于内核注册的i2c适配器,用户空间可以通过open、ioctl、write、read等函数与i2c设备交互。在Linux内核代码文件/include/linux/i2c-dev.c中针对每个适配器生成一个主设备号为89的设备节点,实现了文件操作接口,用户空间可以通过i2c设备节点访问i2c适配器。
(1)打开适配器
[mw_shl_code=c,true]if ((fd = open("/dev/i2c-1",O_RDWR)) < 0) {
/* 错误处理 */
exit(1);
}[/mw_shl_code] 打开适配器对应的设备节点,i2c-dev为打开的线程建立一个i2c_client,但是这个i2c_client并不加到i2c_adapter的client链表当中。当用户关闭设备节点时,它自动被释放。
(2)设置地址模式[mw_shl_code=c,true]if (ioctl(fd, I2C_TENBIT, 0) < 0) {
/* 错误处理 */
exit(1);
}[/mw_shl_code]
0表示7比特模式,非0表示10比特模式,默认是7比特模式。
(3)设置从机地址
[mw_shl_code=c,true]if (ioctl(fd, I2C_SLAVE_FORCE, slave_addr) < 0) {
/* 错误处理 */
exit(1);
}[/mw_shl_code]
在调用read()和write()函数之前必须设置从机地址。
(4)读写操作
对I2C的读写操作可以参考内核源码中相关文档介绍,这里不再介绍
文档:Documentation/i2c/dev-interface
用户空间读写I2C EEPROM例子
1.twi.c文件:[mw_shl_code=c,true]#include "twi.h"
#include "i2c-dev.h"
#include <linux/types.h>
#define PAGE_SIZE 128
/* I2C file description */
static int fd;
/* I2C initialize flag */
static RET_STATUS init_flag = FAILD;
/* Send buffer */
static char buffer[PAGE_SIZE + 2];
RET_STATUS i2c_init(const char *dev_pathname, long slave_addr)
{
if (!dev_pathname) {
return FAILD;
}
/* Open i2c device */
fd = open(dev_pathname, O_RDWR);
if (fd < 0) {
perror("[info] Open i2c device error");
return FAILD;
}
/* Set i2c addresses with normal 7 bit */
if (ioctl(fd, I2C_TENBIT, 0) < 0) {
perror("[info] Ioctl i2c TENBIT error");
return FAILD;
}
/* Set slave device address */
if (ioctl(fd, I2C_SLAVE_FORCE, slave_addr) < 0) {
perror("[info] Ioctl i2c slave error");
return FAILD;
}
init_flag = SUCCESS;
return SUCCESS;
}
RET_STATUS i2c_write(const char *send_buf, int addr, int *num)
{
int send_bytes = 0;
int count = 0;
int res;
int i;
char buf[3];
if (init_flag == FAILD) {
printf("[info] I2C hasn't initialized.\n");
return FAILD;
}
if (!send_buf) {
return FAILD;
}
if (*num > strlen(send_buf)) {
*num = strlen(send_buf);
}
for (i = 0; i < *num; ++i,++addr) {
buf[0] = addr >> 8;
buf[1] = addr;
buf[2] = *(send_buf + i);
/*
* 根据at24c512b写字节时序
* 设备地址,2个8位数据地址,1个8位数据
*/
res = i2c_smbus_write_word_data(fd, buf[0], buf[2] << 8 | buf[1]);
usleep(5000);
if (res < 0) {
perror("[info] Writing occur error");
return FAILD;
}
count += res;
}
*num = count;
return SUCCESS;
}
RET_STATUS i2c_read(char *recv_buf, int addr, const int buf_size, int *num)
{
char buf[2];
int res;
int i;
int count = 0;
if ((recv_buf == NULL) ||
(buf_size < 0) ||
(*num < 0)) {
return FAILD;
}
buf[0] = addr >> 8;
buf[1] = addr;
/*
* 设置读数据的起始地址
*/
res = i2c_smbus_write_byte_data(fd, buf[0], buf[1]);
if (res < 0) {
perror("[info] Writing address occur error");
return FAILD;
}
for (i = 0; i < *num; ++i) {
*(recv_buf + i) = i2c_smbus_read_byte(fd);
if (*(recv_buf + i) < 0) {
perror("[info] Reading occur error");
break;
}
++count;
}
*(recv_buf + count) = '\0';
*num = count;
if (*num > count) {
return FAILD;
}
return SUCCESS;
}
void i2c_deinit(void)
{
close(fd);
}
[/mw_shl_code]
2.main.c文件:
[mw_shl_code=c,true]#include "twi.h"
#define I2C_DEV "/dev/i2c-0"
#define SLAVE_ADDR 0x51
#define BUF_SIZE 128
int main(int argc, char *argv[])
{
char send_data[BUF_SIZE] = "This is test data, If reading this string, Testing is successful";
char recv_data[BUF_SIZE] = { 0 };
int len = 0;
int addr = 0x10;
printf("Initialize i2c device\n");
if (i2c_init(I2C_DEV, SLAVE_ADDR) == FAILD) {
printf("[info] Initialize i2c faild\n");
return 1;
}
printf("Write data to eeprom 0x%x via I2C\n", addr);
len = strlen(send_data);
if (i2c_write(send_data, addr, &len) == FAILD) {
printf("[info] Write data to eeprom faild\n");
return 2;
}
sleep(1);
printf("Read data from eeprom 0x%x via I2C\n", addr);
len = BUF_SIZE - 1;
if (i2c_read(recv_data, addr, BUF_SIZE, &len) == FAILD) {
printf("[info] Read data from eeprom faild\n");
return 3;
}
printf("Read content: %s\n", recv_data);
return 0;
}
[/mw_shl_code]
3.完整程序见附件
|