使用uboot学习I2C

目录

一,I2C的理论基础

二,I2C的寄存器和概念

三,I2C的函数

1,rk3288_i2c_start

2,rk3288_i2c_stop

3,rk3288_i2c_read

4,rk3288_i2c_write

5,i2c_rk3288_xfer

6,rk3288_i2c_set_rate

四,I2C设备读写实例

[五,I2c slave设备syr827的使用,](#五,I2c slave设备syr827的使用,)

1,syr827函数

regulator_syr82x_set_enable

regulator_syr82x_set_voltage

2,syr827重要寄存器

一,I2C的理论基础

二,I2C的寄存器和概念

NAK:no ack

I2C_CON = 0x000,

con_bit(0):1表示i2c_en

con_bit(2-1):00表示transmit only

con_bit(2-1):01表示transmit address--> restart --> transmit address --> receive only

con_bit(2-1):10表示receive only

con_bit(5):1表示master不应答

con_bit(6):1表示NAK时停止传输

I2C_CLKDIV = 0x004,

I2C_MRXADDR = 0x008,

I2C_MRXRADDR = 0x00c,

I2C_MTXCNT = 0x010,

I2C_MRXCNT = 0x014,

I2C_IEN = 0x018,

I2C_IPD = 0x01c,

ipd_bit(2):MTXCNT data transmit finished interrupt pending bit

ipd_bit(3):MRXCNT data received finished interrupt pending bit

ipd_bit(6):NAK handshake received interrupt pending bit

I2C_FCNT = 0x020,

I2C_TXDATA_BASE = 0x100,

I2C_RXDATA_BASE = 0x200,

三,I2C的函数

1,rk3288_i2c_start

(1)通过write32(I2C_IPD,0x7f)复位所有中断

(2)通过write32(I2C_CON,(1 << 0)|(1 << 3))使能和start i2c,bit(0):i2c_en,bit(3):i2c_start

(3)在10us内读取I2C_IPD的bit4(startipd)是否为1,若为1则写1复位,否则循环读取,超时则返回

(4)I2C_IPD是写0无效寄存器,所以写1复位只写bit4即可

2,rk3288_i2c_stop

(1)通过write32(I2C_IPD,0x7f)复位所有中断

(2)通过write32(I2C_CON,(1 << 0)|(1 << 4))使能和stop i2c,bit(0):i2c_en,bit(4):i2c_stop

(3)在10us内读取I2C_IPD的bit5(stopipd)是否为1,若为1则写1复位,否则循环读取,超时则返回

(4)I2C_IPD是写0无效寄存器,所以写1复位只写bit5即可

(5)通过write32(I2C_CON,0)停用i2c

3,rk3288_i2c_read

I2C_MRXRADDR寄存器用于存储I2C接收模式下的从机地址(包括读/写位)而 I2C_MRXADDR 寄存器可能用于配置I2C发送模式下的从机地址或作为通用地址寄存器

在I2C读时序中,主设备首先发送从设备地址(通过MRXADDR配置),然后发送寄存器地址(通过MRXRADDR配置),最后重新发送从设备地址(最低位设为1表示读操作),以完成寄存器读取

(1)通过write32(I2C_MRXADDR, (1 << 24) | (msg->addr << 1) | 1)配置从机地址,bit24是address low byte valid,地址左移1bit和协议对上7bit+r/w 位

(2)通过write32(I2C_MRXRADDR,0)发送从设备的寄存器地址,这里是0,有些i2c从设备有寄存器,比如sensor

(3)循环len,len为8bit buf的个数,每次循环最多处理32个字节

(4)循环第一次con_bit(2-1)=01,循环第二次及以后con_bit(2-1)=10

(5)write32(I2C_IPD,0x7f);write32(I2C_CON,con);write32(I2C_MRXCNT, bytes);con_bit0/5/6置1,bit2-1如第四条描述

(6)100ms内循环判断,如果ipd_bit(3)中断产生则ok,如果ipd_bit(6)中断产生或超时则失败返回

(7)通过read32(I2C_RXDATA_BASE)读取data,处理大小端,若len为奇数,大端模式buff[3]是空,不影响数据完整性

4,rk3288_i2c_write

(1)int len = msg->len + 1;表示deviceaddr+regaddr+data,多了一个deviceaddr

(2)write32(I2C_TXDATA_BASE)填充数据,处理大小端,第一次填充带上deviceaddr

(3)write32(I2C_IPD,0x7f);write32(I2C_CON, (1 << 6) | (0 << 1) | (1 << 0));write32(I2C_MTXCNT, bytes);con_bit(2-1):00表示transmit only

(4)100ms内循环判断,如果ipd_bit(2)中断产生则ok,如果ipd_bit(6)中断产生或超时则失败返回

(5)如果len大于32的话循环下一次

5,i2c_rk3288_xfer

(syr82x_read/syr82x_write)->->i2c_transfer->i2c_rk3288_xfer

(1)调用rk3288_i2c_start产生一个start信号

(2)循环msgs,因为xfer支持i2c读和i2c写,i2c读至少需要2个msg,先写地址,再读data,两个msg的flag不一样,所以需要循环

(3)在循环内如果index不等于0,再发送一个start信号

(4)在循环内,如果flag是写则调用rk3288_i2c_write,如果flag是读则调用rk3288_i2c_read,直到循环结束

(5)调用rk3288_i2c_stop产生一个stop信号

6,rk3288_i2c_set_rate

通过配置I2C_CLKDIV分频系数设置i2c的频率,分频系数通过getclk(link-pclk-i2c0)与设备树的频率参数所得

I2c0的parent是link-pclk-i2c0

时钟树是:

(cpll->gate-cpll/gpll->gate-gpll)->mux-pd-bus-src->div-pd-bus-src->div-pd-bus->gate-cpu-pclk->div-cpu-pclk->pclk-bus-pre->gate-pclk-i2c0->link-pclk-i2c0

四,I2C设备读写实例

syr82x_read(pdat->dev, SYR82X_VSEL0, &val);

static bool_t syr82x_read(struct i2c_device_t * dev, u8_t reg, u8_t * val)

{

struct i2c_msg_t msgs[2];

u8_t buf;

msgs[0].addr = dev->addr;

msgs[0].flags = 0;

msgs[0].len = 1;

msgs[0].buf = ®

msgs[1].addr = dev->addr;

msgs[1].flags = I2C_M_RD;

msgs[1].len = 1;

msgs[1].buf = &buf;

if(i2c_transfer(dev->i2c, msgs, 2) != 2)

return FALSE;

if(val)

*val = buf;

return TRUE;

}

syr82x_write(pdat->dev, SYR82X_VSEL0, val);

static bool_t syr82x_write(struct i2c_device_t * dev, u8_t reg, u8_t val)

{

struct i2c_msg_t msg;

u8_t buf[2];

buf[0] = reg;

buf[1] = val;

msg.addr = dev->addr;

msg.flags = 0;

msg.len = 2;

msg.buf = &buf[0];

if(i2c_transfer(dev->i2c, &msg, 1) != 1)

return FALSE;

return TRUE;

}

五,I2c slave设备syr827的使用,

1,syr827函数

regulator_syr82x_set_enable

syr82x_read(pdat->dev, SYR82X_VSEL0, &val);

if(enable)

val |= (0x1 << 7);

else

val &= ~(0x1 << 7);

syr82x_write(pdat->dev, SYR82X_VSEL0, val);

syr82x_read(pdat->dev, SYR82X_VSEL1, &val);

if(enable)

val |= (0x1 << 7);

else

val &= ~(0x1 << 7);

syr82x_write(pdat->dev, SYR82X_VSEL1, val);

regulator_syr82x_set_voltage

syr82x_read(pdat->dev, SYR82X_VSEL0, &val);

val &= ~(0x3f << 0);

val |= ((syr82x_vol_to_reg(voltage, 12500, 712500, 1500000) & 0x3f) << 0);

syr82x_write(pdat->dev, SYR82X_VSEL0, val);

syr82x_read(pdat->dev, SYR82X_VSEL1, &val);

val &= ~(0x3f << 0);

val |= ((syr82x_vol_to_reg(voltage, 12500, 712500, 1500000) & 0x3f) << 0);

syr82x_write(pdat->dev, SYR82X_VSEL1, val);

2,syr827重要寄存器

SYR82X_VSEL0 = 0x00,

SYR82X_VSEL1 = 0x01,

SYR82X_CTRL = 0x02,

syr82x_read(pdat->dev, SYR82X_CTRL, &val);

val &= ~(0x7 << 4);val |= (0x4 << 4);配置设置正电压跃变的转换速率10mV/2.4us

slew rate 就是电压转换速率(Slew Rate),简写为SR,简称压摆率其定义是在1微秒或者1纳秒等时间里电压升高的幅度

syr82x_write(pdat->dev, SYR82X_CTRL, val);

相关推荐
BackCatK Chen1 天前
第 8 篇:TMC2240 电机正反转实现|DIR 引脚控制 + 代码优化(稳定不抖动)
stm32·单片机·嵌入式硬件·保姆级教程·电机正反转·tmc2240·dir引脚控制
星马梦缘1 天前
EDA彩灯电路绘制
单片机·嵌入式硬件·物联网·pcb·eda·嘉立创
VekiSon1 天前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
来自晴朗的明天1 天前
14、光耦隔离电路(EL3H7)
单片机·嵌入式硬件·硬件工程
G***技1 天前
杰和IB3-272:以低功耗高性能打造新一代工业智能交互核心
单片机·嵌入式硬件·物联网
MAR-Sky1 天前
keil5中数据的不同定义和单片机(以stc8为例)里的对应关系(idata,xdata,data,code)
单片机·嵌入式硬件
项目題供诗1 天前
51单片机入门(八)
单片机·嵌入式硬件·51单片机
羽获飞1 天前
从零开始学嵌入式之STM32——9.STM32的时钟系统
stm32·单片机·嵌入式硬件
飞睿科技1 天前
乐鑫智能开关方案解析:基于ESP32-C系列的低功耗、高集成设计
嵌入式硬件·物联网·esp32·智能家居·乐鑫科技
来自晴朗的明天1 天前
13、NMOS 电源防反接电路
单片机·嵌入式硬件·硬件工程