Android 使用I2C读写(User space)

前言

Android 9.0
Telechips tcc803x

用户如何在userspace直接访问板上的i2c外设寄存器?

一、实现原理

通过I2C_RDWR这个IO控制命令将i2c_msg数组传递给kernel去执行。

二、实现步骤

Talk is cheap, show my codes.

I2CCtr.h

#ifndef XXX
#define XXX

#pragma once

	namespace I2C
	{

	    typedef enum i2c_opt_state
	    {
	        I2C_IOCTL_OK = 0,            /**< i2c ioctl OK */
	        I2C_IOCTL_NG,                /**< i2c ioctl NG */
	        I2C_READ_OK,	             /**< i2c read OK */
	        I2C_READ_NG,                 /**< i2c read NG */
	        I2C_WRITE_OK,		         /**< i2c write OK */
	        I2C_WRITE_NG, 	             /**< i2c write NG */
	    } i2c_opt_state;

	    struct i2c_msg {
	        __u16 addr;	/* slave address			*/
	        __u16 flags;
            #define I2C_M_RD		    0x0001	/* read data, from slave to master */
					                            /* I2C_M_RD is guaranteed to be 0x0001! */
            #define I2C_M_TEN		    0x0010	/* this is a ten bit chip address */
            #define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
            #define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
            #define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
            #define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
            #define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
            #define I2C_M_STOP		    0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
            /* Telechips */
            #define I2C_M_NO_STOP		0x0020
            #define I2C_M_MODE		    0x0040
            #define I2C_M_WR_RD		    0x0080
            #define I2C_M_WM899x_CODEC	0x0100
	        __u16 len;		/* msg length				*/
	        __u8 *buf;		/* pointer to msg data		*/
        };

        struct i2c_rdwr_ioctl_data {
	        struct i2c_msg __user *msgs;	/* pointers to i2c_msgs */
	        __u32 nmsgs;			        /* number of i2c_msgs */
        };
	
	    class I2CCtr 
	    {
	    public:
            I2CCtr(void);
            virtual ~I2CCtr(void);
		  
            int Open(const char *dev);
			int Write(const unsigned short slaveAddr, const unsigned short subAddr,
				const unsigned char *buf, const unsigned short len);
			int Read(const unsigned short slaveAddr, const unsigned short regAddr,
				unsigned char *buf, const unsigned short len);
		  		  	
        private:	
           int WriteInternal(const unsigned short slaveAddr, const unsigned short subAddr,
		   	const unsigned char *buf, const unsigned short len);
		   int ReadInternal(const unsigned short slaveAddr, const unsigned short regAddr,
		   	unsigned char *buf, const unsigned short len);
		   
           int fd;
		   struct i2c_rdwr_ioctl_data iic_data;
            	
	    };

	}

#endif // XXX

i2c_msg、i2c_rdwr_ioctl_data在不同平台上可以会不一样。替换kernel里的定义即可。

I2CCtr.cpp


#define LOG_TAG "I2C"


#include <log/log.h>
//#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include "I2CCtr.h"


I2CCtr::I2CCtr(void)
: fd(-1)
{
  
}

I2CCtr::~I2CCtr(void)
{
    if (fd > 0) {
        close(fd);
		free(iic_data.msgs);
    }
}

int I2CCtr::Open(const char *dev)
{
    if (fd == -1) {
        fd = open(dev, O_RDWR);
	    if (fd < 0) {
            ALOGE("%s open Error[%s].", dev, strerror(errno));
	    } else {
            ALOGI("I2C Open Success!!");
			iic_data.nmsgs = 2; 
	        iic_data.msgs = (struct i2c_msg*) malloc(iic_data.nmsgs*sizeof(struct i2c_msg));
	        if (!iic_data.msgs) {   
	            ALOGE("Memory alloc error");
	            close(fd);      
	            fd = -1;       
	        } else {
			    ioctl(fd, I2C_TIMEOUT, 2);
				ioctl(fd, I2C_RETRIES, 1);
	        }
	    }
    }

    return fd;
}

int I2CCtr::Read(const unsigned short slaveAddr, const unsigned short regAddr,
	unsigned char *dataBuf, const unsigned short len)
{
    if (fd < 0) {
        ALOGW("I2C is not open.");
		return I2C_READ_NG;
    }

	return ReadInternal(slaveAddr, regAddr, dataBuf, len);
}

int I2CCtr::ReadInternal(const unsigned short slaveAddr, const unsigned short regAddr,
	unsigned char *dataBuf, const unsigned short len)
{
	 unsigned char ucRegAddr = regAddr; 
	
	iic_data.nmsgs = 2;
	(iic_data.msgs[0]).addr  = slaveAddr;
	(iic_data.msgs[0]).len = 1;
	(iic_data.msgs[0]).buf = &ucRegAddr;
 
	(iic_data.msgs[1]).addr  = slaveAddr;
	(iic_data.msgs[1]).flags = I2C_M_RD;
	(iic_data.msgs[1]).len = len;
	(iic_data.msgs[1]).buf = dataBuf;
 
	if (ioctl(fd, I2C_RDWR, (unsigned long)&iic_data) < 0) {
	    ALOGE("Error[%s]: Failed to read from slave:0x%x reg:0x%x", strerror(errno), slaveAddr, regAddr);
		return I2C_READ_NG;
	}
	
    return I2C_READ_OK;
}

int I2CCtr::Write(const unsigned short slaveAddr, const unsigned short regAddr,
	const unsigned char *buf, const unsigned short len)
{
    if (fd < 0) {
        ALOGW("I2C is not open.");
		return I2C_WRITE_NG;
    }

	return WriteInternal(slaveAddr, regAddr, buf, len);
}

int I2CCtr::WriteInternal(const unsigned short slaveAddr, const unsigned short regAddr,
	const unsigned char *buf, const unsigned short len)
{
    unsigned char data[len + 1];    

	iic_data.nmsgs = 1;       
	(iic_data.msgs[0]).len = 1 + len; 
    (iic_data.msgs[0]).addr = slaveAddr;
	(iic_data.msgs[0]).flags = 0; //write   
    (iic_data.msgs[0]).buf = data;

    data[0] = regAddr;
    memcpy(data + 1, buf, len); 

	int ret = ioctl(fd, I2C_RDWR, (unsigned long)&iic_data);
	if( ret < 0 ) {  
        ALOGE("Error[%s]: Failed to write into slave:0x%x reg:0x%x", strerror(errno), slaveAddr, regAddr);
	    return I2C_WRITE_NG;
	}
    
    
    return I2C_WRITE_OK;
}

三、使用示例

    I2C::I2CCtr mI2CCtr = new I2C::I2CCtr();
    mI2CCtr->Open("/dev/i2c-7");

    const unsigned short len = 1;
    unsigned char buf[len] = {0};
    unsigned short regAddr = 0xFE;

    buf[0] = value; // 写入value值

    if (mI2CCtr->Write(SLAVEADDRESS_ADV7511W, regAddr, buf, len) == I2C::I2C_WRITE_NG) {
        ALOGE("Error to write slave:0x%x reg:0x%x ", SLAVEADDRESS_ADV7511W, regAddr); 
    } else {
        ALOGV("Write 0x%x into slave:0x%x reg:0x%x ", buf[0], SLAVEADDRESS_ADV7511W, regAddr); 
    }
    
    if (mI2CCtr->Read(SLAVEADDRESS_ADV7511W, regAddr, buf, len) == I2C::I2C_READ_OK) {
        ALOGV("Read 0x%x from slave:0x%x reg:0x%x ", buf[0], SLAVEADDRESS_ADV7511W, regAddr); 
    } else {
        ALOGE("Error to read slave:0x%x reg:0x%x ", SLAVEADDRESS_ADV7511W, regAddr); 
    }    

注意:操作i2c结节时,可能会出现selinux avc:denied错误。修改te文件添加权限即可。

四、总结

Linux上,一切皆为文件。操作i2c也如此。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值