使用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);

相关推荐
_She0011 小时前
滤波器 变压器 功分器 的笔记
嵌入式硬件
大神与小汪2 小时前
STM32WB55串口蓝牙模块
stm32·单片机·嵌入式硬件
蝎蟹居2 小时前
GBT 4706.1-2024逐句解读系列(25) 第7.5条款:不同电压功率需清晰明确
人工智能·单片机·嵌入式硬件·物联网·安全
独处东汉3 小时前
AI辅助Stm32l031项目开发调试板子之按键跟adc
stm32·单片机·嵌入式硬件
爱潜水的小L3 小时前
自学嵌入式day48,温度传感器
单片机·嵌入式硬件
电子绿洲3 小时前
什么是红外接收头?红外遥控系统核心元件基础知识解析
单片机·嵌入式硬件·智能硬件·硬件电路·硬件设计
乡野码圣4 小时前
【RK3588 Android12】开发效率提升技巧
android·嵌入式硬件
蓁蓁啊4 小时前
GCC 头文件搜索路径:-I vs -idirafter 深度解析
java·前端·javascript·嵌入式硬件·物联网
Xx香菜6 小时前
单片机—4
单片机·嵌入式硬件