天天看點

Linux/Android I2C測試

 1.  I2C測試工具

      1.1 Linux編譯:arm_xxxx_gcc i2c_test.c -o i2c_test

      1.2 Android編譯:

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS := -O2 -Wall 
LOCAL_SHARED_LIBRARIES := libutils libcutils libc
LOCAL_C_INCLUDES += 頭檔案路勁/include 
LOCAL_SRC_FILES := i2c_test.c
LOCAL_MODULE := i2c_test
include $(BUILD_EXECUTABLE)
           

  2. 測試代碼:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#define	I2S_NODE	"/dev/i2c-0"
#define ARRAY_SIZE(a)	(int)(sizeof(a) / sizeof((a)[0]))
#define	MAX_BUFFER_LEN	1024

static int i2c_open(const char *dev_name)
{
	int fd = open(dev_name, O_RDWR, 644);

  	if (fd < 0) {
    		fprintf(stderr, "Failed, open %s\n", dev_name);
    		return -ENODEV;
  	}

	return fd;
}

static int i2c_close(int fd)
{
	close(fd);
}

static int FD_VALID(int fd)
{
	int ret = fcntl(fd, F_GETFL) != -1 || errno != EBADF;

    	if (!ret)
		fprintf(stderr, "Failed, fd.%d !!!\n", fd);

    	return ret;
}

/*
 * I2C WRITE
 * slave /A buf[0] /A .. buf[n] /NA [S]
 */
static int i2c_msg_w(int fd, int slave, unsigned char *buf, int bytes)
{
	struct i2c_rdwr_ioctl_data rdwr;
	struct i2c_msg msgs[1];
	int ret;

	rdwr.msgs = msgs;
 	rdwr.nmsgs = 1;
 	rdwr.msgs[0].addr = (slave>>1);
 	rdwr.msgs[0].flags = !I2C_M_RD;
 	rdwr.msgs[0].len = (bytes);
 	rdwr.msgs[0].buf = (__u8 *)buf;

	ret = ioctl(fd, I2C_RDWR, &rdwr);
	if (ret < 0)
		return ret;

	return 0;
}

static int i2c_write(int fd, int slave, unsigned char *buf, int bytes)
{
	return i2c_msg_w(fd, slave, buf, bytes);
}

/*
 * I2C WRITE
 * slave /A buf[0] /A .. buf[n] /NA [S]
 */
static int i2c_read(int fd, int slave, unsigned char *buf, int bytes)
{
	struct i2c_rdwr_ioctl_data rdwr;
	struct i2c_msg msgs[1];
	int ret;

	rdwr.msgs = msgs;
 	rdwr.nmsgs = 1;
 	rdwr.msgs[0].addr = (slave>>1);
 	rdwr.msgs[0].flags = I2C_M_RD;
 	rdwr.msgs[0].len = bytes;
 	rdwr.msgs[0].buf = (__u8 *)buf;

	ret = ioctl(fd, I2C_RDWR, &rdwr);
	if (ret < 0)
		return ret;

	return 0;
}

static int i2c_read_stop(int fd, int addr,
			 unsigned char *w_buf, int w_len,
			 unsigned char *r_buf, int r_len)
{
	int ret;

	ret = i2c_write(fd, addr, w_buf, w_len);
	if (ret)
		return ret;

	ret = i2c_read(fd, addr, r_buf, r_len);
	if (ret)
		return ret;

	return 0;
}

static int i2c_read_nostop(int fd, int addr,
			   unsigned char *w_buf, int w_len,
			   unsigned char *r_buf, int r_len)
{
	struct i2c_rdwr_ioctl_data rdwr;
	struct i2c_msg msgs[2];
	int ret;

	rdwr.msgs = msgs;
 	rdwr.nmsgs = 2;

 	rdwr.msgs[0].addr = (addr>>1);
 	rdwr.msgs[0].flags = !I2C_M_RD;
 	rdwr.msgs[0].len = w_len;
 	rdwr.msgs[0].buf = (__u8 *)w_buf;

 	rdwr.msgs[1].addr = (addr>>1);
 	rdwr.msgs[1].flags = I2C_M_RD;
 	rdwr.msgs[1].len = r_len;
 	rdwr.msgs[1].buf = (__u8 *)r_buf;

	ret = ioctl(fd, I2C_RDWR, &rdwr);
	if (ret < 0)
		return ret;

	return 0;
}

static int i2c_probe(int fd, int port, unsigned char s, unsigned char e)
{
	int i, found = 0;

	printf("i2c.%d detect [0x%02x~0x%02x]\n", port, s, e);

	for (i = s; i < e; i += 2) {
		if (!i2c_write(fd, i, NULL, 0)) {
			printf("\t0x%02x [0x%02x:7b]\n", i, i>>1);
			found++;
		}
	}

	if (!found)
		printf("Not found\n");

	return found;
}

static void print_usage(void)
{
    	printf( "usage: i2c_test -p <port> -s <slave> -a <addr>,<addr bytes> -w <data>,.,. -r <bytes>\n"
    		"\n"
        	"\t-p port i2c-n, default 'i2c-0'\n"
            	"\t-s slave(8bit hex)\n"
            	"\t-a addr(hex): <addr>,<addr bytes>, addr bytes is 1 or 2\n"
            	"\t-w write(8bit hex) : 0xN,0xN,...\n"
            	"\t-r read bytes\n"
            	"\t-n nostop read\n"
            	"\t-c loop counts\n"
            	"\t-l read bytes length\n"
            	"\t-d detect i2c.n's devices (0x0 ~ 0xff)\n"
            	"\tEX>\n"
            	"\t write: addr 2byte:0xa0b0, data 2byte: 0x12,34\n"
            	"\t #> i2c_test -p 1 -s 10 -a a0b0,2 -w 12,34\n\n"
            	"\t read : addr 2byte:0xa0b0, data 2byte\n"
            	"\t #> i2c_test -p 1 -s 10 -a a0b0,2 -r 2\n"
		);
}

struct option_t {
	int port;
	unsigned int slave, addr;
	unsigned char buffer[MAX_BUFFER_LEN];
	int addr_bytes, read_bytes, write_bytes;
	bool read_mode, write_mode;
	int loops;
	int length;
	bool nostop;
	bool detect;
} OP = {
  	.port = 0,
  	.slave = 0,
  	.addr = 0,
  	.addr_bytes = 1,
  	.read_bytes = 1,
  	.write_bytes = 0,
	.write_mode = false,
	.read_mode = true,
	.loops = 1,
	.nostop = false,
	.detect = false,
};

static int parse_options(int argc, char **argv, struct option_t *op)
{
	int opt;
	char *ptr;
	int i = 0, ret = 0;

	if (argc == 1) {
		print_usage();
		return -EINVAL;
	}

  	op->port = 0, op->slave = 0, op->addr = 0;
	op->write_mode = false, op->read_mode = true;
	op->length = 1;
	op->loops = 1;
	op->nostop = false;
	op->detect = false;

  	memset(op->buffer, 0, sizeof(MAX_BUFFER_LEN));

	while (-1 != (opt = getopt(argc, argv, "hp:a:s:r:w:m:nl:c:d"))) {
		switch(opt) {
        	case 'p':
        		op->port = strtol(optarg, NULL, 10);
        		break;
        	case 's':
        		sscanf(optarg, "%x", &op->slave);
        		break;
        	case 'a':
        		ptr = strtok(optarg, ",");
        		op->addr = strtol(ptr, NULL, 16);

        		ptr = strtok(NULL, ",");
        		if (ptr)
        			op->addr_bytes = strtol(ptr, NULL, 10);
        		break;
        	case 'r':
       			op->read_bytes = strtol(optarg, NULL, 10);
       			op->read_mode = true;

       			if (op->read_bytes > MAX_BUFFER_LEN) {
				fprintf(stderr,
					"Failed, read bytes %d over max %d\n",
					op->read_bytes, MAX_BUFFER_LEN);
				ret = -EINVAL;
			}
			break;
        	case 'w':
			ptr = strtok(optarg, ",");
			op->buffer[0] = strtol(ptr, NULL, 16);
   			i++;

   			while( ptr = strtok(NULL, ","))
   				op->buffer[i++] = strtol(ptr, NULL, 16);

			op->write_bytes = i;
      			op->write_mode = true;

			if (op->write_bytes > MAX_BUFFER_LEN) {
				fprintf(stderr,
					"Failed, write bytes %d over max %d\n",
					op->write_bytes, MAX_BUFFER_LEN);
				ret = -EINVAL;
			}
       			break;
  		case 'n':
			op->nostop = true;
			break;
        	case 'l':
        		op->length = strtol(optarg, NULL, 10);
        		break;
		case 'c':
			op->loops = strtoll(optarg, NULL, 10);
			break;
		case 'd':
			op->detect = true;
			break;
		case 'h':
		default:
			print_usage();
			ret = -EINVAL;
			break;
		}
	}

	return ret;
}

int main(int argc, char **argv)
{
	struct option_t *op = &OP;
  	char dev_name[20] = { I2S_NODE };
  	unsigned char *c, *ptr = op->buffer;
  	int fd;
  	int addr, offs, size;
  	int i, n, cnt, ret;

	ret = parse_options(argc, argv, op);
	if (ret)
		return ret;

	sprintf(dev_name, "/dev/i2c-%d", op->port);

  	fd = i2c_open(dev_name);
	if (!FD_VALID(fd))
		return -EINVAL;

	if (op->detect) {
		unsigned char s = 0, e = 255;

		if (optind < argc)
			sscanf(argv[optind++], "%x", (unsigned int *)&s);

		if (optind < argc)
			sscanf(argv[optind++], "%x", (unsigned int *)&e);

		return i2c_probe(fd, op->port, s, e);
	}

	if (op->write_mode) {
		offs = op->addr_bytes;
		size = op->write_bytes;

		memmove(ptr + offs, ptr, size);

		/* set write address */
		for (i = 0; i < offs; i++)
			ptr[i] = (op->addr >> (8 * (offs - (i + 1)))) & 0xff;

		printf("[W] i2c.%d slave:0x%02x, addr:0x%x, bytes %d:%d\n",
			op->port, op->slave, op->addr, offs, size);

		for (cnt = 0; cnt < op->loops; cnt++) {
			ret = i2c_write(fd, op->slave, ptr, size + offs);
			if (ret) {
				fprintf(stderr,
					"Failed, [W] i2c.%d slave:0x%02x, addr:0x%x, bytes %d\n",
					op->port, op->slave, op->addr, size);
				goto exit;
			}

			if (op->loops > 1) {
				printf("\r[count:%d]", cnt);
				fflush(stdout);
			}
		}
	} else {
		offs = op->addr_bytes;
		size = op->read_bytes;

		printf("[R] i2c.%d slave:0x%02x, addr:0x%x, bytes %d:%d, %s, length:%d\n",
			op->port, op->slave, op->addr, offs, size,
			op->nostop ? "no stop" : "stop", op->length);

		for (cnt = 0; cnt < op->loops; cnt++) {
			for (n = 0, addr = op->addr; n < op->length; n++, addr++) {
				/* set write address */
				for (i = 0; offs > i; i++)
					ptr[i] = (addr >> (8 * (offs - (i + 1)))) & 0xff;

				if (op->nostop)
					ret = i2c_read_nostop(fd, op->slave, ptr, offs, ptr, size);
				else
					ret = i2c_read_stop(fd, op->slave, ptr, offs, ptr, size);

				if (ret) {
					fprintf(stderr,
						"Failed, [R] i2c.%d slave:0x%02x, addr:0x%x, bytes %d\n",
						op->port, op->slave, addr, size);
					goto exit;
				}

				if (op->loops > 1) {
					printf("\r[count:%d]", cnt);
					fflush(stdout);
				}

				if (cnt == op->loops - 1) {
					printf("[R] 0x%02x ", addr);
					for (i = 0; op->read_bytes > i; i++) {
						printf("[0x%02x]", ptr[i]);
						if (!((i + 1) % 8))
							printf("\n");
					}
					printf("\n");
				}
			}
		}
 	}

	return 0;
exit:
	i2c_close(fd);

  	return ret;
}