跳转至

I2C 使用指南*

第一章 概述*

i2c 是可配置,可综合和可编程的控制总线,为系统中集成电路之间的通信链路提供支持。它是一个简单的双线总线,带有用于系统控制的软件定义协议,用于温度传感器和电压电平转换器,通用 I/O,A/D 和 D/A 转换器,COREC 和许多类型的微处理器。

IIC 也称 I2C,是一个多主从的串行总线,由飞利浦公司发明的通讯总线,属于半双工同步传输类总线,仅由两条线就能完成多机通讯,一条 SCL 时钟线,另外一条双向数据线 SDA,IIC 总线要求每个设备 SCL/SDA 线都是漏极开路模式,因此必须带上拉电阻才能正常工作。I2C 协议占用引脚少,硬件实现简单,可扩展性强,I2C 数据传输速率有标准模式 (100kbps)、快速模式 (400kbps) 和高速模式 (3.4Mbps)。所有接到 I2C 总线设备上的串行数据 SDA 都接到总线的 SDA 上,各设备的时钟线 SCL 接到总线的 SCL 上。I2C 总线上的每个设备都自己一个唯一的地址,来确保不同设备之间访问的准确性。任何时间点上只能有一个主控,且 SCL 由主控控制

第二章 APUS I2C 功能描述*

2.1 功能特性*

  • 三路 I2C 总线控制器

  • 串行数据线 (SDA) 和串行时钟 (SCL) 组成

  • 支持标准模式 (100kbit/s)
  • 支持快速模式 (400kbit/s)
  • 支持高速模式 (3.4Mbit/s)
  • 支持主机模式和从机模式
  • 支持7-bit/10-bit寻址
  • 批量传输模式
  • 发送和接收缓冲区
  • 中断或轮询模式操作
  • 处理所有总线速度下的位和字节
  • DMA 握手接口
  • 可编程的 SDA 保持时间
  • 作为 I2C 系统中的主机时,仅作为主机编程
  • 作为 I2C 系统中的从站时,仅作为从站编程

第三章 i2C Master参考例子*

  • 具体接口细节请参看头文件apus/platform/drv-apus/include/gx_i2c.h

3.1 I2C Master读写寄存器数据*

方式一 I2C Master读写*

static int i2c_master_example(int argc, char * const argv[])
{
    padmux_set(I2C0_SCL_PIN, 10);
    padmux_set(I2C0_SDA_PIN, 11);

    /* 初始化i2c0 */
    gx_i2c_init(0);

    /* 设置i2c传输速度 */
    gx_i2c_set_speed(0, 1000);

    /* 初始化dma */
    gx_dma_init();

    unsigned char bus = 0, slv_addr = 0x57, address_width = 1;
    unsigned int reg = 0x09;
    unsigned char data = 0x03;
    unsigned short len = 1;
    int ret = -1;

    /* 使用i2c0向设备地址为0x57的slave的0x09寄存器写入0x03 */
    ret = gx_i2c_tx(bus, slv_addr, reg, address_width, &data, len);
    if (ret != 0) {
        printf("error\n");
        return ret;
    }

    /* 使用i2c0读取设备地址为0x57的slave的0x03寄存器 */
    ret = gx_i2c_rx(bus, slv_addr, reg, address_width, &data, len);
    if (ret != 0) {
        printf("error\n");
        return ret;
    }
    printf("data = %d\t\n", data);

    return 0;
}

COMMAND_EXPORT_ALIAS(i2c_master_example, i2c_master_example, "i2c_master_example");

方式二 i2C Master读写数据*

int i2c_master_example1(void)
{
    padmux_set(I2C0_SCL_PIN, 10);
    padmux_set(I2C0_SDA_PIN, 11);

    /* 初始化i2c0 */
    gx_i2c_init(0);

    /* 设置i2c传输速度 */
    gx_i2c_set_speed(0, 1000);

    /* 初始化dma */
    gx_dma_init();

    unsigned char bus = 0, slv_addr = 0x57;
    unsigned char data = 0x09;
    unsigned short len = 1;

    /* 使用i2c0向设备地址为0x57的slave写入0x09 */
    ret = gx_i2c_write(bus, slv_addr, &data, len);
    if (ret != 0) {
        printf("error\n");
        return ret;
    }

    /* 使用i2c0读取设备地址为0x09的slave */
    ret = gx_i2c_read(bus, slv_addr, &data, len);
    if (ret != 0) {
        printf("error\n");
        return ret;
    }

    return 0;
}
COMMAND_EXPORT_ALIAS(i2c_master_example1, i2c_master_example1, "i2c_master_example1");

方式三 i2C Master写数据*

int i2c_master_example2(void)
{
    padmux_set(I2C0_SCL_PIN, 10);
    padmux_set(I2C0_SDA_PIN, 11);

    /* 初始化i2c0 */
    gx_i2c_init(0);

    /* 设置i2c传输速度 */
    gx_i2c_set_speed(0, 1000);

    /* 初始化dma */
    gx_dma_init();

    void *i2c_dev = NULL;
    GX_I2C_MSG msgs;
    unsigned char data = 0x09;
    unsigned short len = 1;
    unsigned char bus = 0, slv_addr = 0x57;

    /* 打开i2c0 */
    i2c_dev = gx_i2c_open(bus);
    if (!i2c_dev) {
        i2c_debug("open i2c dev failed.\n");
        return -1;
    }

    /* 发送msg,向0x57的slave写0x09,作用与gx_i2c_write一致 */
    msgs.len   = len;
    msgs.addr  = slv_addr;
    msgs.buf   = &data;
    msgs.flags = 0;
    status = gx_i2c_transfer(i2c_dev, &msgs, 1);

    /* 关闭i2c0 */
    gx_i2c_close(i2c_dev);

    return 0;
}
COMMAND_EXPORT_ALIAS(i2c_master_example2, i2c_master_example2, "i2c_master_example2");

方式四 i2C Master读数据*

int i2c_master_example3(void)
{
    padmux_set(I2C0_SCL_PIN, 10);
    padmux_set(I2C0_SDA_PIN, 11);

    /* 初始化i2c0 */
    gx_i2c_init(0);

    /* 设置i2c传输速度 */
    gx_i2c_set_speed(0, 1000);

    /* 初始化dma */
    gx_dma_init();

    void *i2c_dev = NULL;
    GX_I2C_MSG msgs;
    unsigned char bus = 0, slv_addr = 0x57, address_width = 1;
    unsigned char reg = 0x09, data = 0x40;
    unsigned short len = 1;

    /* 打开i2c0 */
    i2c_dev = gx_i2c_open(bus);
    if (!i2c_dev) {
        i2c_debug("open i2c dev failed.\n");
        return -1;
    }

    /* 发送msg,读取设备地址为0x57的slave的0x09寄存器,作用与gx_i2c_rx一致 */
    msgs[0].addr  = slv_addr;
    msgs[0].buf   = ®
    msgs[0].len   = address_width;
    msgs[0].flags = 0;

    msgs[1].addr  = slv_addr;
    msgs[1].buf   = &data;
    msgs[1].len   = len;
    msgs[1].flags = I2C_M_RD;

    ret = gx_i2c_transfer(dev, msgs, 2);

    /* 关闭i2c0 */
    gx_i2c_close(i2c_dev);

    return 0;
}
COMMAND_EXPORT_ALIAS(i2c_master_example3, i2c_master_example3, "i2c_master_example3");

3.2 i2C Master 中断读写*

其他中断读写API请参考头文件apus/platform/drv-apus/include/gx_i2c.h, 使用方式与3.1方式相似

static void async_callback(void *priv)
{
    printf("%s!!\n", __func__);
}

static int i2c_master_async_example(int argc, char * const argv[])
{
    unsigned char rx_buffer[256] __attribute__((aligned(DCACHE_LINE_SIZE)));

    padmux_set(I2C0_SCL_PIN, 10);
    padmux_set(I2C0_SDA_PIN, 11);

    /* 初始化i2c0 */
    gx_i2c_init(0);

    /* 设置i2c传输速度 */
    gx_i2c_set_speed(0, 1000);

    /* 初始化dma */
    gx_dma_init();

    unsigned char bus = 0, slv_addr = 0x57, address_width = 1;
    unsigned int reg = 0x09;
    unsigned char data = 0x03;
    unsigned short len = 1;
    int ret = -1;

    /* 使用i2c0向设备地址为0x57的slave的0x09寄存器写入0x03 */
    ret = gx_i2c_async_tx(bus, slv_addr, reg, address_width, &data, len, async_callback, NULL);
    if (ret != 0) {
        printf("error\n");
        return ret;
    }

    /* 使用i2c0读取设备地址为0x57的slave的0x03寄存器 */
    ret = gx_i2c_async_rx(bus, slv_addr, reg, address_width, rx_buffer, 1, async_callback, NULL);
    if (ret != 0) {
        printf("gx_i2c_async_rx error\n");
        return ret;
    }
    printf("data = %d\t\n", data);

    return 0;
}

COMMAND_EXPORT_ALIAS(i2c_master_async_example, i2c_master_async_example, "i2c_master_async_example");

3.3 i2C MasterDMA读写*

使用接口同 i2C Master 中断读写。使能i2C DMA需要打开 apus/platform/drv-apus/src/i2c.c 控制

#define CONFIG_I2C_DMA

第四章 I2C Slave示例代码*

4.1 i2c slave 中断读写*

  • 具体接口细节请参看头文件apus/platform/drv-apus/include/gx_i2c.h
void do_someting(void)
{
    printf("stop\n");
}
static int gx_i2c_slave_async_callback(GX_I2C_SLAVE_EVENT event, unsigned char *val, void *private)
{
    unsigned char data;

    switch (event) {
        /* 检测到stop信号 */
        case I2C_SLAVE_STOP:
            do_someting();
            break;
        /* 检测到读请求 */
        case I2C_SLAVE_REQUESTED_DATA:
            /* 返回给master 0x33 */
            *val = 0x33;
            break;
        /* 检测到写请求 */
        case I2C_SLAVE_RECEIVE_DATA:
            /* 获取master发送的数据 */
            data = *val;
            break;
        default:
            break;
    }
}

int i2c_slave_example(void)
{
    unsigned char bus = 1, slv_addr = 0x57;

    padmux_set(I2C1_SCL_PIN, 12);
    padmux_set(I2C1_SDA_PIN, 13);

    /* 初始化i2c0为设备地址0x57的slave */
    gx_i2c_slave_open(bus, slv_addr, gx_i2c_slave_async_callback, NULL);

    return 0;
}

COMMAND_EXPORT_ALIAS(i2c_slave_example, i2c_slave_example, "i2c_slave_example");

4.2 i2c slave DMA 响应读写*

  • 使用接口同**i2c slave 中断**读写, 使能i2C DMA需要在apus/platform/drv-apus/src/i2c.c 定义相关控制
#define CONFIG_I2C_SLAVE_DMA_RX_TEST
#define CONFIG_I2C_SLAVE_DMA_TX_TEST

4.3 i2c slave DMA 特殊响应读写*

在 i2c master 未发起读的时候,i2c slave 先发起 dma 传输,等待 master 来读取,以此降低 DMA 初始化等过程的时延。初始化 i2c slave DMA 后调用 gx_i2c_slave_enable_fast_dma_tx 函数来使能该功能。

int gx_i2c_slave_enable_fast_dma_tx(unsigned char bus_id)
{
    if (bus_id > 2)
        return -1;
    *(volatile unsigned int *)0xb500001C |= 1 << (bus_id * 4);

    return 0;
}
  • 未使用该功能

fast_dma1

  • 使用该功能

fast_dma2