You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下I2C read()读取ADS1110数据丢失1位故障问题

ADS1110 I2C读取D14位恒为0故障排查

问题描述

尝试通过I2C读取ADS1110 ADC数据,ADS1110 7位I2C地址为1001 000:

  • 写操作仅支持修改配置寄存器,传输格式为「从机地址 + 配置值」
  • 读操作返回3字节数据,顺序为:转换结果高字节、转换结果低字节、配置寄存器值
  • ADS1110默认配置为0x8C,连续转换模式下状态位最高位为0时表示转换数据为最新有效值

使用Linux标准read()/write()实现I2C读取逻辑,代码如下:

#define NUMS 10
char readbuf[NUMS];

int main(int argc, char** argv)
{
    // int file = i2c_init("/dev/i2c-0", 0x48);
    int file = open("/dev/i2c-0", O_RDWR);
    int addr = 0b01001000;

    if (file < 0) {
        printf("openfile error!\n");
        exit(1);
    }

    if (ioctl(file, I2C_SLAVE, addr) < 0) {
        printf("ioctl error!\n");
        exit(1);
    }

    // 配置为增益1倍
    readbuf[0] = 0x0C;

    if (write(file, readbuf, 1) != 1) {
        printf("write error!\n");
        exit(1);
    }

    if (read(file, readbuf, 3) != 3) {
        printf("read error!\n");
        exit(1);
    }

    printf("%x %x %x\n", readbuf[0] & 0xff, readbuf[1] & 0xff, readbuf[2] & 0xff);

    close(file);
    exit(EXIT_SUCCESS);
}

代码中配置ADS1110为0x0C:连续转换模式、1倍增益、15SPS采样率(16位精度),对应满量程输入2.048V(编码值0x7FFF)。测试发现:

  • 输入电压低于1.024V时读取结果完全正确
  • 输入电压高于1.024V时,转换结果的D14位始终读为0,例如输入1.5V时,预期输出高字节为0x5D(二进制0101开头),实际读取到0x1D(二进制0001开头)
  • 除D14位异常外,低字节、配置寄存器的读取值均完全正确
  • 示波器采集的通信波形如下:
    I2C通信示波器波形

根因分析

故障是I2C总线SDA线上拉能力不足,上升沿过慢导致的位采样错误,完全匹配所有现象:

  1. I2C读第一个数据字节(转换结果高字节)前,总线连续两个周期处于低电平:从机应答地址字节时拉低SDA、发D15位(正电压下该位为0)时再次拉低SDA,SDA线电容完全放电。
  2. 输入电压低于1.024V时,转换结果D14位为0,从机继续拉低SDA发0,不存在电平跳变,采样完全正确。
  3. 输入电压高于1.024V时,D14位为1,从机释放SDA,需要上拉电阻将SDA电平拉高。如果上拉电阻阻值过大、总线电容过高(比如飞线太长、挂接器件过多),SDA上升时间超过I2C时钟周期的采样窗口,主机就会把该位误判为0。
  4. 后续位采样正常:D14位之后SDA已经有足够时间充电到高电平阈值,即使后续再有0→1的跳变,SDA被拉低的时间仅为1个时钟周期,放电不充分,上升速度更快,不会出现采样错误。
  5. 配置寄存器读取正常:配置为0x0C时,其bit6位本身为0,从机主动拉低SDA,不需要电平上升,因此不会出错。

解决方案

按优先级依次排查修复:

  • 更换SDA/SCL线上拉电阻:标准模式(100kHz)下推荐使用4.7kΩ上拉电阻,快速模式(400kHz)可更换为2.2kΩ,不要使用10kΩ以上的上拉电阻。
  • 降低I2C时钟频率:如果当前使用400kHz快速模式,先降到100kHz标准模式测试,给SDA电平上升留足时间。
  • 优化总线布线:减少过长飞线、去除SDA线上多余的寄生电容,减少总线挂接的器件数量。
  • 代码层面优化:将readbuf类型从char改为unsigned char,避免有符号字符型的隐式转换问题;连续转换模式下不需要每次读取前都重写配置寄存器,初始化时写一次配置即可循环读取。

内容的提问来源于stack exchange,提问作者Chroluma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:12:22