跳转至

I2C

I2C 驱动 | sample: i2c

学习目标

  • 理解 I2C 两线制总线(SCL + SDA)和主从模型
  • 掌握 I2C 主机的初始化:引脚复用 → 配置地址和速率 → uapi_i2c_master_write/read
  • 能够在 WS63 上作为 I2C 主机读写从设备(EEPROM、传感器等)

基本概念

I2C 总线简介

I2C(Inter-Integrated Circuit)是飞利浦发明的两线制串行总线——SCL(时钟)+ SDA(数据),支持一主多从。

flowchart LR
    M[WS63 主机] -->|SCL| S1[从设备1]
    M -->|SDA| S1
    M -->|SCL| S2[从设备2]
    M -->|SDA| S2

从机地址

每个 I2C 设备有唯一的 7-bit 地址——主机通过地址选中目标从机,然后发起读写。常见地址:EEPROM 0x50~0x57、温度传感器 0x48。

传输速率

模式 速率 适用场景
标准模式 100kHz 低速传感器、EEPROM
快速模式 400kHz 多数传感器和存储器
高速模式 3.4MHz 摄像头等高速设备

I2C 读写时序

主机写:START → 从机地址+W → 寄存器地址 → 数据 → STOP
主机读:START → 从机地址+W → 寄存器地址 → RESTART → 从机地址+R → 读数据 → STOP

涉及 API

API 用途 头文件
uapi_pin_set_mode(pin, mode) 设置 SCL/SDA 引脚为 I2C 功能 pinctrl.h
uapi_i2c_init(port, baudrate, hscode) 初始化 I2C 端口和速率 i2c.h
uapi_i2c_master_write(port, addr, buf, len) 主机写数据到从机 i2c.h
uapi_i2c_master_read(port, addr, buf, len) 主机从从机读数据 i2c.h
uapi_i2c_deinit(port) 去初始化 I2C i2c.h

案例说明

做什么

初始化 I2C 主机(400kHz),向从设备写入数据并回读验证。演示标准的 I2C 主机读写流程。

规格与功能

规格项 说明
I2C 端口 I2C0(Master)
速率 400kHz(Fast Mode)
主机地址 0x0
从机地址 根据实际设备配置
操作 写数据 → 读回验证

程序运行流程:引脚复用 → i2c_initmaster_write 写数据 → master_read 回读 → 比较验证。

案例流程

sequenceDiagram
    participant M as WS63 Master
    participant S as I2C Slave

    M->>M: uapi_i2c_init 400kHz
    M->>S: START + 从机地址+W
    M->>S: 寄存器地址 + 数据
    M->>S: STOP

    M->>S: START + 从机地址+W
    M->>S: 寄存器地址
    M->>S: RESTART + 从机地址+R
    S-->>M: 回读数据
    M->>S: STOP

案例操作指导

第一步:编译

fbb build ws63-liteos-app

第二步:烧录和接线

SCL、SDA 接从设备对应引脚,加上拉电阻(通常 4.7kΩ 到 VCC),共 GND。

第三步:验证

串口打印写入和回读的数据一致。

关键配置

参数 说明
baudrate 400000 400kHz——大多数 I2C 设备支持
hscode 0x0 主机地址
从机地址 设备数据手册 7-bit 地址,左移 1 位
上拉电阻 ~4.7kΩ I2C 总线必须有上拉——OD 输出

代码详解

完整代码参考 src/application/samples/peripheral/i2c/i2c_master_demo.c

#include "pinctrl.h"
#include "i2c.h"
#include "soc_osal.h"
#include "app_init.h"

#define I2C_MASTER_ADDR       0x0
#define I2C_SET_BAUDRATE      400000
#define I2C_TASK_PRIO         24

static void app_i2c_init_pin(void)
{
    /* SCL 和 SDA 都要设为 I2C 功能 */
    uapi_pin_set_mode(CONFIG_I2C_SCL_MASTER_PIN, CONFIG_I2C_MASTER_PIN_MODE);
    uapi_pin_set_mode(CONFIG_I2C_SDA_MASTER_PIN, CONFIG_I2C_MASTER_PIN_MODE);
}

static void i2c_master_task(const char *arg)
{
    (void)arg;
    i2c_data_t data = { 0 };
    uint8_t slave_addr = CONFIG_I2C_SLAVE_ADDR;

    app_i2c_init_pin();

    /* 初始化 I2C——400kHz,主机地址 0 */
    uapi_i2c_init(CONFIG_I2C_PORT, I2C_SET_BAUDRATE, I2C_MASTER_ADDR);

    /* 准备要写的数据 */
    data.send_buf[0] = 0x00;   // 寄存器地址
    data.send_buf[1] = 0x5A;   // 数据
    data.send_len = 2;

    /* 主机写 */
    uapi_i2c_master_write(CONFIG_I2C_PORT, slave_addr,
                          data.send_buf, data.send_len);

    osal_msleep(10);  // 等从设备处理

    /* 主机读——先写寄存器地址再读 */
    data.send_buf[0] = 0x00;   // 要读的寄存器地址
    data.send_len = 1;
    data.recv_len = 1;

    uapi_i2c_master_read(CONFIG_I2C_PORT, slave_addr,
                         data.send_buf, data.send_len,
                         data.recv_buf, data.recv_len);

    osal_printk("read back: 0x%02X\r\n", data.recv_buf[0]);
}
app_run(i2c_entry);

I2C 是开漏(OD)输出——SCL 和 SDA 必须接上拉电阻到 VCC(通常 4.7kΩ),否则总线无法输出高电平。部分开发板内置上拉,没有的话需要外接。