在配置i2c从设备寄存器时往往需要修改驱动中的初始化函数来修改寄存器的值,这样往往需要重新编译内核,其实可以使用i2c驱动提供给应用层的接口函数ioctl来在命令行修改寄存器,只需要编写一个类似i2c测试程序的程序文件,使用int main(int argc, char **argv) 来向程序传递参数即可实时读写从设备的寄存器,工作队列(workqueue)可以实现多个寄存器的取值。
#include <stdio.h>
#include <linux/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#define MAX_I2C_MSG 2
#define I2C_RETRIES 0x0701
#define I2C_TIMEOUT 0x0702
#define I2C_RDWR 0x0707
#define ADV7180_REG_NUM 253 /*连续读的寄存器个数*/
#define ADV7180_REG_BASE_ADDR 0 /*要连续读的第一个寄存器的地址,此处从0x00开始连续读253个寄存器值*/
/*此函数作用是把从命令行输入的数字字符转换为十六进制数,即寄存器地址或值*/
int strtol_dzb(unsigned char *ps,int flag)
{
int i=10;
int r=0;
char *pc = ps;
if(NULL==ps ) return -1;
while(*pc != '\0')
{
if((*pc >= 'a' && *pc <= 'f') ||
(*pc >= 'A' && *pc <= 'F') ||
(*pc == 'x' || *pc == 'X') )
{
i=16;
}
else if( *pc < '0' || *pc > '9')
{
return -1;
}
pc++;
}
if(flag!=0) i=flag;
pc = ps;
while(*pc != '\0')
{
r *= i;
if( *pc>='a' && *pc <= 'f')
{
r += (*pc-'a')+10;
}
else if( *pc>='A' && *pc <= 'F')
{
r += (*pc-'A')+10;
}
else if( *pc>='0' && *pc <= '9')
{
r += (*pc-'0');
}
pc++;
}
return r;
}
/* 主函数,3种情况,一个参数时读出253个值;三个参数时为“./test -r 0x00”,读某个寄存器;四个参数时为“./test -w 0x00 0x11”,写寄存器00值为11。*/
int main(int argc, char **argv)
{
struct i2c_rdwr_ioctl_data work_queue;
unsigned char idx;
unsigned char mode=1;//1--read, 0--w;
unsigned int fd;
unsigned short slave_address=0x68;
unsigned short reg_address =ADV7180_REG_BASE_ADDR;//0x2c;
unsigned char val[256]={0};
unsigned char data_len=ADV7180_REG_NUM;
unsigned char data=0;
int ret,tmp;
fd = open("/dev/i2c-1",O_RDWR);
work_queue.nmsgs = MAX_I2C_MSG; /* 消息数量 */
work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs*sizeof(struct i2c_msg));
if (!work_queue.msgs)
{
printf("Memory alloc error\n");
close(fd);
return 0;
}
//printf("argc =%d \n",argc);
if(argc==1) // dump 7180
{
idx = reg_address;
val[idx]=idx;
(work_queue.msgs[0]).len = 1;
//(work_queue.msgs[0]).flags = 0;//I2C_M_WR;
(work_queue.msgs[0]).addr = slave_address;
(work_queue.msgs[0]).buf = &val[idx];
(work_queue.msgs[1]).len = data_len;
(work_queue.msgs[1]).flags = 1;//I2C_M_RD;
(work_queue.msgs[1]).addr = slave_address;
(work_queue.msgs[1]).buf = &val[idx];
ioctl(fd, I2C_TIMEOUT, 2); /* 设置超时 */
ioctl(fd, I2C_RETRIES, 1); /* 设置重试次数 */
ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
if (ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
}
else
{
printf("\n-----------------ADV7180 Reg-Test---------------------\n");
printf( "addr: 0 1 2 3 4 5 6 7 8 9 a b c d e f \n");
printf( "------------------------------------------------------");
for(idx = 0; idx < ADV7180_REG_NUM; idx++)
{
if(idx%16==0) printf("\n %02x: ", idx);
printf(" %02x", val[idx]);
}
printf("\n-----------------------END----------------------------\n");
}
}
else if(argc==2|| argc > 4)
{
printf("Usage: %s [[-r regAddr] | [-w regAddr byteData]]\n", argv[0]);
printf(" -r regAddr read a byte from register--regAddr of adv7180\n");
printf(" -w regAddr data write a byte data to register--regAddr of adv7180\n");
}
else
{
if(strstr(argv[1],"-r") ) // read a byte only
{
if(-1 == (tmp=(unsigned short)strtol_dzb(argv[2],16)) )
{
printf(" Invalid reg_addr: %s ",argv[2]);
close(fd);
return -1;
}
reg_address=(unsigned short)tmp;
printf("mode: read reg_addr: %3d (%02x) \n", reg_address, reg_address);
val[0]=(unsigned char)reg_address;
(work_queue.msgs[0]).len = 1;
(work_queue.msgs[0]).addr = slave_address;
(work_queue.msgs[0]).buf = &val[0];
(work_queue.msgs[1]).len = data_len;
(work_queue.msgs[1]).flags = 1;//I2C_M_RD;
(work_queue.msgs[1]).addr = slave_address;
(work_queue.msgs[1]).buf = &val[0];
work_queue.nmsgs=2;
ioctl(fd, I2C_TIMEOUT, 2); /* 璁剧疆瓒呮椂 */
ioctl(fd, I2C_RETRIES, 1); /* 璁剧疆閲嶈瘯娆℃暟 */
ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
if (ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
}
else
{
printf("Read: Reg--%02x Data--%02x \n", reg_address, val[0]);
}
}
else if( strstr(argv[1],"-w") ) // write a byte only
{
if(-1 == (tmp=(unsigned short)strtol_dzb(argv[2],16)) )
{
printf(" Invalid reg_addr: %s ",argv[2]);
close(fd);
return -1;
}
reg_address = (unsigned short)tmp;
if(-1 == (tmp=(unsigned short)strtol_dzb(argv[3],16)) )
{
printf(" Invalid data: %s ",argv[3]);
close(fd);
return -1;
}
data = (unsigned char)tmp;
printf("mode: write reg_addr: 0x%02x data: %x \n", reg_address, data);
val[0]=(unsigned char)reg_address;
val[1]=data;
(work_queue.msgs[0]).len = 2;
(work_queue.msgs[0]).flags = 0;//I2C_M_WR;
(work_queue.msgs[0]).addr = slave_address;
(work_queue.msgs[0]).buf = &val[0];
work_queue.nmsgs=1;
ioctl(fd, I2C_TIMEOUT, 2); /* 璁剧疆瓒呮椂 */
ioctl(fd, I2C_RETRIES, 1); /* 璁剧疆閲嶈瘯娆℃暟 */
ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
if (ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
}
#if 0
else
{
(work_queue.msgs[0]).len = 1;
(work_queue.msgs[0]).flags = 0;//I2C_M_WR;
(work_queue.msgs[0]).addr = slave_address;
(work_queue.msgs[0]).buf = &val[0];
(work_queue.msgs[1]).len = data_len;
(work_queue.msgs[1]).flags = 1;//I2C_M_RD;
(work_queue.msgs[1]).addr = slave_address;
val[idx]=0;
(work_queue.msgs[1]).buf = &val[0];
work_queue.nmsgs=2;
ioctl(fd, I2C_TIMEOUT, 2); /* 璁剧疆瓒呮椂 */
ioctl(fd, I2C_RETRIES, 1); /* 璁剧疆閲嶈瘯娆℃暟 */
ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
if (ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
}
else
{
printf("Write: reg--%02x w-data--%02x r-data--%02x \n", reg_address,data,val[0]);
}
}
#endif
}
}
close(fd);
return ;
}