This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] AM62A7:I2C 总线上的空消息导致 I2C 控制器锁定

Guru**** 2034770 points
Other Parts Discussed in Thread: AM62A7
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1450134/am62a7-i2c-controller-lock-up-due-to-the-void-message-on-i2c-bus

器件型号:AM62A7

工具与软件:

您好!  

SDK:09.01.00

我们使用的是具有09.01.00 SDK 的 AM62A7处理器。 我们在 I2C-2总线上集成了 AR0235摄像头传感器。 有时(100次中的1或2次)我们会看到 I2C 超时错误、如下所示。  

Fullscreen
1
2
[ 2.975722] omap_i2c 20020000.i2c: controller timed out
[ 2.975747] ar0235 2-0036: failed to read chip id 1850
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

我们已捕获 Saleae 日志来确定该问题。 我们知道 I2C 总线上存在 void 消息。 我们在 AM62A7的 TRM 中找到了 void 消息说明、其内容如下所示。

当我们观察到 I2C-2总线(图像传感器连接在此处)的 Saleae 日志时、我们发现了类似的波形为 void 消息情况。

我随附了 Saleae 日志以供参考。  当 i2c 在 396th 秒的最后一个波形上出现超时错误时、我发现了 void 消息条件。

e2e.ti.com/.../4188.logs.zip

请建议我们如何避免 I2C 线路上出现 void 消息?

此致、

Jay

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jay:

    我将在软件方面与您合作。

    对于未来的读者、这里是讨论的硬件方面。 我要求的最新测试是通过测试来验证 SDA 是否实际被 AM62Ax 而不是 I2C 总线上的任何其他东西拉低: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1446977/am62a7-i2c-bus-timeout-issue/5561441#5561441

    从软件方面可能会发生什么?

    我对你没有立即的答案。 因此、只要我经过我的思考过程、这个响应就会有点长。 我将在最后提供操作的摘要

    我们将讨论驱动器
    drivers/i2c/buss/i2c-omap.c

    我假设您要将中断与 I2C 驱动程序一起使用、对吧? 如果是、根据 OMAP_i2c_xfer_irq、我预计轮询= false:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static int
    omap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
    {
    return omap_i2c_xfer_common(adap, msgs, num, false);
    }
    static int
    omap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
    {
    return omap_i2c_xfer_common(adap, msgs, num, true);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    因此这意味着"控制器超时"错误来自驱动程序中的此处:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /*
    * Low level master read/write transaction.
    */
    static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
    struct i2c_msg *msg, int stop, bool polling)
    {
    ...
    /*
    * REVISIT: We should abort the transfer on signals, but the bus goes
    * into arbitration and we're currently unable to recover from it.
    */
    if (!polling) {
    timeout = wait_for_completion_timeout(&omap->cmd_complete,
    OMAP_I2C_TIMEOUT);
    }
    ...
    if (timeout == 0) {
    dev_err(omap->dev, "controller timed out\n");
    omap_i2c_reset(omap);
    __omap_i2c_init(omap);
    return -ETIMEDOUT;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    TIMEOUT =0表示 IRQ 未从 OMAP_i2c_xfer_data 返回并执行 OMAP_i2c_complete_cmd 函数调用:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static irqreturn_t
    omap_i2c_isr_thread(int this_irq, void *dev_id)
    {
    int ret;
    struct omap_i2c_dev *omap = dev_id;
    ret = omap_i2c_xfer_data(omap);
    if (ret != -EAGAIN)
    omap_i2c_complete_cmd(omap, ret);
    return IRQ_HANDLED;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    什么地方发生了什么?

    让我们参考 TRM I2C 低级编程模型:

    配置目标地址和数据控制寄存器

    在控制器模式下、通过对 I2C_SA[9-0] SA 位字段和进行编程来配置目标地址寄存器
    通过对 I2C_CNT[15-0]进行编程来使传输关联的数据字节数(I2C 数据有效载荷)
    DCOUNT 位域。

    发生在 OMAP_i2c_xfer_msg 中:

    Fullscreen
    1
    2
    3
    4
    omap_i2c_write_reg(omap, OMAP_I2C_SA_REG, msg->addr);
    /* make sure writes to omap->buf_len are ordered */
    barrier();
    omap_i2c_write_reg(omap, OMAP_I2C_CNT_REG, omap->buf_len);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    我假设我们要启动一个转移。

    发起传输

    轮询 I2C_IRQSTATUS_RAW[12] BB 位。 如果它被清零(总线不忙)、配置 I2C_CON[0] STT
    和 I2C_CON[1] STP 位。 要启动传输、I2C_CON[0] STT 位必须设置为1、而不是
    强制将 I2C_CON[1] STP 位设置为1。

    OMAP_i2c_xfer_msg 中也会发生这种情况:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
    ...
    other configuration here
    ...
    /*
    * NOTE: STAT_BB bit could became 1 here if another master occupy
    * the bus. IP successfully complete transfer when the bus will be
    * free again (BB reset to 0).
    */
    omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    在执行此写入之前、我没有看到 BB 位的任何轮询。 我不确定这是否会在多主器件设置中导致问题、但我想在您的用例中可以。

    发送数据

    轮询 I2C_IRQSTATUS_RAW[4] XRDY 位、或使用 XRDY 中断(I2C_IRQENABLE_SET[4]
    XRDY_IE 位必须设置为1)才能向 I2C_DATA 寄存器写入数据。
    ...
    中断子例程序列

    这是我们最后圈回误差来源的部分。  omap_i2c_xfer_msg 开始倒计时。 如果 ISR 没有在一秒内完成发送、则会超时。

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    /*
    * REVISIT: We should abort the transfer on signals, but the bus goes
    * into arbitration and we're currently unable to recover from it.
    */
    if (!polling) {
    timeout = wait_for_completion_timeout(&omap->cmd_complete,
    OMAP_I2C_TIMEOUT);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    其中 OMAP_I2C_TIMEOUT 的定义如下:

    Fullscreen
    1
    i2c-omap.c:#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    同时、我们使用 OMAP_i2c_isr_thread 来捕获 XRDY 中断、并使用 OMAP_i2c_xfer_data 来执行中断子例程序列。

    因此、我希望我们在以下情况下超时:从未调用 ISR、或者 OMAP_i2c_xfer_data 只是无限期旋转。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    后续调试步骤

     当 stat 非零时、看起来可能无限期旋转 OMAP_i2c_xfer_data:

    Fullscreen
    1
    2
    3
    bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
    stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
    stat &= bits;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    您是否愿意在内核驱动程序中添加 print 语句并重新编译? 我想看看 stat 的值。 您可以在"controller timed out\n"行的正下方添加另一个 dev_err、其中包含该信息。

    在生产代码中的 ISR 内添加 print 语句是不好的做法、但我不记得 Linux 编译器是否确实会阻止您这样做。 因此、您也可以尝试在 ISR 内部添加一条 print 语句、查看您是否曾到达 ISR。

    此致、

    Nick

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Nick。  

    感谢您的答复。  

    按照您的建议捕获 void 消息生成点、例如它是从处理器侧生成还是从从从侧生成。 我将附加此场景的 Saleae 日志。  

    如果您查看 Saleae 的301.5秒日志、SDA_3V3线路被下拉、但 SCL_3V3线路未变为低电平。 根据 TRM、此条件将成为 void 消息。  

    SCL_3V3 -时钟

    SDA_3V3 -处理器侧的数据线

    SDA_1v8 -从器件侧的数据线

    处理器(主器件)和从器件之间有电平转换器。 我们已检查电平转换器两侧的数据线电平、看起来像是在主侧(处理器侧)开始生成无效消息。

    请检查随附的 Saleae 日志是否相同。

    e2e.ti.com/.../void_2D00_message_2D00_condition.zip

    让我们知道您从这些日志中得出的结果、并建议我们如何避免这种情况。

    此致、

    Jay

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jay:

    感谢连接波形。

    VCC1.8V 线对我来说很有趣。 应用 VCC_1V8电源与 I2C 外设何时准备好进行交互之间需要多长时间?

    我注意到、在所有成功的 I2C 交互中、VCC_1V8线会变为高电平、然后 I2C 外设的 SDA_1V8线会变为高电平、然后 SDA_3V3线会变为低电平。 但是、对于不起作用的情况、在 SDA_3V3变为低电平之前、SDA_1V8线绝不会变为高电平。 如果每次 I2C 通信未正确完成时都发生相同的事情、那会很有意思。 在 Linux 开始尝试与外设进行交互时、我想知道外设是否尚未准备就绪。

    工作案例:

    无法正常工作的情况:

    很显然、在 Linux 软件中也许仍然有某些操作、但是我想首先确保硬件如预期的那样启动。

    此致、

    Nick

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Nick。  

    您来自其他主题的回复:

    "我还希望您从硬件方面验证一件事:您能否确认 void 消息实际上来自 AM62Ax、而不是 I2C 总线上的其他内容?

    我希望该测试看起来像是将一个电阻器与 SDA 线串联、并测量电阻器每一侧的电压。 电阻器的哪一侧先开始改变电压?'

    您能否提供电阻值和一些原理图来测量数据? 另外、如果还需要测量任何其他内容、请告知我们。 我们的硬件团队希望再次验证这一点。  

    此致、

    Jay

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jay:

    我已让 Sreenivasa 在另一个主题中评论电阻器值:
    https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1446977/am62a7-i2c-bus-timeout-issue/5584257#5584257

    如果 Sreenivasa 在下周未回复、请随意使用该主题。

    一旦您能够确定 只有在 SDA_3V3在 SDA_1V8能够变为高电平之前变为高电平时或者这仅仅是上一个波形捕获中的巧合、I2C 超时才似乎发生、我们就可以继续讨论此线程。

    此致、

    Nick

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您是否使用与 AM62Ax 不同的电源为 I2C 外设供电?

    请参阅此常见问题解答、了解 AM62Ax 与外设之间的一些通用电源时序指南:
    https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1300808/faq-am625-am623-custom-board-hardware-design-power-sequencing-between-soc 处理器和连接器件失效防护

    此致、

    Nick

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Nick。

    我们将使用不同的电源为 I2C 外设供电。 我们将通过 SOC GPIO 启用外设电源、因此在 SOC 通电之前将关闭外设。

    谢谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Virag、

    SOC GPIO 是如何开启的? 您要做什么来确保在 Linux I2C 驱动程序开始尝试与外设通信之前经过一段时间?

    您好、Sreenivasa、

    对于电源排序、当外设与处理器单独供电时、我不确定 IO 引脚何时被视为"已加电"(即、Virtag 和团队何时可以安全地为 I2C 外设供电?)。 是否在电压轨全部启动后 IO 立即供电、即可能在 uboot 启动之前? 或者直到应用 pinmux 设置时它才通电、还是在其他一点上通电?

    谢谢!

    Nick