eCos Bit-Bang I2C

1 I2C总线协议
I2C协议
2条双向串行线,一条数据线SDA,一条时钟线SCL。
SDA传输数据是大端传输(字节高位先传),每次传输8bit,即一字节。
支持多主控(multimastering),任何时间点只能有一个主控。
总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.

I2C开始和结束信号
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

I2C位传输
数据传输:SCL为高电平时,SDA线必须保持稳定,SDA上传输一个bit数据;
数据改变:SCL为低电平时,SDA线才能改变电平

I2C应答信号
主控每发送完8bit数据后等待从设备ACK。
即在第9个clock,若从设备发回ACK,SDA会被拉低。
若没有ACK,SDA会被置高,这会引起主控发生RESTART或STOP流程

I2C写流程
写寄存器的标准流程为:
1. Master发起START
2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
3. Slave发送ACK
4. Master发送reg addr(8bit),等待ACK
5. Slave发送ACK
6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK
7. Slave发送ACK
8. 第6步和第7步可以重复多次,即顺序写多个寄存器
9. Master发起STOP

I2C读流程
读寄存器的标准流程为:
1. Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
2. Slave发送ACK
3. Master发送reg addr(8bit),等待ACK
4. Slave发送ACK
5. Master发起START
6. Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
7. Slave发送ACK
8. Slave发送data(8bit),即寄存器里的值
9. Master发送ACK
10. 第8步和第9步可以重复多次,即顺序读多个寄存器

基本通信流程
1、 主设备发出开始信号(Start)。
2、 主设备发出1字节的从设备地址信息,其中最低位为读写控制码(0为写,1为读),高7位为从机器地址码。
3、 从设备发出认可信号。
4、 主设备开始对从设备进行读写操作。如果是读操作,则每读取1字节,主设备会发送一个应答信号(Ack)给从设备,如果是写操作,则每写入1字节,从设备会发送一个应答信号(Ack)给主设备。
5、 主设备发出结束信号(Stop)。

2 DECLARE_I2C_GPIO

/*
 * BUS IDLE: SDA & SCL HIGH
 * SCL HIGH: data stable, sample SDA
 * SCL LOW:  data change, disable sample
 */

typedef struct {
    uint16_t sda;
    uint16_t scl;
} i2c_gpio_t;

#define DECLARE_I2C_GPIO(NAME, SDA, SCL, FREQ)  \
    static const i2c_gpio_t i2c_gpio_##NAME =   \
{SDA, SCL};

DECLARE_I2C_GPIO(gpiomux, 12, 11, 100);

static void i2c_writebit(i2c_gpio_t *handle, u8 a);

static inline u32 translate_addr(u32 addr)
{
    u32 phy_addr = addr;

    // kseg1: 0xA000 0000 - 0xBFFF FFFF(512M)
    phy_addr &= 0x0FFFFFFC;
    //phy_addr &= 0x0FFFFFFF;
    phy_addr |= 0xb0000000;

    return phy_addr;
}

static int8_t gpio_get_value_v2(u8 gpio)
{
    uint32_t addr;

    if (gpio <= 31) {
        // GPIO_DATA_0
        addr = translate_addr(0x10000620);
    } else if (gpio >= 32 && gpio <= 63) {
        // GPIO_DATA_1
        addr = translate_addr(0x10000624);
        gpio = gpio - 32;
    } else {
        // 64 ... 95
        // GPIO_DATA_2
        addr = translate_addr(0x10000628);
        gpio = gpio - 64;
    }

    return ((HAL_REG32(addr) >> gpio) & 0x1);
}

static void gpio_set_value_v2(u8 gpio, u8 value)
{
    uint32_t addr, reg_val;

    if (gpio <= 31) {
        if (value > 0) {
            // GPIO_DSET_0
            addr = translate_addr(0x10000630);
        } else {
            // GPIO_DCLR_0
            addr = translate_addr(0x10000640);
        }
    } else if (gpio >= 32 && gpio <= 63) {
        if (value > 0) {
            // GPIO_DSET_1
            addr = translate_addr(0x10000634);
        } else {
            // GPIO_DCLR_1
            addr = translate_addr(0x10000644);
        }
        gpio = gpio - 32;
    } else {
        // 64 ... 95
        if (value > 0) {
            // GPIO_DSET_2
            addr = translate_addr(0x10000638);
        } else {
            // GPIO_DCLR_2
            addr = translate_addr(0x10000648);;
        }
        gpio = gpio - 64;
    }

    reg_val = HAL_REG32(addr);
    reg_val |= (1 << gpio);
    HAL_REG32(addr) = reg_val;
}

static void SDAIN(i2c_gpio_t *handle)
{
    u8 gpio = handle->sda;
    u32 addr, reg_val;

    if (gpio <= 31) {
        // GPIO_CTRL_0
        addr = translate_addr(0x10000600);
    } else if (gpio >= 32 && gpio <= 63) {
        // GPIO_CTRL_1
        addr = translate_addr(0x10000604);
        gpio = gpio - 32;
    } else {
        // 64 ... 95
        // GPIO_CTRL_2
        addr = translate_addr(0x10000608);
        gpio = gpio - 64;
    }

    reg_val = HAL_REG32(addr);
    reg_val &= ~(1 << gpio);
    HAL_REG32(addr) = reg_val;
}

static void SDAOUT(i2c_gpio_t *handle)
{
    int gpio = handle->sda;
    u32 addr, reg_val;

    if (gpio <= 31) {
        // GPIO_CTRL_0
        addr = translate_addr(0x10000600);
    } else if (gpio >= 32 && gpio <= 63) {
        // GPIO_CTRL_1
        addr = translate_addr(0x10000604);
        gpio = gpio - 32;
    } else {
        // 64 ... 95
        // GPIO_CTRL_2
        addr = translate_addr(0x10000608);
        gpio = gpio - 64;
    }

    reg_val = HAL_REG32(addr);
    reg_val |= 1 << gpio;
    HAL_REG32(addr) = reg_val;
}

/*
 * MT7628K CPU freq = 580/575 MHz, about 1.72 ns, 1 us = 581 clock
 * ESP8266 CPU freq = 80 MHz, about 12.5 ns, 1 us = 80 clock
 *
 * 100 kHz = 100,000, about 10 us
 * 400 kHz = 400,000, about 2.5 us
 *
 */
static void delay5us(void)
{
    uint16_t i = 50;

    while(i--);
}

static void sendack(i2c_gpio_t *handle)
{
    i2c_writebit(handle, 0);
}

static void sendnack(i2c_gpio_t *handle)
{
    i2c_writebit(handle, 1);
}

static void i2c_start(i2c_gpio_t *handle)
{
    SDAOUT(handle);
    gpio_set_value_v2(handle->sda, 1);
    delay5us();
    gpio_set_value_v2(handle->scl, 1);
    delay5us();
    gpio_set_value_v2(handle->sda, 0);
    delay5us();
    gpio_set_value_v2(handle->scl, 0);
    delay5us();
}

static void i2c_stop(i2c_gpio_t *handle)
{
    SDAOUT(handle);
    gpio_set_value_v2(handle->sda, 0);
    delay5us();
    gpio_set_value_v2(handle->scl, 1);
    delay5us();
    gpio_set_value_v2(handle->sda, 1);
    delay5us();
    gpio_set_value_v2(handle->scl, 0);
    delay5us();
}

static void wait_ack(i2c_gpio_t *handle)
{
    uint16_t i;

    gpio_set_value_v2(handle->scl, 0);
    delay5us();
    SDAIN(handle);
    delay5us();
    gpio_set_value_v2(handle->scl, 1);
    delay5us();
    while(gpio_get_value_v2(handle->sda) && (i < 0x2b0)) {
        i++;
    }

    gpio_set_value_v2(handle->scl, 0);
    delay5us();
}

static void i2c_writebyte(i2c_gpio_t *handle, u8 a)
{
    uint16_t i;

    SDAOUT(handle);
    for (i = 0; i < 8; i++) {
        gpio_set_value_v2(handle->scl, 0);
        delay5us();
        if (a & 0x80) {
            gpio_set_value_v2(handle->sda, 1);
        } else {
            gpio_set_value_v2(handle->sda, 0);
        }
        a = (a << 1);
        delay5us();
        gpio_set_value_v2(handle->scl, 1);
        delay5us();
    }
}

static void i2c_writebit(i2c_gpio_t *handle, u8 a)
{
    SDAOUT(handle);
    gpio_set_value_v2(handle->scl, 0);
    delay5us();
    if (a == 0) {
        gpio_set_value_v2(handle->sda, 0);
    } else {
        gpio_set_value_v2(handle->sda, 1);
    }
    delay5us();
    gpio_set_value_v2(handle->scl, 1);
    delay5us();
    gpio_set_value_v2(handle->scl, 0);
    delay5us();
}

static u8 i2c_readbyte(i2c_gpio_t *handle)
{
    u8 i, temp = 0;

    SDAIN(handle);
    gpio_set_value_v2(handle->scl, 0);
    delay5us();
    for (i = 0; i < 8; i++) {
        gpio_set_value_v2(handle->scl, 1);
        delay5us();
        temp =(temp << 1)|gpio_get_value_v2(handle->sda);
        delay5us();
        gpio_set_value_v2(handle->scl, 0);
        delay5us();
    }
    return temp;
}

void i2c_init(i2c_gpio_t *handle)
{
    // pin mux
    // Reference to "MT7628 PROGRAMMING GUIDE", p15 of System Control
    // GPIO1_MODE 0x10000060
    // GPIO2_MODE 0x10000064
    gpio_set_value_v2(handle->sda, 1);
    gpio_set_value_v2(handle->scl, 1);
}

void i2c_byte_write(i2c_gpio_t *handle, u8 saddr, u8 reg, u8 val)
{
    i2c_start(handle);
    i2c_writebyte(handle, saddr);
    wait_ack(handle);
    i2c_writebyte(handle, reg);
    wait_ack(handle);
    i2c_writebyte(handle, val);
    wait_ack(handle);
    i2c_stop(handle);
}

u8 i2c_byte_read(i2c_gpio_t *handle, u8 saddr, u8 reg)
{
    u8 temp;

    i2c_start(handle);
    i2c_writebyte(handle, saddr);
    wait_ack(handle);
    delay5us();
    i2c_writebyte(handle, reg);
    wait_ack(handle);
    i2c_start(handle);
    i2c_writebyte(handle, saddr + 1);
    wait_ack(handle);
    temp = i2c_readbyte(handle);
    sendnack(handle);
    i2c_stop(handle);

    return temp;
}

static void acc_i2c_init(void)
{
    i2c_init(&i2c_gpio_gpiomux);
}
module_init(acc_i2c_init);
 

发布了124 篇原创文章 · 获赞 51 · 访问量 32万+

猜你喜欢

转载自blog.csdn.net/zoosenpin/article/details/73332314
I2C