RISCV_I2C使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 04/09/2025 |
1. 概述¶
1.1 I2C¶
I2C,全称Inter-Integrated Circuit,集成电路总线,使用多主从架构,是一种串行、同步、半双工的通信总线,包含串行时钟线(SCL)与串行数据线(SDA),都是双向IO线。通信过程中,时钟信号由主设备全程提供;数据信号取决于主设备是做读操作还是写操作,当进行写操作时,数据信号由主设备提供,当进行读操作时,数据信号由从设备提供。
1.2 MIIC¶
MIIC,即Master IIC device,是SigmaStar提供的专门作为I2C通信主设备的IP,可实现与各种外接的I2C slave device通讯,满足绝大部分I2C通讯协议设备的需求。
设备bank和硬件组别的关系如下表所示:
MIIC Group | bank addr |
---|---|
HW MIIC group0 | 1114H |
HW MIIC group1 | 1115H |
HW MIIC group2 | 1116H |
HW MIIC group3 | 1117H |
HW MIIC group4 | 1118H |
HW MIIC group5 | 3EH |
2. 关键字¶
sysdesc:
RTOS用于描述外设硬件属性的文件,外设节点中包含的属性值可用于外设的配置,类似Linux的设备树文件
padmux:
引脚复用,用于将模块功能引脚连接到具体的外部引脚上面,打通信号连接。
open-drain:
即开漏输出,不输出电压,控制输出低电平时的引脚接地,控制输出高电平时为高阻态,有外部电路负责高电平。
push-pull:
即推挽输出,既可以输出低电平,也可以输出高电平。一般由两个参数相同的三极管或MOSFET组成, 有较强的驱动能力。
3. 功能描述¶
3.1 通信协议¶
一个完整的I2C通信,应包含:起始信号、从设备地址与读写位、应答信号、任意字节长度的数据以及停止信号。
起始信号: 一次完整I2C通信的第一个信号,由主设备提供。示意本次通讯开始。电平信号为 - 当SCL为高电平,SDA从高电平拉为低电平。
从设备地址: 通信从设备的“身份证”,与读写位一起共享address frame。占据高7bit或高10bit。通过主设备发出来的地址来确认自己是否被选中。设备地址可以相同,但如果同时接在同一总线上,很容易导致通讯失败或数据错误。
读写位: 用于指示当次传输主设备要进行写操作还是读操作,b0为写操作,b1为读操作。与从设备地址一起共享address frame。占据最低位bit0。
例: 如果从设备地址为7bit的0x50,进行读操作,那么:
address frame = (0x50 << 1) | 0x01 = 0xA1
应答信号: 数据接收方反馈给发送方的信号,低电平表示接收成功,高电平表示接收失败。接收方可以是主设备也可以是从设备。当主设备在读取数据时,发送完从设备地址之后,就会变成数据的接收方。但是clock信号始终都是由主设备提供的。
数据: 传输的数据,写操作或者读操作。以字节为单位。另外,一般在I2C通讯写操作时,从设备地址之后会跟随所要读写的从设备寄存器地址,可能是8bit长度,可能是16bit长度,他们也属于传输过程中的数据。
停止信号: 一次完整通讯的最终信号,由主设备提供。示意本次通讯到此结束。电平信号为 - 当SCL为高电平,SDA从低电平拉为高电平。
如下为I2C通信协议格式:

3.2 功能配置¶
功能 |
说明 |
备注 |
---|---|---|
FIFO transfer | 每个传输信号都需要由CPU来参与,通过写入不同的MIIC寄存器发送不同的信号 | 采用polling方式,CPU loading会比较大;单次最大传输数据量为8192字节;在每次传输量都比较小的时候建议使用此模式 |
DMA transfer | 整个通信过程都由MIIC自行动作,仅需要提前填入传输内容,再触发即可;HW MIIC会根据已经填入的时序设定来进行通讯 | 采用中断方式,CPU loading会比FIFO mode小;单次最大传输数据量为4086字节;每次传输量都比较大时建议使用此模式;当传输期间出现错误时HW会立即停止这次通讯,触发中断 |
timing 调整 | 开放了几个I2C通讯时序可供调整,当具体某部分时序不满足从设备要求时,在dtsi节点中调整 | 可调时序: t-SU-STA, t-HD-STA, t-SU-STO, t-HD-STO, t-SU-DAT, t-HD-DAT |
rate | 支持通讯速率区间可调,不分档位,可根据实际需要在dtsi节点或sysfs节点中调整 | 支持50kHz - 1500KHz,更大速率需求不做保证 |
输出方式调整 | 支持open-drain与push-pull两种输出方式,可在dtsi节点中调整 | MIIC不支持任意调整波形的上升/下降沿时间,仅可以通过调整输出方式来改变,且时间无法确认push-pull上升沿时间会较快 |
padmux | 可配置不同的padmux使总线引到不同的引脚上面 | |
1toN | 部分padmux会同时连接几组PAD引脚,通讯时信号会同时提供到这几组PAD上面 | 该方式有如下限制: 所有的从设备必须类型一样且地址一样,而且MIIC只能写数据不能读数据一般用于同时接入几个相同从设备,需要同步设定的情况 |
外部上拉 | I2C总线上必须要接外部上拉 |
如下为I2C时序:

MIIC支持配置的时序如下:
时序 |
说明 |
---|---|
t-SU-STA | 起始信号建立时间 |
t-HD-STA | 起始信号保持时间 |
t-SU-STO | 结束信号建立时间 |
t-HD-STO | 结束信号保持时间 |
t-LOW | 时钟低电平时间 |
t-HIGH | 时钟高电平时间 |
t-SU-DAT | 数据信号建立时间 |
t-HD-DAT | 数据信号保持时间 |
I2C将不同的通信速度按区间分成多种速度模式,如下:
速度模式 |
说明 |
---|---|
Standard-mode (Sm) | 最大可达 100k bit/s |
Fast-mode (Fm) | 最大可达 400k bit/s |
Fast-mode Plus (Fm+) | 最大可达 1M bit/s |
High-speed mode (Hs-mode) | 最大可达 3.4M bit/s |
Ultra Fast-mode (UFm) | 最大可达 5M bit/s |
Sm/Fm/Fm+对时序要求如下图:

4. 硬件连接介绍¶
I2C为多主从架构,顾名思义一路总线上面可以有多个主设备与多个从设备,他们之间通过从设备地址与应答信号来建立彼此联系。
SigmaStar的I2C,每一路总线上仅提供了一个MIIC(master iic)主设备,从设备个数无要求,根据使用需求自行设定。
并且,遵从I2C标准协议,在总线的SDA与SCL上面必须要接入外部上拉,这是因为I2C通讯需要输出高电平的能力,而当器件输出为开漏输出时,是无法输出高电平的,这时就需要外部上拉的帮助,借此实现“线与”功能,决定最终电平。
如下为I2C总线示例图:

5. RTOS用法介绍¶
5.1 DRIVER PATH¶
sc/driver/sysdriver/i2c/os/iic_os.h sc/driver/sysdriver/i2c/drv/pub/drv_iic.h sc/driver/sysdriver/i2c/drv/src/drv_iic.c sc/driver/sysdriver/i2c/drv/src/drv_iic_test.c sc/driver/sysdriver/i2c/hal/pcupid/src/hal_iic.c sc/driver/sysdriver/i2c/hal/pcupid/inc/hal_iic.h sc/driver/sysdriver/i2c/hal/pcupid/inc/hal_iic_reg.h sc/driver/sysdriver/i2c/hal/pcupid/inc/hal_iic_cfg.h
5.2 CONFIG配置¶
config文件位于mak/options_chipname_riscv_isw.mak
,使能CONFIG_I2C_SUPPORT
# Feature_Name = [DRV] I2C driver support # Description = I2C driver support # Option_Selection = TRUE, FALSE # CONFIG_I2C_SUPPORT = TRUE
5.3 SYSDESC配置¶
chipname-default.sys文件位于sc/driver/sysdriver/sysdesc/hal/chipname/pub
<i2c0> [reg_u32_u16] 0x2222800 0x200; [interrupts_u8] INT_IRQ_MIIC; [camclk_u16] CAMCLK_miic0; [dma_u8] 1; [output_mode_u8] 2; [speed_u32] 200000; [t_su_sta_u32] 0; [t_hd_sta_u32] 0; [t_su_sto_u32] 0; [t_hd_sto_u32] 0; [t_su_dat_u32] 0; [t_hd_dat_u32] 0; [status_u8] 1;
Master IIC驱动中支持配置的属性如下表:
属性 | 描述 | 设定值 | 备注 |
---|---|---|---|
reg_u32_u16 | 指定bank的地址 | 不需要修改 | |
interrupts_u8 | 指定硬件中断号 | 不需要更改 | |
dma_u8 | 选择是否使能DMA模式 | 1-开启;0-关闭 | 可根据需要修改 |
output_mode_u8 | 选择输出模式 | 1:开漏输出; 2:开漏推1T输出; 3:开漏推1T强上拉;4:推挽输出 | 可根据需要修改,1->4上升沿时间依次缩短 |
speed_u32 | 设定通讯频率,单位HZ | 范围50K~1500K HZ | 可根据需要修改 |
t_su_sta_u32 | 设定起始信号保持时间 | ns value | 可根据需要修改 |
t_hd_sta_u32 | 设定起始信号建立时间 | ns value | 可根据需要修改 |
t_su_sto_u32 | 设定结束信号建立时间 | ns value | 可根据需要修改 |
t_hd_sto_u32 | 设定结束信号保持时间 | ns value | 可根据需要修改 |
t_su_dat_u32 | 设定结束信号建立时间 | ns value | 可根据需要修改 |
t_hd_dat_u32 | 设定起始信号建立时间 | ns value | 可根据需要修改 |
camclk_u16 | 指定时钟源 | 不需要修改 | |
status_u8 | 选择是否使能驱动 | 1-enable;0-disable | 可根据需要修改 |
详细说明:
下图5-1为miic对详细时序的分解,图5-2为可调整的几个时序的位置。
图5-1 miic通信时序
图5-2 miic起始信号与结束信号时序调整
sysdesc中开放的几个时序调整,对应波形位置为:
时序 |
波形位置 |
---|---|
t-su-sta | reg_start_setup_cnt |
t-hd-sta | reg_start_cnt |
t-su-sto | reg_stop_cnt |
t-hd-sto | reg_stop_hold_cnt |
t-su-dat | reg_lcnt - reg_sda_cnt |
t-hd-dat | reg_sda_cnt |
如果节点中属性值为0,driver会按照既定计算得出ns值,如果有设定则按照设定值,设定的理论最大值为U32_MAX,单位为ns。
5.4 PADMUX配置¶
CONFIG配置:CONFIG_PADMUX_SUPPORT=TRUE
如果chipname_xxx.sys
文件配置了属性<padmux>
,那么PADMUX的设定直接在此配置:
<padmux> [schematic_u32_u32_u32] PAD_GPIOE_01 PINMUX_FOR_I2C0_MODE_1 MDRV_PUSE_I2C0_SDA, PAD_GPIOE_04 PINMUX_FOR_I2C1_MODE_1 MDRV_PUSE_I2C1_SCL, PAD_GPIOE_05 PINMUX_FOR_I2C1_MODE_1 MDRV_PUSE_I2C1_SDA, PAD_GPIOE_21 PINMUX_FOR_I2C2_MODE_1 MDRV_PUSE_I2C2_SCL, PAD_GPIOE_22 PINMUX_FOR_I2C2_MODE_1 MDRV_PUSE_I2C2_SDA, PAD_GPIOE_23 PINMUX_FOR_I2C3_MODE_1 MDRV_PUSE_I2C3_SCL, PAD_GPIOE_24 PINMUX_FOR_I2C3_MODE_1 MDRV_PUSE_I2C3_SDA, PAD_GPIOD_01 PINMUX_FOR_I2C4_MODE_1 MDRV_PUSE_I2C4_SCL, PAD_GPIOD_02 PINMUX_FOR_I2C4_MODE_1 MDRV_PUSE_I2C4_SDA, PAD_PM_I2C_SDA PINMUX_FOR_PM_I2CM0_MODE_1 MDRV_PUSE_I2C5_SCL, PAD_PM_I2C_SDA PINMUX_FOR_PM_I2CM0_MODE_1 MDRV_PUSE_I2C5_SDA, [status_u8] 1;
否则通过使能PADMUX驱动,在chipname-xxx-padmux.c
文件配置引脚复用功能,该文件位于sc/driver/sysdriver/padmux/hal/chipname/src
,只需要在对应的schematic
属性添加如下内容中设定:
pad_info_t schematic[] = { {PAD_GPIOE_01 PINMUX_FOR_I2C0_MODE_1 MDRV_PUSE_I2C0_SDA}, {PAD_GPIOE_04 PINMUX_FOR_I2C1_MODE_1 MDRV_PUSE_I2C1_SCL}, {PAD_GPIOE_05 PINMUX_FOR_I2C1_MODE_1 MDRV_PUSE_I2C1_SDA}, {PAD_GPIOE_21 PINMUX_FOR_I2C2_MODE_1 MDRV_PUSE_I2C2_SCL}, {PAD_GPIOE_22 PINMUX_FOR_I2C2_MODE_1 MDRV_PUSE_I2C2_SDA}, {PAD_GPIOE_23 PINMUX_FOR_I2C3_MODE_1 MDRV_PUSE_I2C3_SCL}, {PAD_GPIOE_24 PINMUX_FOR_I2C3_MODE_1 MDRV_PUSE_I2C3_SDA}, {PAD_GPIOD_01 PINMUX_FOR_I2C4_MODE_1 MDRV_PUSE_I2C4_SCL}, {PAD_GPIOD_02 PINMUX_FOR_I2C4_MODE_1 MDRV_PUSE_I2C4_SDA}, {PAD_PM_I2C_SDA PINMUX_FOR_PM_I2CM0_MODE_1 MDRV_PUSE_I2C5_SCL}, {PAD_PM_I2C_SDA PINMUX_FOR_PM_I2CM0_MODE_1 MDRV_PUSE_I2C5_SDA}, };
第一列为引脚索引号,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/gpio.h
中查询;
第二列为模式定义,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/padmux.h
中查询;
第三列为引脚及搭配模式的索引名称,可以在sc/drivers/sysdriver/padmux/drv/pub/drv_puse.h
中查询;
5.5 Sample code¶
头文件位于 sc/driver/sysdriver/i2c/drv/pub/drv_iic.h
。
static int i2c_ut_test(CLI_t * cli, char * p) { u8 i; u8 argc; u32 port; u32 slave; char *cmd; tI2cMsg msg; u32 addr; u32 value; u8 data[32]; u8 e_data[32]; int ret = 0; u8 r_flag = 0; u32 speed = 0; argc = CliTokenCount(cli); if (argc < 2) return eCLI_PARSE_INPUT_ERROR; cmd = CliTokenPop(cli); if (strcmp(cmd, "r") == 0) { argc = CliTokenCount(cli); if (argc != 4) return eCLI_PARSE_INPUT_ERROR; r_flag = 1; } else if (strcmp(cmd, "w") == 0) { argc = CliTokenCount(cli); if (argc < 5 || argc > 6) return eCLI_PARSE_INPUT_ERROR; } else { return eCLI_PARSE_INPUT_ERROR; } if (CliTokenPopNum(cli, &port, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } if (CliTokenPopNum(cli, &slave, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } cmd = CliTokenPop(cli); if (strcmp(cmd, "A16D8") == 0) { msg.addr = (u16)slave; if (r_flag) { if (CliTokenPopNum(cli, &addr, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } //write msg.flags = 0; data[0] = (u8)((addr >> 8) & 0xff); data[1] = (u8)(addr & 0xff); msg.buf = data; msg.len = 2; drv_i2c_master_xfer(port, &msg, 1); //read msg.flags = CAM_I2C_RD; msg.buf = data; msg.len = 1; drv_i2c_master_xfer(port, &msg, 1); cliPrintf(" %04x : %02x\r\n", (u16)addr, (u8)data[0]); } else { if (CliTokenPopNum(cli, &addr, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } if (CliTokenPopNum(cli, &value, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } CliTokenPopNum(cli, &speed, 0); data[0] = (u8)((addr >> 8) & 0xff); data[1] = (u8)(addr & 0xff); data[2] = (u8)(value & 0xff); //write msg.flags = 0; msg.buf = data; msg.len = 3; //set i2c speed if (speed) drv_i2c_set_speed(port, speed); //transfer drv_i2c_master_xfer(port, &msg, 1); } } return eCLI_PARSE_OK; }
6. API 参考¶
该功能模块提供以下接口:
API名 | 功能 |
---|---|
drv_i2c_master_xfer | 进行iic传输(同步) |
drv_i2c_set_speed | 设置iic传输速度 |
头文件位于sc/driver/sysdriver/i2c/drv/pub/drv_iic.h
typedef struct i2c_msg { u16 addr; /*slave address*/ u16 flags; #define CAM_I2C_RD 0x0001 #define CAM_I2C_STOP_BEFORE_RESTART 0x0002 #define CAM_I2C_TEN 0x0010 #define CAM_I2C_DMA_SAFE 0x0200 #define CAM_I2C_RECV_LEN 0x0400 #define CAM_I2C_NO_RD_ACK 0x0800 #define CAM_I2C_IGNORE_NAK 0x1000 #define CAM_I2C_REV_DIR_ADDR 0x2000 #define CAM_I2C_NOSTART 0x4000 #define CAM_I2C_STOP 0x8000 u16 len; /*msg length*/ u8 *buf; /*pointer to msg data*/ }tI2cMsg;
6.1. drv_i2c_master_xfer¶
-
功能
与 para_group 对应iic channel进行一次同步的iic传输,使用 para_num 个 pMsg 存储传输信息。
-
声明
s32 drv_i2c_master_xfer(u8 para_group, struct i2c_msg *para_msg, s32 para_num);
-
形参
参数名称 描述 para_group 设备组号 para_msg 通信内容 para_num 信息长度 -
返回值
返回值 描述 0 失败 正数 成功
6.2 drv_i2c_set_speed¶
-
功能
设置 para_group 对应的bus速度为 speed
-
声明
s32 drv_i2c_set_speed(u8 para_group, u32 speed);
-
形参
参数名称 描述 para_group i2c bus speed 通讯频率,单位HZ -
返回值
返回值 描述 0 成功 other 失败
7. 调试¶
当出现通讯异常时,可以参考如下方面进行问题调试,提供了几种较为常见的排查方向,另调试过程建议抓取波形方便分析。
排查方向 | 常见问题 |
备注 |
---|---|---|
外部上拉 | 1. 提示通讯超时错误信息;2. 抓取波形无变化,SCL始终为低电平; 3. 波形读写的数据都为0x00 | |
padmux | 1. 提示无ACK信号;2. 波形没有变化,电平一直维持 | 参考PADMUX章节,或padmux模块说明 |
通信速率 | 通讯失败,无ACK信号 | 可查找从设备手册,确认正常工作的通信速率范围 |
时钟源 | 1. 提示通讯超时错误信息;2. 无波形 | 参考CLKGEN模块说明 |
时序 | 通讯无ACK信号 | 若从设备会对各部分详细时序有特定要求,可从设备手册查找确认 |
从设备工作状态 | 通讯失败,无ACK | 当从设备没有处在正常的工作状态的时候,无法对主设备发起的信号进行响应 |