linux下的I2c 和展锐8310下的I2c

I2C物理层

它是一个支持设备的总线。“总线”指多个设备共用的信号线。在一个I2C通讯总线中,可连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机。

·一个I2C总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

·每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。

·总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

·多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

·具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模下可达3.4Mbit/s,但目前大多I2C设备尚不支持高速模式。

I2C协议层

以主机向从机写数据为例,其基本结构如图所示,依次为:
起始信号——从机地址——读写信号——数据位——应答位——… … ——停止位

 

起始信号(S):当 SCL 线是高电平时,SDA 线从高电平向低电平切换;停止信号(P):当 SCL 是高电平时,SDA 线由低电平向高电平切换。

 

 

应答信号

I2C最大的一个特点就是有完善的应答机制,从机接收到主机的数据时,会回复一个应答信号来通知主机表示“我收到了”。

应答信号出现在1个字节传输完成之后,即第9个SCL时钟周期内,此时主机需要释放SDA总线,把总线控制权交给从机,由于上拉电阻的作用,此时总线为高电平,如果从机正确的收到了主机发来的数据,会把SDA拉低,表示应答响应。

非应答信号

当第9个SCL时钟周期时,SDA保持高电平,表示非应答信号。

帧地址:I2C总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA信号线发送设备地址(SLAVE_ADDRESS)来查找从机。I2C协议规定设备地址可以是7位或10位,实际中7位的地址应用比较广泛。

I2C使用SDA信号线来传输数据,使用SCL信号线进行数据同步。SDA数据线在SCL的每个时钟周期传输一位数据。传输时,SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。

I2C的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。

作为数据接收端时,当设备(无论主从机)接收到I2C传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,发送方接收到该信号后会产生一个停止信号,结束信号传输。

 

 Linux代码



int linux_common_i2c_write(struct i2c_client *client, uint8_t *reg_addr, uint8_t *txbuf, int count)
{
    int ret = -1;
    int ii = 0;
    uint8_t buf[MAX_XFER_SIZE + 1] = {0};
    struct i2c_msg msg[1];

    if(count > HX9031A_MAX_XFER_SIZE) {
        count = HX9031A_MAX_XFER_SIZE;
        PRINT_ERR("block write over size!!!\n");
    }
    buf[0] = *reg_addr;
    memcpy(buf + 1, txbuf, count);

    msg[0].addr = client->addr;   //要写的寄存器地址和数据
    msg[0].flags = 0;//write      //读写操作,读为1 写为0
    msg[0].len = count + 1;       // 要读的字节数
    msg[0].buf = buf;             //数据存放的地址

    ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    if (ARRAY_SIZE(msg) != ret) {
        PRINT_ERR("linux_common_i2c_write failed. ret=%d\n", ret);
        ret = -1;
        for(ii = 0; ii < msg[0].len; ii++) {
            PRINT_ERR("msg[0].addr=0x%04X, msg[0].flags=0x%04X, msg[0].len=0x%04X, msg[0].buf[%02d]=0x%02X\n",
                      msg[0].addr,
                      msg[0].flags,
                      msg[0].len,
                      ii,
                      msg[0].buf[ii]);
        }
    } else {
        ret = 0;
    }

    return ret;
}


lin linux_common_i2c_read(struct i2c_client *client, uint8_t *reg_addr, uint8_t *rxbuf, int count)
{
    int ret = -1;
    int ii = 0;
    struct i2c_msg msg[2];

    if(count > MAX_XFER_SIZE) {
        count = MAX_XFER_SIZE;
        PRINT_ERR("block read over size!!!\n");
    }
    //先写需要读的寄存器地址
    msg[0].addr = client->addr;  //要读的寄存器地址
    msg[0].flags = 0;//write     //读写操作,读为1 写为0
    msg[0].len = 1;
    msg[0].buf = reg_addr;
    //再读数据
    msg[1].addr = client->addr;
    msg[1].flags = I2C_M_RD;//read
    msg[1].len = count;
    msg[1].buf = rxbuf;

    ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    if (ARRAY_SIZE(msg) != ret) {
        PRINT_ERR("linux_common_i2c_read failed. ret=%d\n", ret);
        ret = -1;
        PRINT_ERR("msg[0].addr=0x%04X, msg[0].flags=0x%04X, msg[0].len=0x%04X, msg[0].buf[0]=0x%02X\n",
                  msg[0].addr,
                  msg[0].flags,
                  msg[0].len,
                  msg[0].buf[0]);
        if(msg[1].len >= 1) {
            for(ii = 0; ii < msg[1].len; ii++) {
                PRINT_ERR("msg[1].addr=0x%04X, msg[1].flags=0x%04X, msg[1].len=0x%04X, msg[1].buf[%02d]=0x%02X\n",
                          msg[1].addr,
                          msg[1].flags,
                          msg[1].len,
                          ii,
                          msg[1].buf[ii]);
            }
        }
    } else {
        ret = 0;
    }

    return ret;
}

8310代码

struct i2c_msg {
	uint16 addr;/* slave address */
	uint16 flags;
    #define I2C_M_TEN			0x0010	/* this is a ten bit chip address */
    #define I2C_M_RD			0x0001	/* read data, from slave to master */
    #define I2C_M_STOP			0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
    #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 */
	uint16 len;		/* msg length */
	uint8 *buf;		/* pointer to msg data */
};
struct SPRD_I2C sprd_i2c[I2C_DEVICE_MAX] = {
	{
		/*i2c0*/
		CTL_I2C0_BASE,
		400000,
		0,
		12,
		1,
		TB_I2C0_INT,
		REG_AP_CLK_CORE_CGM_I2C0_CFG,
		I2C_26M,
		REG_AP_APB_APB_EB,
		BIT_AP_APB_I2C0_EB,
		REG_AP_APB_APB_RST,
		BIT_AP_APB_I2C0_SOFT_RST,
		1,
		DMA_I2C0_TX,
		DMA_I2C0_RX,
	},
	{
		/*i2c1*/
		CTL_I2C1_BASE,
		100000,
		1,
		12,
		1,
		TB_I2C1_INT,
		REG_AP_CLK_CORE_CGM_I2C1_CFG,
		I2C_26M,
		REG_AP_APB_APB_EB,
		BIT_AP_APB_I2C1_EB,
		REG_AP_APB_APB_RST,
		BIT_AP_APB_I2C1_SOFT_RST,
		0,                    //DMA使能位打开可能会影响读的正确性
		DMA_I2C1_TX,
		DMA_I2C1_RX,
	},
	{
		/*i2c2*/
		CTL_I2C2_BASE,
		400000,
		1,
		12,
		1,
		TB_I2C2_INT,
		REG_AP_CLK_CORE_CGM_I2C2_CFG,
		I2C_26M,
		REG_AP_APB_APB_EB,
		BIT_AP_APB_I2C2_EB,
		REG_AP_APB_APB_RST,
		BIT_AP_APB_I2C2_SOFT_RST,
		1,
		DMA_I2C2_TX,
		DMA_I2C2_RX,
	},

};
int i2c_write(uint8_t addr, uint8_t *txbuf, int count)
{
    int ret = -1, transfer = -1, config_msg = -1, close = -1;
    uint8_t buf[32 + 1] = {0};
    buf[0] = addr;
    memcpy(buf + 1, txbuf, count);
    struct i2c_client MEIG_IIC;
    MEIG_IIC.index = 1;
    struct i2c_msg msgs[2];
    ret = I2C_Open(&MEIG_IIC);
    if(ret == -1){
        return -1;
    }
    MG_LOGD( "mg_i2c_write ret =%d", ret );
    msgs[0].buf = buf; //寄存器地址加要写的数据
	msgs[0].len = count + 1 ;
	msgs[0].flags = 0; //读写为似乎不起作用
	msgs[0].addr = 0x50; //寄存器地址左移一位,最后一位为读写位  寄存器地址为0x28 即00101000 左移一位最后一位为读写位 即01010000
    transfer = i2c_transfer((uint32)MEIG_IIC.i2c, msgs, 1);
    MG_LOGD( "mg_i2c_write transfer =%d", transfer );
    close = I2C_Close((uint32)(&MEIG_IIC));
    if(close == -1){
        return -1;
    }
    MG_LOGD( "mg_i2c_write close =%d", close );
    return 0;
};


int i2c_read(uint8_t addr, uint8_t *rxbuf, int count)
{

    int ret = -1, transfer = -1, config_msg = -1, close = -1;
    struct i2c_client MEIG_IIC;
    MEIG_IIC.index = 1;        //i2c设备
    struct i2c_msg msgs[2];
    ret = I2C_Open(&MEIG_IIC);
    if(ret == -1){
        return -1;
    }
    MG_LOGD( "mg_i2c_read ret =%d", ret );
    msgs[0].buf = &addr;
	msgs[0].len = 1;     //读写为似乎不起作用
	msgs[0].flags = 0;
	msgs[0].addr = 0x50; //寄存器地址左移一位,最后一位为读写位  寄存器地址为0x28 即00101000 左移一位最后一位为读写位 即01010000
	msgs[1].buf = rxbuf; 
	msgs[1].len = count;
	msgs[1].flags = I2C_M_RD; //读写为似乎不起作用
	msgs[1].addr = 0x51; //寄存器地址左移一位,最后一位为读写位  寄存器地址为0x28 即00101000 左移一位最后一位为读写位 即01010001
    transfer = i2c_transfer((uint32)MEIG_IIC.i2c,  msgs ,2);
    uint8_t  reg_value = *(msgs[1].buf);
    MG_LOGD( "mg_i2c_read transfer =%d ,reg_value = %x", transfer ,rxbuf[0] );
    close = I2C_Close((uint32)(&MEIG_IIC));
    if(close == -1){
        return -1;
    }
    MG_LOGD( "mg_i2c_read close =%d", close );
    return 0;
};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 展锐ResearchDownload是一款用于展锐芯片设备的刷机工具。展锐是一家中国的半导体公司,其芯片广泛应用于手机、平板电脑、智能家居等领域。展锐ResearchDownload支持展锐芯片设备的刷机、升级、修复等操作。用户可以通过该工具将新的固件刷入设备中,以达到优化系统、修复Bug、增加新功能的目的。展锐ResearchDownload不仅支持展锐芯片设备,还支持MTK、Spreadtrum等芯片平台的设备。在使用该工具时,需要注意备份好重要数据,同时确认固件为官方固件,避免使用非官方来源的固件造成设备损坏。总的来说,展锐ResearchDownload是展锐芯片设备的重要工具之一,为用户提供了方便、快捷的刷机和升级服务,是值得信赖和使用的软件。 ### 回答2: 展锐researchdownload是一个专门用于展锐处理器的刷机工具,可以将展锐处理器的固件刷入到手机等设备中。展锐researchdownload具有简单易用、速度快、可靠稳定等特点。它支持的刷机操作包括刷入系统和刷入BootLoader,同时也支持底层配置。使用展锐researchdownload刷机可以解决一些系统问题,提升设备运行速度,更换新的功能和特性等。在操作时,用户需要将手机等设备连接到计算机上,并较详细地设置好参数和选项,如串口号、Baudrate、CPU/Flash型号等。展锐researchdownload也具有校验和修复功能,可以检测和修复制作过程中产生的缺陷。总之,展锐researchdownload是刷机必备的重要工具之一,对于展锐处理器的用户来说,熟练掌握和使用它可以更好地提升设备性能和体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值