Linux: I2C Broadcom错误解决方法。

创建于 2013-03-20  ·  73评论  ·  资料来源: raspberrypi/linux

Broadcom BCM2835在I2C模块中存在一个(硬件)错误。

BCM以一种不好的方式实现了“时钟延长”:

BCM并没有确保时钟的最小“高电平时间”,而是让I2C时钟在内部运行,并且当需要再次翻转时钟时,它将检查时钟是否变高,如果时钟变低,则检查时钟是否变高。做一个“时钟延长”。 但是,如果在检查之前几纳秒内,从机就释放时钟信号,表明它已准备好使用新时钟,那么时钟脉冲可能会短至40ns。 (这是我能够衡量的最低水平,当然,这种情况很少见)。 对于100kHz(10微秒)的I2C时钟,释放时钟的“不良”时刻相隔5微秒。

我的奴隶要求至少500ns的时钟脉冲。 (应该比将主机配置为100kHz工作时所产生的主机短十倍)。

那是我们目前无法做的硬件错误。 (硬件专家的提示:而不是通过这种方式实现时钟延长:在时钟保持低电平时禁止CLOCKDIV计数器的计数。这可能会在每个周期上使几个快速时钟扩展时钟,但是标准一致性将大大改善)。

发生这种情况时,BCM将发送一个带有非常短的第一个时钟脉冲的字节。 从设备然后看不到第一个时钟脉冲,因此当在该字节的末尾需要对那个字节进行确认时,从设备仍在等待第8位。 BCM将此解释为“ NAK”,并中止I2C传输。 但是,在该时间点,从站看到其第8个时钟脉冲并发出“ ACK”(将SDA线拉低)。 这又意味着BCM无法为下一次传输发出适当的“开始”条件。

建议的软件解决方法,以减少此硬件错误的影响:当传输由于字节的“ NAK”而中止时,请在STOP之前发出一个额外的时钟周期以同步从设备。 这可能必须在软件中完成。

仅当从站未ACK字节时,才在“错误路径”中发生这种情况。 也许最好仅在它不是传输的第一个字节时才执行此操作,因为该错误不会发生在传输的第一个字节上。

此软件修复程序是否属于驱动程序? 是。 它是存在错误的硬件驱动程序。 驱动程序的责任是使这种越野车硬件尽其所能。

最有用的评论

嗨hmf2015,
这不是论坛。 这是一个错误跟踪器。 此评论列表讨论了与您的问题无关的错误。 请与适当的论坛或服务台讨论您的问题。 再次感谢您提出的问题:“也许是相同的?也许我的描述有助于解决该错误?” 但现在我们可以确定您所看到的与您无关,请不要进一步“污染”此讨论。

所有73条评论

如果驱动程序中的变通办法可以使大多数用户更好地使用它,请确保应将其包括在内。
你有合适的补丁吗?

还没有。

1)我还没有深入研究I2C驱动程序。 大约一年前,我有计划自己写,但是在我熟悉之前,有人写过它。 因此,一个已经知道此驱动程序的人可能会做得更好,可以进行为时5分钟的项目。 我至少要花几个小时才能认识司机。
2)如果您(也许还有其他人)同意有必要进行修复/解决,则应首先进行讨论。
3)我只是想将其记录为“待办事项”,我们不应忘记它...。
4)也许有人会建议其他解决方法。

说到变通办法:当我们尝试启动新交易时,SDA线仍然很低也可能触发变通办法。 显然,这是一个“问题”。

“出错”的情况对于“正常”的情况可能很少见。 许多人将在I2C总线上安装hardware-i2c模块。 回到I2C发明之初,“ 10us”对于某些芯片来处理请求可能是“非常短的”时间范围,因此时钟延长是必要的。 如今,任何硬件I2C实现都应该能够甚至更快地处理“快速I2C”。

这与Atmel家伙实现其异步模块的方式相结合。 代替使模块以外部提供的时钟(i2c从属或SPI从属)运行,模块仍以处理器时钟运行。 它通过使所有输入信号经过一串filpflops来同步所有输入信号。 好的硬件设计。 替代方案是IMHO更好:在外部时钟之外运行模块,并在数据传递到另一个(cpu-)时钟域时进行同步。 例如,这将允许SPI模块以20MHz的速度运行,即使CPU仅以8运行。

无论如何。 足够的硬件干扰。

建议的解决方法:在事务开始时,SDA线仍然很低,请发出一个额外的时钟周期。 (它应该从高位开始才能发出“开始”条件)。

首先,我对I2C知之甚少。 我已经与Gert和其他人谈过解决方法。

I2C存在两个已知的问题:

  1. 您描述的时钟延展问题
  2. 重新启动时I2C状态机出现问题

对于1,Gert的观点没有万无一失的解决方法。
如果I2C从站不支持时钟延长,则可以。
如果I2C时钟延展了一定数量,那么降低I2C时钟频率可以避免该问题
对于以前情况下不会掉线的从属设备,请切换到驱动程序,这是一种安全的解决方法。

我不知道您的建议是否可行。 我很想知道它是否可以解决问题或完全解决问题。

Gert说,他对将要尝试发布的错误有所保留。

对于2,在GPU I2C驱动程序中,我们有一些代码可以解决状态机问题:

/***********************************************************
 * Name: i2c_actual_read
 *
 * Arguments:
 *       const I2C_PERIPH_SETUP_T *periph_setup,
         const uint32_t sub_address,
         const uint32_t data_to_read_in_bytes,
         void *data
 *
 * Description: Routine to actually transfer data to the I2C peripheral
 *
 * Returns: int == 0 is success, all other values are failures
 *
 ***********************************************************/
static int32_t i2c_actual_read(  const I2C_PERIPH_SETUP_T *periph_setup,
                                 const I2C_USER_T *user,
                                 const uint32_t sub_address,
                                 const uint32_t read_nbytes,
                                 void *data,
                                 const int using_interrupt)
{
   int32_t rc = -1; /* Fail by default */
   int32_t status = 0;
   int32_t nbytes;

   uint32_t sub;
   uint8_t* read_data = (uint8_t*)data;
   uint32_t data_read = 0;

   if( NULL != periph_setup && NULL != data ) {

      // confirm that the latch is held for this transaction
      assert( i2c_state.periph_latch[ periph_setup->port ] != rtos_latch_unlocked() );

      // -> START
      // -> Slave device address | WRITE
      // <- Ack
      // -> Sub address
      // <- Ack
      // -> Sub address
      // <- Ack
      // -> ReSTART
      // -> Slave device address | READ
      // <- Ack
      // <- Data[0]
      // -> Ack
      // <- Data[1]
      // -> nAck
      // -> STOP

      I2CC_x( periph_setup->port )     = I2CC_EN | I2CC_CLEAR; /* Enable I2C and clear FIFO */
      I2CS_x( periph_setup->port )     = I2CS_ERR | I2CS_DONE | I2CS_CLKT; /* clear ERROR and DONE bits */
      I2CA_x( periph_setup->port )     = periph_setup->device_address;

      sub = sub_address;
      nbytes = periph_setup->sub_address_size_in_bytes;

      if( 0 == nbytes ) {
         /* No subaddress to send - just issue the read */
      } else {
         /*
           See i2c.v: The I2C peripheral samples the values for rw_bit and xfer_count in the IDLE state if start is set.

           We want to generate a ReSTART not a STOP at the end of the TX phase. In order to do that we must
           ensure the state machine goes RACK1 -> RACK2 -> SRSTRT1 (not RACK1 -> RACK2 -> SSTOP1). 

           So, in the RACK2 state when (TX) xfer_count==0 we must therefore have already set, ready to be sampled:
           READ ; rw_bit     <= I2CC bit 0   -- must be "read"
           ST;    start      <= I2CC bit 7   -- must be "Go" in order to not issue STOP
           DLEN;  xfer_count <= I2CDLEN      -- must be equal to our read amount

           The plan to do this is:
           1. Start the sub-add]ress write, but don't let it finish (keep xfer_count > 0)
           2. Populate READ, DLEN and ST in preparation for ReSTART read sequence
           3. Let TX finish (write the rest of the data)
           4. Read back data as it arrives

         */
         assert( nbytes <= 16 );
         I2CDLEN_x( periph_setup->port )  = nbytes;
         I2CC_x( periph_setup->port )    |= I2CC_EN | I2CC_START; /* Begin, latch the WRITE and TX xfer_count values */

         /* Wait for us to leave the idle state */
         while( 0 == ( I2CS_x(periph_setup->port) & (I2CS_TA|I2CS_ERR) ) ) {
            _nop();
         }
      }

      /* Now we can set up the parameters for the read - they don't get considered until the TX xfer_count==0 */
      I2CDLEN_x( periph_setup->port )  = read_nbytes;
      I2CC_x( periph_setup->port )     |= I2CC_EN | I2CC_START | I2CC_READ;

      /* Let the TX complete by providing the sub-address */
      while( nbytes-- ) {
         I2CFIFO_x( periph_setup->port ) = sub & 0xFF; /* No need to check FIFO fullness as sub-address <= 16 bytes long */
         sub >>= 8;
      }

      /* We now care that the transmit portion has completed; the FIFO is shared and we mustn't read out
         any of the data we were planning on writing to the slave! */

      /* Wait for peripheral to get to IDLE or one of the two RX states - this way we *know* TX has completed or hit an error */
      {
         uint32_t state;
         bool_t state_transition_complete;
         bool_t error_detected;
         do { 
            state = (I2CS_x( periph_setup->port ) & 0xf0000000) >> 28;
            state_transition_complete = ((state == 0) || (state == 4) || (state == 5));
            error_detected = (I2CS_x(periph_setup->port) & (I2CS_ERR | I2CS_CLKT)) != 0;
         } while(!state_transition_complete && !error_detected);

         if (error_detected) {
            /* Clean up, and disable I2C */
            I2CC_x( periph_setup->port ) &= ~(I2CC_INTD | I2CC_INTR);
            I2CC_x( periph_setup->port ) &= ~(I2CC_START | I2CC_READ);
            I2CS_x( periph_setup->port ) = I2CS_CLKT | I2CS_ERR | I2CS_DONE;
            I2CC_x( periph_setup->port ) |= I2CC_CLEAR;
            I2CC_x( periph_setup->port ) = 0;
            return -1;
         }
      }

      if (using_interrupt)
      {
         /* Wait for interrupt to complete. */
         i2c_state.active_buffer[periph_setup->port] = data;
         i2c_state.active_buffer_length[periph_setup->port] = read_nbytes;
         i2c_state.active_buffer_offset[periph_setup->port] = 0;
         i2c_state.pending_transfer[periph_setup->port] = I2C_PENDING_TRANSFER_READ;
         RTOS_LATCH_T latch = rtos_latch_locked();
         i2c_state.pending_latch[periph_setup->port] = &latch;

         /* Enable interrupt. */
         I2CC_x( periph_setup->port ) |= I2CC_INTD | I2CC_INTR;

         rtos_latch_get (&latch);

         i2c_state.pending_latch[periph_setup->port] = NULL;
         data_read = i2c_state.active_buffer_offset[periph_setup->port];

         rc = (data_read == read_nbytes) ? 0 : -1;
      }
      else
      {
         uint32_t time_now = 0;

         /* Loop until we've read all our data or failed. */
         while( 0 == ( I2CS_x(periph_setup->port) & (I2CS_TA|I2CS_ERR|I2CS_DONE) ) ) {
            _nop();
         }

         /* Wait for some data to arrive - we should wait, at most, I2C_TIMEOUT_IN_USECS for data to arrive every time we start waiting */
         time_now = i2c_state.systimer_driver->get_time_in_usecs( i2c_state.systimer_handle );
         while( ((i2c_state.systimer_driver->get_time_in_usecs( i2c_state.systimer_handle ) - time_now) < I2C_TIMEOUT_IN_USECS)
                && ( data_read < read_nbytes )
                && !(I2CS_x( periph_setup->port ) & I2CS_ERR) ) 
         {
            if (I2CS_x( periph_setup->port ) & I2CS_RXD) 
            {
               read_data[ data_read ] = I2CFIFO_x( periph_setup->port );
               data_read++;
               time_now = i2c_state.systimer_driver->get_time_in_usecs( i2c_state.systimer_handle  );
            }
         }

         if( (data_read != read_nbytes) /* Did we read all the data we asked for? */
             || ( (read_nbytes - data_read) != I2CDLEN_x( periph_setup->port ) ) /* Has DLEN decremented? */
             || ( 0 != (I2CS_x( periph_setup->port ) & I2CS_ERR) ) ) { /* Are there any errors? */
            rc = -1;
         } else {
            while( I2CS_DONE != (I2CS_x(periph_setup->port) & I2CS_DONE) ); /* Wait for the peripheral */
            rc = 0;
         }
      }

      /* Clean up, and disable I2C */
      I2CC_x( periph_setup->port ) &= ~(I2CC_INTD | I2CC_INTR);
      if(I2CS_x( periph_setup->port ) & I2CS_ERR) {
         //Wait for it to be idle
         while(I2CS_x( periph_setup->port ) & I2CS_TA)
            _nop();
      }
      I2CS_x( periph_setup->port ) = I2CS_ERR | I2CS_DONE;
      //Finally disable the I2C
      I2CC_x( periph_setup->port ) = 0x0;
   }

   if( !user->skip_asserts ) {
      assert( rc >= 0 );
      _nop();
   }

   return rc;
}      

我不确定人们是否遇到了这个问题,但是如果您愿意,粘贴可能会有所帮助。

无法完全根除此硬件错误。

发生这种情况时,主机和从机在时钟周期数上存在分歧。 因此,从属设备解释的数据与作为主设备解释的数据(=树​​莓pi =驱动程序/应用程序)不同。 您可能正在某个地方的寄存器中写入一个完全伪造的值。 太烦人了。

我建议的解决方法至少会导致下一个事务正常工作。 影响将减半:仅一项交易被取消,而不是两项。 这不会消除问题。

如果I2C从站不支持时钟延长,则可以。

如果I2C从站不需要时钟延长...

如果I2C时钟延展了一定数量,那么降低I2C时钟频率可以避免该问题

是。 我在一个位置上有10个“现场”设备。 显然,三个模块的时钟频率(RC时钟)是不同的,以至于它们最终在完全错误的时刻延长了“完成”时间。 降低时钟频率解决了这些模块的问题。

如果时钟延长延迟不是固定的,而是变化超过5微秒,则统计上或多或少有机会解决此问题。 在我的情况下,从机需要0.25微秒的时钟宽度。 因此,时钟延长在BCM的时钟更改时刻之前的5%的时间内结束,这会出错。 因此,在这种情况下,大约每20个传输中就有1个会出错。 (规范说,一个时钟脉冲的最小值为250ns。实际上,这并不意味着它是否更短就不会被看到。我认为它的出现机会从> 250ns的100%线性变为<< 125ns。)

我昨天花了很多时间来延长时钟延长周期,使其在5微秒的机会窗口内落在2.5微秒的标记附近。 如果我打算以窗口的开始为目标并且我的RC时钟运行得有点快,那么我会点击“ 0”来触发该错误。 如果我的目标是5,同样的事情。 所以现在我的目标是在中间,远离糟糕的地方。 但是将I2C时钟更改为80kHz,然后将BAM更改为敏感点……(如果80kHz不会发生,那么它的值会在80到100之间)。

哈哈! 我以完全相同的方式对测试板进行了检测。 我已经切断了SCL走线,并在其上安装了一个0.1英寸的跳线连接器。在不测量的情况下,那里有一个正常的跳线,或者当我连接时,带有100欧姆电阻的母连接器。

我不认为这只会在第一个时钟发生。 这意味着我可以通过根本不进行时钟延长(如大多数硬件I2C芯片那样)或通过使时钟延长至少持续整个周期来解决该问题。

我以一种可以使时钟延长以0.5微秒为增量变化的方式来检测i2c从代码。 我可以命令它在I2C上将时钟延展更改为XXX,然后在更改回默认值之前像这样工作50毫秒。 (以防万一它不起作用,我们需要它再次起作用。这样,我可以快速扫描这些设置的整个范围的值,同时使用逻辑分析仪监视SDA和SCL线。发送“使用延迟XXX”,然后发送一个字符串需要25毫秒,然后在脚本中增加一个计数器并发送“下一个延迟”将花费大约100ms的shell脚本,因此我可以在10秒钟内扫描100个可能的值。

我已经看到该错误在更长的延迟时间内发生。 因此,“仅在第一时间发生”这一理论是不正确的。

关于“超级高效”中断处理程序:是的,我也可以这样做。 问题是:时钟扩展功能使我可以将“处理此字节”代码放入中断例程中,而不必担心它花费几微秒或几毫秒的时间。 从理论上讲,时钟延长将确保主机在继续下一个字节之前等待我完成该字节的处理。 该计划完全被2835中的错误所破坏。我现在只是使时钟延长停止,然后希望在随后的70微秒内完成对字节的处理。

我必须以“周期计数”为目标,以5微秒半时钟的中间时间为我释放时钟舒展。 如果我打算开始(以导致4.9微秒为时钟高周期),则我的从属服务器上的时钟可能会以百分之几的速度运行,并导致bug提前触发半个周期。 因此,半个时钟周期的两端都很危险,我必须争取一个较短但有效的时钟周期。

模块中的更改很简单,恕我直言:当SCL被“驱动为高电平”(即完全不驱动)时,停止I2C模块主时钟。 这具有允许更长的I2C总线产生的副作用,因为当总线电容高于规格时,会发生自动时钟延长。

这个: http : http :

感谢您尝试提供帮助,iz8mbw,但这些与此(硬件)错误无关。

我已经测量了我的I2C时钟,它显示为驱动器认为应该的100kHz。 驱动程序有一个“时钟源”对象,它查询频率并使用该频率。 我尚未检测驱动程序以打印出频率。

只是为那些想了解实际错误的人提供的信息,我以逻辑分析器转储的形式提供了一些“证明”。
嗯,我可以附加图像,但不能附加二进制LA转储。 那个在这里: http :

在图像LA_with_bug_shot1.png中,您将看到一小段活动:“将延迟设置为XXX”,然后是一小段尝试写入约10个字节的突发,但是由于NACK而中止。 在右侧,您会看到一个适当的10字节数据包。 SDA线一直保持低电平,直到下一个未对齐的突发(所有位都已移位,并且在我的从设备中,“ xth-byte-in-packet”计数器尚未被该数据包开始时的不存在的启动条件重置) 。

在图像LA_with_bug_shot2.png中,我放大了发生短脉冲的部分。 我见过的最长的脉冲出错了:290ns。 (以上是针对Atmel的数据表规格!)
LA_with_bug_shot1
LA_with_bug_shot2

哦,那是哪里来的!

我有一个我想从树莓派使用I2C控制的项目,说实话,我接近放弃,要么切换到Beagleboard,要么让Pi通过SPI通过FPGA与FPGA对话,然后执行I2C任务。

我的邮件中有一个委员会可以做到这一点(预计交付时间:明天)。 SPI连接器,I2C连接器。 尝试使用该板将是一个不错的项目。 给我发送电子邮件,如果您想随时了解情况。

当前情况:我看到行为与Gert兼容:当从属设备是ATMEGA时,“只有第一个周期会出错”,而当从属设备是我的ATTINY之一时,我看到的是完全起作用的错误。

这是我测试的延迟:
i2c_delays_atmega
在此测试期间观察到的最短SCL脉冲为4.5微秒。

现在使用attiny从站进行测试,已测试的ACK延迟为:
i2c_delays_attiny

最小脉冲宽度为41ns(我的测量分辨率):
i2c_delays_attiny2

啊。 找到了! 似乎在字节的ACK之前延长时钟是“危险的”,但在ACK之后延长时钟是可以的......

我和其他人肯定遇到了重复的开始问题。 我在proc hipi_i2c_read_register_rs中的http://cpansearch.perl.org/src/MDOOTSON/HiPi-0.26/BCM2835.xs上有一个用户空间黑客。 即使我还没有弄清楚如何确定TX阶段已经完成,这似乎也适合那些报告尝试过或合并了C代码的用户(尽管只有5个人)。 我想我需要学习编译内核模块并针对上面的代码运行现有的测试。

我们难道不可以强迫内核忽略I2C硬件,并在相同的引脚上使用基于GPIO的I2C? 我认为这样做的开销比硬件本身的错误更容易接受。

您期望什么开销? 当前驱动程序默认为100kHz时钟。 因此,从i2c间隙传感器读取10个字节大约需要1毫秒。 如果您不停地进行操作,那么很可能一直在搅动CPU周期...。

我的喜好是驱动程序可以通过模块参数(或者,如果更方便的话,可以使用单独的模块)来支持bitbanging i2c。

许多设备不使用时钟延展(或时钟延展一定数量,因此可以在降低的速度下正常工作),因此在这些情况下,硬件I2C驱动程序仍然是首选。

内核本身在GPIO引脚上具有用于位撞I2C的驱动程序,此驱动程序的开销比从用户空间进行位撞的开销低得多,并且公开了与硬件I2C驱动程序相同的API。 我的建议是将驱动程序和硬件I2C驱动程序都编译为模块,然后默认加载硬件驱动程序。

@Ferroin
您是否在Pi上使用了bitbanged I2C驱动程序?
您添加了哪些.config选项来构建它? 是否有任何源补丁?
您如何选择要使用的驱动程序(modprobe?不同的/ dev /设备?)

尚未在Pi上使用驱动程序,但我有一个朋友在BeagleBoard上成功使用了该驱动程序。
config选项为I2C_GPIO。
如果将该驱动程序和Broadcom驱动程序都配置为模块,则选择驱动程序就像加载内核模块一样简单。
GPIO模块确实需要参数来告诉它将哪些GPIO用作SDA和SCL,我不知道这些参数是什么,但是基于dirvers / i2c / busses / i2c-gpio.c中未充分记录的源,看起来合适的参数是'sda = X scl = Y',其中X和Y是您要使用的引脚。

i2c-gpio模块本身不提供任何向其传递参数的方法。 因此,您需要另一个模块来注册平台数据并至少配置总线号,SDA和SCL引脚。 我已经写过这种模块的概念证明,它甚至可以在引脚0和1上工作,但是没有加载i2c-bcm2708(i2cdetect检测到pcf8574,我能够用gpio-pcf857x模块驱动某些LED)。 但是后来我在更换引脚时烧掉了pcf8574(而且我现在没有任何其他i2c芯片),所以我无法真正对其进行测试。 是代码

@kadamsi
设置sda_pin / scl_pin模块参数可能很有用。 如拉请求。
谁能确认这对他们有用?

这看起来并不那么琐碎:它希望一直传递到一个PlatformData结构。

另一方面,该平台并没有规定您今天要使用哪些GPIO,因此进行更改工作听起来确实合理。 (通常,平台数据指定:“ / this /计算机如何连接”。)

@popcornmix
我正计划使它们可配置,但我昨天没有足够的时间。 我还希望它能够一次创建多个总线。 也许以动态方式,例如GPIOS exportunexport sysfs文件(但我不确定是否有可能彻底取消导出此类总线)? 哦,我发现了另一个pcf8574,可以确认使用外部上拉电阻时,它在不同的GPIO引脚上也能正常工作。 不幸的是,我没有要测试的更复杂的I²C设备。 那么您是否有兴趣在默认内核树中提供这样的模块?

@kadamski
我没有安装程序来测试像这样的模块。 但是,芯片提供的任何硬件功能(例如I2C)都应具有内核驱动程序,以允许更多的人使用它们。 如果I2C硬件存在会阻止人们使用某些外围设备的错误,那么值得一听的替代声音听起来很值得。

因此,如果您生产的新驱动程序对不使用它的人无害(即作为模块构建,并且在加载之前什么也没有),并且有证据(即一些确认用户报告)可以正常工作,那么我很高兴接受PR。

硬件是否已在BCM2837(在RPi 3中)上修复?

我的猜测是:不。 但是我今天可能没有时间对此进行测试。

BCM2837 I2C保持不变。

不幸的是,但感谢您的信息。

多数民众赞成在非常烦人。

我同意。 是否有人链接到BCM2837勘误表或类似内容,说明问题仍然存在? 当我们必须传递新闻时会很方便。 或@ P33M ,如果您为Broadcom工作,也许

他是权威人士,尽管不适用于Broadcom。

那很好。 但是我已经用Google搜索了,除了P33M在其他地方是M33P之外,还很难找到我可以有用地传递的ID。 很好,但这意味着他不是引述的好消息。 :-)因此,勘误链接非常方便。

@ P33M适用于Raspberry Pi。 您可以将他所说的视为权威。

我认为可能没有勘误表。 我离开他了
确认他的身份,还是不行!

2016年3月15日14:30,RalphCorderoy [email protected]写道:

那很好。 但是我已经搜索过Google,除了P33M是M33P
在其他地方,努力寻找可以有效传递的ID。 没关系
但意味着他不是引述的好消息来源。 :-)因此,勘误链接将是
便利。

-
您收到此邮件是因为您发表了评论。
直接回复此电子邮件或在GitHub上查看:
https://github.com/raspberrypi/linux/issues/254#issuecomment -196845789

@RalphCorderoy我是Raspberry Pi(trading)Ltd的雇员。我的回答是权威的。

@ P33M ,Ta,那样做。 对不起,麻烦。

这正在影响我正在从事的项目。 幸运的是,我可以完全控制从属设备的固件,并且能够添加使用变通方法来在响应中添加额外的半周期延迟(时钟延长),从而避免不良行为。

可以在advamation.com上找到对该问题的良好分析。

是Broadcom的I2C实现中的这种不良硬件,还是可能进行内核调整以使硬件正常运行?

我刚刚订阅了这个问题,因为我正在开发的产品也遇到了这个问题
在AVR和Pi之间使用i2c。 现在,我需要重新考虑。
有没有人使用过任何可靠的i2c比特冲击形式?

@ mwilliams03 ,您可能对该项目很感兴趣,在

特别是,这里是有关I2C问题的信息。 另请注意, AVR的TWI模块存在阻止快速读取的问题

感谢@ pdg137 ,我尝试了一下,并且第一次尝试时,我获得了120万次读取,没有错误,并且仍在继续。

@rewolff看来此问题已解决。 如果是这种情况,请关闭此问题。

现在....添加一个电平转换器和40cm的延长线..然后可以使用吗? 很有可能这会在波形的“上”侧引起足够的延迟,并且突然间,错误再次出现。

据我所知,Broadcom和员工仍然认为此错误仅限于最后一个字节之后的第5微秒(实际上是半个时钟)。 那么只需增加10微秒,便可以将时间延长到两个半钟,并且应该没有问题。 在我的测试中,我发现“不好的”时刻使时钟每5微秒延长一次。

由于SPI和I2C之间的对称性,如果在“下一个数据”中断中“计算”下一个数据字节,则在我的AVR代码中更容易...。(我公开了一个允许继续读取的接口,因此有16个字节的缓冲区并不总是足够的。)。

我不相信。

我在Respberry Pi和ATMEGA 324PA之间遇到SMBus的问题-这些可能与这个问题有关吗? https://stackoverflow.com/questions/39274784/talking-smbus-between-raspberr-pi-and-atmega-324pa-avr-not-clock-stretching

据我所知,Broadcom和员工仍然认为此错误仅限于最后一个字节之后的第5微秒(实际上是半个时钟)。

@rewolff :我必须同意Broadcom员工的意见。 在我的测试中,使用Raspberry Pi 3和100 kHz I2C(在节流CPU时会降低到62 kHz),我从advamation.com获得了类似于

动画听起来不错。 但是,这与我的经验不符。 也许我应该设置一个测试。 可能要花一点时间。 它忙着其他东西。

但是,如果是这种情况,通常在中断例程中使用“ usleep(10)”(具有硬件时钟延长功能)通常就可以解决问题,并使事情无法锁定。 我很确定事实并非如此。 :-(

@rewolff :在Raspberry Pi 3上,我已经看到CPU调至600 MHz,导致默认的I2C速度为62 kHz。 因此,如果ISR在SCL的下降沿开始,则应在从机的ISR中休眠17微秒。 或者,如果您认为CPU可能会被限制在600 MHz以下,则请睡眠更长的时间。

Raspberry Pi内核中是否可以包含@kadamski的i2c-gpio-param模块? 我可以确认这种方法似乎对我的应用程序(AVR软件I2C从站)非常有效,并且为树莓派内核安装所需的标头有些麻烦,因此使它可用非常好。

解决整个问题的硬件错误也是一个不错的解决方法。

@onnokort您的意思是像2015年11月以来在当前内核中存在的i2c-gpio覆盖吗? https://github.com/raspberrypi/linux/blob/rpi-4.4.y/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
从自述文件中获取覆盖:

Name:   i2c-gpio
Info:   Adds support for software i2c controller on gpio pins
Load:   dtoverlay=i2c-gpio,<param>=<val>
Params: i2c_gpio_sda            GPIO used for I2C data (default "23")

        i2c_gpio_scl            GPIO used for I2C clock (default "24")

        i2c_gpio_delay_us       Clock delay in microseconds
                                (default "2" = ~100kHz)

@ 6by9 :太好了,谢谢,我今天学到了一些新东西。 我尚未对此进行测试,但是,是的,这正是我想要的(并在i2c-gpio-param中找到了)。

@popcornmix @ 6by9可以关闭吗? 大约是很长一段时间了,我阅读的dt param内容似乎是一个不错的选择。

对于绝对不能与我们的I2C硬件完美配合的设备,建议的解决方法是使用i2c-gpio覆盖层,该覆盖层将引脚固定。

否则,上游驱动程序将支持地址ACK阶段的时钟延长。

另外两美分: https

亲爱的所有人,今天,我已经测试了来自东亚的GY-955封装中的BNO055,它在Pi 2B(BMC2835)的情况下在100_000 Hz时表现非常难看。 为了进行测试,我将I2C总线的频率从50_000更改为400_000 Hz,发现100_000 Hz时出现问题,但是对于50_000、85_000、115_000和125_000Hz,来自Adafruit的代码(Adafruit_Python_BNO055)与I2C连接150_000可以很好地工作对于BNO055,Hz似乎太快了,它可以工作,但是有时值是错误的。 我承认,我没有用示波器测试频率,我只读出了/ sys / class / i2c-adapter / i2c-1 / of_node / clock-frequency文件,因此存在一些不确定性。 现在,我开始在ADA中实现与BNO055的完整接口。
默认:BMC I2C处理中的硬件错误仅在100_000 Hz出现,必须确认。

仅供参考,当从设备进行时钟扩展并在0.9至0.999 I2C时钟周期后释放SCL线时,就会发生硬件错误。 该行将开始上升,并且pi硬件将说:哦,他没有进行时钟延长,因此我可以通过将时钟线再次拉低来提供下一个时钟脉冲。

当时钟周期中剩余的时间足以使clk线通过覆盆子的“ HIGH”阈值而不是从属设备的阈值时,或从属设备进行噪声过滤并在<x%of正常的I2C时钟周期故障。

这不仅会“仅在100kHz时发生”,而且还会在许多其他频率上发生,除了从设备的响应时间必须是一个不同的值。

假设时钟为100kHz,则正常周期为5us高和5us低。 现在假设在t = 0时pi通过将时钟线拉低来开始最后一个时钟周期。 在t = 5us时,pi释放时钟信号,但从机仍处于忙状态并保持时钟为低电平。 在t = 9us时,从机完成并释放时钟信号。 在t = 10us时,pi将查看时钟信号,并认为:好的,没有时钟延展,因此继续操作,它将时钟信号再次拉低。 现在,时钟信号仅保持1us的高电平(由于电容和上拉电阻的时间常数而变小了一点),从机可能看不到。 现在,另一台设备在9微秒后无法就绪,而在10.5秒后就无法就绪。 现在在100kHz时,pi会看到“仍然很低,时钟延展,再等待5微秒。现在我们将获得4.5微秒的时钟脉冲,一切都会正常进行。但是,以90kHz运行此设备,就会遇到麻烦。 pi将在开始时以11微秒为单位,并且时钟信号将保持高电平的时间少于一微秒->问题。

抱怨此事的人不是拥有其他设备的人。 这些以默认的100kHz工作。 但是该错误仍然非常真实,并且会以与您和我拥有的设备不同的总线速度在这些设备上发生。

感谢您的答复,它解释的很好,为什么我能以所选的频率获得可靠的转移:
在100_000 Hz时,问题会在9到9.99 µsec的时间内出现
在85_000 Hz时,问题开始于1_000_000 / 85_000 * .9 = 10,59 µsec> 9.99 sec,因此我认为时钟延展被忽略了,对于所有低于85_000 Hz的频率,问题的开始点都高于10,59 µsec 。
在115_000 Hz时,总线周期为1_000_000 / 125_000 = 8.7 µsec <9 µsec,因此可以正确检测到时钟脉冲,对于高于115_000 Hz的所有频率,总线周期均小于8.7 µsec。
因此,当我遇到问题时,我可以计算出所需的频率。
(我阅读了http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html上的信息,
记为.5,而不是一个时期的.9)。

好。 这取决于您的从站将什么检测为有效时钟信号。 以及总线上的RC引入了多少延迟。 就我而言,用作从机的AVR将小于两个时钟周期的脉冲视为小故障。 在内部RC时钟为8MHz(+/- 10%!!!)的情况下,必须至少检测250ns的脉冲。 I2C规范需要5微秒,因此在正式要求和不再适用之间存在20的“余量”。

起初我以为我会增加我的从属设备的时钟延长时间,所以说12us。 在总线电容增加足够的延迟以再次引起问题之前,这种方法一直有效。 因此很难解决。 不得不告诉您的客户不要使用标准的100kHz i2c,这很烦人。

抱歉,但是我需要一些时间来编写完整的实现和测试方案。
感谢您提供给我的所有信息,这非常有帮助。
我的测试场景是由2个MEMS(BNO055封装为GY-055,MPU9255封装为MPU-9250 / 6500,WHO_AM_I寄存器表示MPU9255)和1个GPIO扩展器PCF 8574(封装的PCF 8574)构建的。
Pi(2b)的I2C时钟设置为125 kHz,通过读取/ sys / class / i2c-adapter / i2c-1 / of_node / clock-frequency进行验证。
我的代码运行100次,从MEMS读取数据并以0.1秒的延迟为PCF写入数据。
结果:

  • MEMS的初始化成功。
  • 在所有周期中,通过I2C总线成功读取MEMS数据。
  • 在所有周期中,都已成功通过I2C总线将数据写入PCF。

因此,MEMS和PCF接受比标准100 kHz高的时钟。
在较老的环境中,通过串行线与AVR进行通信,在第二个环境中,通信将通过USB进行,但还没有完成,实际上我是由BNO055引起的I2C总线问题,但我认为在我的环境中,我找到了Pi 2b的解决方法,希望它也可以与Pi 3一起使用,这是下一个测试。 然后,我必须集成其他2个MEMS,1个VL53L0X和1个BME280,我希望它可以在新频率下工作,并且总线电容可以接受所有这些元素。

我现在正在RPi 3 Model B +上处理此问题,并且看到的结果与Advamation文章所述的结果不同。 芯片最近没有更新,是吗?

简短的版本是,如果我以read-preACK,write-preACK或write-postACK进行扩展,那么一切似乎都可以正常工作。 我唯一需要确保长时间伸展或根本不伸展的唯一时间是read-postACK。 不过,在我可以确定地说任何话之前,我仍然需要整理实验。

首先,有关术语的说明。 进阶文章说:

因此,只有在以下情况下,带有Raspberry Pi的I2C才有效
从站根本不使用时钟拉伸,或者
从设备仅在结束时/直接在I2C读取ACK阶段之后(读取ACK / NACK之后)延长时钟,但随后延长0.5个时钟周期以上。

术语“ I2C读取ACK阶段”似乎有点模棱两可。 如果是I2C读命令(即,将后地址R /W̅位置1),则从设备将写入A̅C̅K̅位,而不读取它,这与括号相反。 当我在这里说“ read-postACK”时,我的意思是R /W̅位是在地址之后设置的(大概不像SMBus那样被协议更改),因此从站刚刚写了其A̅C̅K̅响应。

如此处暗示的那样,如果RPi感觉到SCL被从机保持为低电平,则它将内部SCL时钟延迟半个周期(5μS)。 如果从站将SCL保持低电平_almost_半个周期,则会触发该错误。 如果发生这种情况,则RPi仍将使SCL变为高电平,然后在其SCL时钟触发后立即将其拉低。 这会导致时钟脉冲频率降低,某些设备可能会将其视为脉冲,而其他设备则不会。 (仅供参考: I2C规范暗示SCL的标称高电平时间为5μS,并在100kHz时确定了4.0μS的最小时间,这是RPi I2C接口的默认速度。)

在我的实验中,在读取预ACK,写入预ACK和写入后ACK阶段,RPi将确保允许的最大SCL高时间为4μS左右。 似乎愿意将SCL时钟推回那些阶段。 我怀疑RPi在释放它后不久就对SCL线路进行了采样,如果SCL仍然很低,它会将SCL时钟推回半相位。

但是,在read-postACK阶段,我确实看到,如果SCL线保持低电平大约6–9μS,则RPi将发出短时钟(<4μS,通常为2μS或更小)。 我怀疑,在此阶段,Broadcom工程师采用了不同的方法,试图降低他们在高电容线路上不得不延迟半阶段的可能性。 可悲的是-正如我们所看到的-它没有达到。

因此,我的当前代码需要在可能需要一段时间的读取(例如ADC转换)的read-postACK阶段将SCL扩展到½个周期之外。 如果我失败了

我正在运行的当前测试使用PIC16F1619作为从器件。 从设备使用循环来扩展前置和后置ACK的读写命令中的时钟。 该环路的长度加上开销从3μS(小于RPi使SCL保持低电平的时间)到90μS(以0.35μS的增量)变化。 我在RPi上有一个Python程序,该程序会将两个寄存器的值不同,然后将它们读回,并断言读回的值是正确的。 使用的值

皮拳
Broadcom一直对此轻描淡写,宣称此问题仅在最初的时钟延伸中发生。 我认为情况并非如此。 您应该能够验证这一点。 推广似乎遵循了Broadcom的声明。

@rewolff好吧,他们的解释可能有些

我很高兴进行一些更好的实验,以演示RPi的I2C何时可以处理时钟延展,以及何时不能处理时钟延展,并获得BCM可以发送给工程师的代表。

可悲的是,他们需要解决此问题的重要芯片版本; 当SCL保持为低电平时(通过内部或外部源),它们无需在SCL分频器时钟上打勾。 这可能需要进行硅级更改,这是昂贵的。 大多数ECO都是金属级的,这是……好,不便宜,但比硅便宜。

我的主要目标是通过一些实验证据来表征可以使用RPi或不可以使用RPi的从站的类型。

听起来我们需要更多可靠的数据,例如repro方案,才能说服Broadcom重新设计I2C控制器。 即使有了可靠的数据,工程师也必须说服管理层,为下一次修订而修改芯片是值得的。

也就是说,我将花一些时间来设计可重现的方案,以便BCM工程师可以清楚地看到并测试问题。 不过,我将依靠这里的社区成员将我的发现传达给Broadcom。 我没有联系他们的渠道。

我应该澄清一下我之前对社区的评论,即硅与金属的变化。

您知道,如果从SparkFun或Adafruit获得电路板,通常会留下痕迹,可以将其切割或焊接在一起以改变其行为? 大多数I2C板都有迹线,您可以更改其迹线以更改地址,启用或禁用上拉电阻等。

Microchip设计人员做同样的事情。 他们可以在微芯片的金属层上进行很多更改,因此不必更改硅层。 那是因为更改硅层既困难又昂贵(例如更改板上的芯片),而金属层更容易更改(例如更改板上的走线)。

金属层可以进行许多有用的更改,因为设计人员会提前考虑并进行金属连接(实质上是跳线),从而改变芯片的性能。

但是,如果有他们没有计划的更改,并且无法弄清楚如何通过重新路由芯片内的走线来进行更改,那么他们就必须更改芯片。 芯片需要更多的计划,验证和掩蔽,因此很难更改。

许多公司,如果它们的硅层“足够好”,将尽可能长地使用它。 他们将在芯片的多个版本中重复使用硅层的某些部分。

我怀疑这就是BCM所处的位置:他们需要有充分的证据证明无法在驱动程序或金属中修复此错误,然后他们才可以从头开始重新设计硅层的这一部分。

要解决这个问题,根本不可能重现现有的芯片(得到一百万美元吗?)。 谁知道,未来的芯片可能会修复。

乔尔·雷·霍尔维克(Joel Ray Holveck)在2018年9月5日星期三上午02:13:19写道:

听起来我们需要更多可靠的数据(例如重现场景)来
说服Broadcom重新设计I2C控制器。 即使
可靠的数据,工程师必须说服管理层
值得为下一个修订版本修改芯片。

他们已经进行了6年和3次硅版本修订,
已经证明了他们的决定:“不会解决”。

如果您以> .5周期拉伸,则您的身体状况良好。

我不这么认为。 每次您在“
Broadcom再次查看”时间段,您会收到短脉冲。我可以轻松地
将时钟信号的释放延迟5个无用的微秒
始终超出0.5个周期。 但这没有用。

James Hughes在2018年9月5日星期三02:28:53 AM -0700写道:

极有可能不会重新启动
仅仅为了解决这个问题而存在的硅片(得到了备用的100万美元?)。 未来
芯片很可能可以解决。

我对此表示怀疑。 我们从具有已知错误的BCM2835转到了具有已知错误的BCM2836
与BCM2837B0完全相同的错误。

现在您为什么认为下一个修订版本会有所不同?

BCM有一个目标市场:这些芯片的电话和电视棒。 在
他们的目标市场没人在做通用的I2C软件
AVR和PIC等微控制器。 他们不会解决此问题。

可惜的是,尽管需要这种调查工作,但确实如此。 当我之前要求提供涵盖这一点的勘误表时,以为没有一个。 现在是否已更改,并且有一个URL? 理想情况下,Broadcom可以通过准确描述故障来确定故障所在,并在发生故障时为社区提供帮助,从而可以更轻松,更有把握地对兼容组件进行变通或评估。 如果他们不想尝试将相关HDL的片段准确地转换为描述,甚至可以达到这些片段的程度。

当允许时钟延长时,建议停止半位时钟除数是一个很好的建议。 会的。

这样做的问题是I2C模块的一部分将需要以“全时钟速度”运行。 现在,I2C模块是一种不错的低功耗模块,因为它的运行速度通常不超过200kHz。

发表文章的主要原因是我在原始文章开头所说

我现在正在RPi 3 Model B +上处理此问题,并且看到的结果与Advamation文章所述的结果不同。 芯片最近没有更新,是吗?

如果在2013年Advamation写作后对I2C硬件或驱动程序进行了重大更改,并且社区知道它们可能会如何影响此错误,那么我应该对我的实验进行适当的更改。

我知道基本问题出在硬件上,但是据我所知,有人可能通过实验发现,更改驱动程序中看似无关的寄存器实际上会更改此错误的行为。 我还没有确认BCM2837具有与RPi 2相同的I2C模块(最近一次,我可以确定性地确认自首次报告此问题以来I2C硬件未更改)。 我也没有找到任何有关BCM283x步进的信息。 据我所知,BCM2836时代可能发生了重大变化。

我对抨击Broadcom,推测它们如何改变未来的版本或类似的东西不感兴趣。

我的主要目标是清楚地记录当前的行为。 看起来随着时间的流逝而改变。 我的第二个目标是允许将来的用户重现我的实验,以查看结果是否仍然有效,或者进行改进或测试其他条件。 我还有另一个次要目标,那就是让Broadcom工程师根据需要轻松地再现测试。 这两个方面都意味着我需要发布实验,这也有帮助:由于我自己的狂妄自大,如果我要发布实验,我将更有动力使其变得更加严格。

我目前的实验计划是使用PIC16F1619作为从器件实现。 它足够快速,通用,可以进行时钟拉伸实验,可以轻松进行操作,并且通用,其他实验者可以重现我的结果。 如果结果不明确,我可能还会使用FPGA进行实验。 我可能会看到,如果使用另一台Rashberry Pi作为从属配置,将其作为从属服务器,是否可以获得合理的粒度,但是我怀疑我需要没有完整OS的东西才能进行实时测试。

解决另外几件事:

抱歉,我的原始帖子不完整; 我不小心张贴了初稿。 我将保持原样,因为所做的更改很小。

我不主张在SCL外部保持低电平时暂停时钟除数的想法独具匠心。 我在其他地方读过,但不记得在哪里。 我以为是来自raspberrypi.org上I2C时钟拉伸线程中的Gert van Loo,但我现在找不到它,所以我一定在其他地方看到过。 我不相信这会大大改变功率分布,

I2C硬件模块尚未固定/更改,不太可能在bcm2835 / 6/7中修复,因为这将需要重新旋转芯片,这实在太昂贵了。

我不知道Advamation是谁,但是RFP(T)组尚未实现它们,所以我不能保证文章的准确性。

亲爱的大家,我在Pi 2B和3上遇到了一个非常奇怪的现象,我尝试解释一下:
当我六月底开始实施BNO055时,我使用了一个较旧的Raspbian(我现在不是该版本),并且使用i2cdetect获得了很多无效的I2C地址。 为此,我在网上查看了有关该论坛的信息。 为此,如上所述,我更改了I2C频率,所有虚影消失了,我可以工作了。 8月中旬,我将Raspbian升级为raspbi-dev 4.14.62-v7 +,系统变得有点不稳定,但是我可以工作。 从更新到更新,系统变得更加不稳定,注意到SD卡上有泄漏。 因此,我通过NOOBS(Linux raspbi-dev 4.14.62-v7 +#1134 SMP Tue Aug 14 17:10:10 BST 2018 armv7l)重新安装了Raspbian,但我忘记设置I2C频率,但没有出现鬼影。 好的,我不在总线上使用microkontroller,仅在MEMS和GPIO扩展器上使用了,但是我觉得Raspbian的i2c代码中有一种解决方法。 此外,我认为检测到的泄漏来自不完善的升级,我使用的是同一张卡,没有检测到泄漏。

@ hmf2015此问题与一个非常特定的I2C问题有关。 SD卡问题不是由此I2C问题引起的。 如果您的SD卡无法正常工作,则应尝试使用新的SD卡。 有些卡性能不好,并且会很快停止工作。 我的SD卡上个月停止工作,因此我不得不更换它。

通常,I2C幻影不是因为这个问题。 之所以经常发生是因为:

  • 您的电源不好。 我喜欢这个
  • 您的电缆太长。 I2C不能用于长度超过1m的电缆。
  • 您的电缆具有电容耦合。 如果将I2C引脚(SCL和SDA)绞在一起,则可能会出现问题。 有时,人们使用双绞线电缆(如以太网电缆)绞合I2C引脚,这会造成问题。 如果必须使用双绞线电缆,则将SCL与Vss(接地)绞合,将SDA与Vdd(3.3V)绞合。 请参阅7.5节中
  • 您的I2C设备具有5V。 Raspberry Pi在3.3V电压下执行I / O。 如果电压不同,可能会造成问题。 (BNO055需要3.3V,因此,如果将其与5V一起使用,则会出现问题。)

我说过我们正在谈论一个特定的问题。 由于此问题,某些设备可能会产生幻影,但设备数量不多。 如果设备由于此问题而导致重影,则它们不会产生很多重影。 我认为您的问题有所不同。

我不知道您说“注意到SD卡上的泄漏”的意思。 这是一个重要的问题,但这不是我们在此网页问题中讨论的问题。 这次谈话是关于一个特定的错误。 该错误不会影响SD卡。

我不认为最近的Raspbian会改变I2C的工作方式。 我们认为Raspbian无法修复此错误。 我们可能是错的。 谢谢您告诉我们这件事。

如果您只是告诉我们这些信息以帮助我们,那么我们谢谢您。 如果您告诉我们此信息以寻求帮助,则可能需要在Raspberry Pi论坛上进行询问。 论坛讨论了很多东西,例如I2C,SD卡,GPIO扩展器以及更多东西。 您所看到的事物可能与我们正在谈论的事物相同,但可能是不同的事物。 论坛中的人员可以帮助您了解所遇到的问题。

感谢您告诉我们这些信息!

感谢您的回答,但是sd卡问题是由操作系统产生的,我检查了我的(Unix)主机上的卡,还可以,现在在新安装后,同一cad可以正常工作。
I2C总线上的鬼魂会以更高的频率消失,现在在重新安装后它们不再出现,我认为可以排除R / C问题和思考。 我知道3.3V的问题,但最低1电平要小一些。
BNO055封装具有一个稳压器。
我还认为I2C问题会和以前一样,但是现在我没有时间(也没有兴趣)研究Raspbian的源代码来检测差异,所以我对此并不感兴趣。在工作环境中。
元素列表仅应显示,我在BCM支持的Andoid环境(使用真正的Unix)中工作,而不是微控制器,因为我很懒,因此我不是通过串行线或USB连接的。 在您的环境中,情况比我的受到的限制更大,因此我不能说您的问题是否减少了,但我希望。

嗨hmf2015,
这不是论坛。 这是一个错误跟踪器。 此评论列表讨论了与您的问题无关的错误。 请与适当的论坛或服务台讨论您的问题。 再次感谢您提出的问题:“也许是相同的?也许我的描述有助于解决该错误?” 但现在我们可以确定您所看到的与您无关,请不要进一步“污染”此讨论。

@popcornmix
嗨,很久以前,您提到过I2C状态机在重新启动时出现问题,并发布了一些与此问题有关的代码。
我不确定您的意思,但是连接到I2C的WM8731编解码器出现问题。
2-3次重启后,I2C总线完全挂断。 i1cdetect除了第一行外不显示任何信息,并且也挂断电话。 恢复的唯一方法是断电/上电循环。
这看起来像您提到的问题吗?
我正在使用4.19 mainine内核。

@ sergey-suloev如果i2cdetect在8个或16个地址后没有继续扫描,我会说这与此问题无关。 当设备进行时钟延长以指示它们尚未为下一个时钟周期做好准备时,该问题就会弹出。 在将近40年前设计I2C时,这对于硬件实现也是可以想象的。 但是如今,硬件始终准备就绪,可以处理下一个时钟周期,因为对于以硬件实现的某些事物而言,其时间已达到10微秒。

此页面是否有帮助?
0 / 5 - 0 等级