Linux: I2CBroadcomのバグ回避策。

作成日 2013年03月20日  ·  73コメント  ·  ソース: raspberrypi/linux

Broadcom BCM2835には、I2Cモジュールに(ハードウェア)バグがあります。

BCMは「クロックストレッチ」を悪い方法で実装します。

BCMは、クロックの最小「ハイタイム」を確保する代わりに、I2Cクロックを内部で実行し、クロックを再度反転するときに、クロックがハイになっているかどうかをチェックし、ローになっている場合は「クロックストレッチ」を行います。 ただし、このチェックの数ナノ秒前にスレーブがクロック信号を解放して、新しいクロックの準備ができていることを示す場合、クロックパルスは40nsまで短くなる可能性があります。 (これは私が測定できる最低値であり、もちろんそれは非常にまれです)。 100kHz(10マイクロ秒)のI2Cクロックでは、クロックを解放するための「悪い」瞬間は5マイクロ秒離れています。

私のスレーブは少なくとも500nsのクロックパルスを必要とします。 (これは、マスターが100kHz動作用に構成されている場合に生成するものよりも10分の1短いはずです)。

これはハードウェアのバグであり、現時点ではあまり実行できません。 (ハードウェア担当者へのヒント:この方法でクロックストレッチを実装する代わりに:クロックがローのままである間はCLOCKDIVカウンターのカウントを禁止します。これにより、サイクルごとにいくつかの高速クロックがクロックストレッチされますが、標準への準拠は大幅に向上します。 )。

これが発生すると、BCMは非常に短い最初のクロックパルスでバイトを送信します。 スレーブは最初のクロックパルスを認識しないため、そのバイトの終わりでそのバイトをACKする時間になると、スレーブはまだ8番目のビットを待機しています。 BCMはこれを「NAK」として解釈し、I2C転送を中止します。 ただし、その時点で、スレーブは8番目のクロックパルスを確認し、「ACK」を発行します(SDAラインをローにプルします)。 これは、BCMが次の転送に対して適切な「START」条件を発行できないことを意味します。

このハードウェアバグの影響を軽減するための推奨ソフトウェア回避策:バイトの「NAK」が原因で転送が中止された場合は、STOPの前に1クロックサイクル余分に発行してスレーブを同期します。 これはおそらくソフトウェアで行う必要があります。

これは、スレーブがバイトをACKしない場合にのみ「エラーパス」で発生します。 転送の最初のバイトではバグが発生しないため、転送の最初のバイトではない場合にのみこれを行うのが最善かもしれません。

このソフトウェア修正はドライバーに属しますか? はい。 これは、バグのあるハードウェアのドライバーです。 このバグのあるハードウェアを可能な限り最高の状態で動作させることは、ドライバーの義務です。

Bug

最も参考になるコメント

こんにちはhmf2015、
これはフォーラムではありません。 これはバグトラッカーです。 このコメントリストでは、問題とは関係のないバグについて説明しています。 適切なフォーラムまたはヘルプデスクと問題について話し合ってください。 繰り返しになりますが、「同じかもしれませんか?私の説明がそのバグの解決に役立つかもしれません」という質問に感謝します。 しかし、あなたが見ているものは無関係であることが確実にわかったので、この議論をこれ以上「汚染」しないでください。

全てのコメント73件

ドライバーの回避策によって大多数のユーザーにとってより適切に機能する場合は、ドライバーを含める必要があります。
適切なパッチはありますか?

いいえ、まだです。

1)I2Cドライバーについてはまだ詳しく説明していません。 一年ほど前、自分で書くつもりだったのですが、なかなか他の人が書いていました。 したがって、このドライバーをすでに知っている人は、5分間のプロジェクトとしてこれを実行するための準備が整っている可能性があります。 ドライバーを知るには少なくとも数時間かかります。
2)修正/回避策が必要であることにあなた(そしておそらく他の人)が同意する場合は、最初にそれについて話し合うことは有益です。
3)これを「やること」として文書化したかっただけです。忘れてはいけません。
4)誰かが別の回避策を提案するかもしれません。

回避策について話す:回避策は、新しいトランザクションを開始しようとしているときにSDAラインがまだ低いことによってもトリガーされる可能性があります。 それは明らかに「問題」の状況です。

「うまくいかない」ケースは、「通常の」ケースではまれな場合があります。 多くの人がI2Cバスにハードウェアi2cモジュールを持っています。 I2Cが発明された当時、「10us」は一部のチップが要求を処理するための「非常に短い」時間枠であった可能性があるため、クロックストレッチが必要でした。 今日では、ハードウェアI2Cの実装は、「高速I2C」をさらに高速に処理できるはずです。

これは、atmelの連中が非同期モジュールを実装した方法と組み合わされています。 モジュールを外部から提供されたクロック(i2c-slaveまたはSPI-slave)で実行する代わりに、モジュールは引き続きプロセッサクロックで実行されます。 また、すべての着信信号を一連のフリップフロップに通して同期させます。 優れたハードウェア設計。 別の方法はIMHOの方が優れています。モジュールを外部クロックから実行し、データが他の(cpu-)クロックドメインに渡されたときに同期します。 これにより、たとえば、CPUが8でしか動作しない場合でも、SPIモジュールは20MHzで機能できます。

とにかく。 十分なハードウェアのとりとめ。

推奨される回避策:トランザクションの開始時にSDAラインがまだ低い場合は、追加のクロックサイクルを発行します。 (「開始」条件を発行できるようにするには、最初は高くする必要があります)。

まず、I2Cについてはほとんど知りません。 回避策についてGertなどに話しました。

I2Cには次の2つの問題があります。

  1. あなたが説明した時計の伸びの問題
  2. 再起動時のI2Cステートマシンの問題

1の場合、Gertの見解では、絶対確実な回避策はありません。
I2Cスレーブがクロックストレッチをサポートしていない場合は問題ありません。
I2Cクロックが制限された量だけ伸びる場合は、I2Cクロック周波数を下げると問題を回避できます。
前のケースに該当しないスレーブ用のビットバンギングドライバーに切り替えることは、安全な回避策です。

あなたの提案がうまくいくかどうかはわかりません。 それが問題を軽減するのか、それとも完全に修正するのかを知りたいと思います。

ガートは、彼が試みて解放されるバグの説明を持っていると言います。

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;
}      

人々がこの問題にぶつかっているかどうかはわかりませんが、貼り付けたものが役立つかもしれません。

このハードウェアのバグを完全に根絶することはできません。

それが発生すると、マスターとスレーブはクロックサイクル数について意見が一致しません。 したがって、スレーブによって解釈されるデータと、意図するマスター(=ラズベリーパイ=ドライバー/アプリケーション)としてのデータは異なります。 レジスタのどこかに完全に偽の値を書き込んでいる可能性があります。 非常に迷惑です。

私が提案した回避策は、少なくとも次のトランザクションを機能させるでしょう。 影響は半分になります。2つではなく1つのトランザクションのみが失敗しました。 それは問題を解決しません。

I2Cスレーブがクロックストレッチをサポートしていない場合は問題ありません。

I2Cスレーブがクロックストレッチを必要としない場合...

I2Cクロックが制限された量だけ伸びる場合は、I2Cクロック周波数を下げると問題を回避できます。

はい。 1つの場所に「フィールド」に10台のデバイスがあります。 明らかに、3つのモジュールのクロック周波数(RCクロック)は、クロックが正確に間違った瞬間に伸びて「完了」するという点で異なります。 クロック周波数を下げると、これらのモジュールの問題が修正されました。

クロックストレッチ遅延が固定されていないが、たとえば5マイクロ秒を超えて変動する場合、問題が発生する可能性は多かれ少なかれ統計的にあります。 私の場合、スレーブには0.25マイクロ秒のクロック幅が必要です。 したがって、クロックストレッチは、BCMのクロック変更の瞬間に至るまでの時間の5%で終了し、その後、問題が発生します。 したがって、この場合、20回に1回の転送が失敗します。 (スペックでは、クロックパルスの最小250nsと言われています。実際、それが短い場合に表示されないという意味ではありません。表示される可能性は、> 250nsの100%から<< 125ns。)

私は昨日、5マイクロ秒の機会のウィンドウで2.5マイクロ秒のマークの周りに収まるように時計のストレッチ期間をストレッチすることに費やしました。 ウィンドウの開始を目指して、RCクロックが少し速く実行される場合、バグをトリガーする「0」を押します。 5を目指すなら同じこと。 だから今、私は悪い場所から離れて、真ん中を目指しています。 しかし、I2Cクロックを80kHzに変更し、BAM、私は敏感なスポットを正しく目指しています...(80kHzで発生しない場合は、80〜100の値で発生します)。

GertによるI2Cバグの説明は次のとおりです。
https://dl.dropbox.com/u/3669512/2835_I2C%20interface.pdf

ハハ! 私はテストボードをまったく同じ方法で計測しました。 SCLトレースを切り取り、そこに0.1インチのジャンパーコネクタを取り付けました。測定していない間は、通常のジャンパー、または100オームの抵抗を備えたメスコネクタがあります。

私はそれが最初の時計でのみ起こるとは思いません。 つまり、(ほとんどのハードウェアI2Cチップがおそらく行うように)クロックストレッチをまったく行わないか、クロックストレッチを少なくとも1サイクル持続させることで、問題を回避できるということです。

クロックストレッチを0.5マイクロ秒刻みで変化させることができるようにi2cスレーブコードを計測しました。 I2Cを介してクロックストレッチをXXXに変更するように命令できます。その後、デフォルト値に戻す前に、50ミリ秒の間そのように機能します。 (機能しない場合は、再度機能させる必要があります。このようにして、ロジックアナライザーでSDAおよびSCLラインを監視しながら、これらの設定の値の全範囲をすばやくスキャンできます。「use delay XXX」を送信してから、スティングの送信には25ミリ秒かかります。スクリプト内のカウンターをインクリメントして「次の遅延」を送信すると、シェルスクリプトに約100ミリ秒かかります。したがって、約10秒で100個の可能な値をスキャンできます。

私はバグがより長い遅延で起こっているのを見たことがあります。 したがって、「最初にのみ発生する」という理論は正しくありません。

「超効率的な」割り込みハンドラについて:はい、私もそうすることができます。 重要なのは、クロックストレッチ機能により、「このバイトを処理する」コードを割り込みルーチンに入れることができ、数マイクロ秒または数ミリ秒かかることを心配する必要がないということです。 理論的には、クロックストレッチにより、マスターは次のバイトに進む前に、このバイトの処理が完了するのをマスターが待機するようになります。 その計画は2835年のバグで完全に破壊されました。私は今、クロックストレッチを停止させ、その後70マイクロ秒でバイトの処理を終了したいと思っています。

クロックストレッチを解放するには、5マイクロ秒の半クロックの中央を目指すために「サイクルカウント」する必要があります。 開始を目指す場合(4.9マイクロ秒のクロック高周期を発生させるため)、スレーブのクロックが数パーセント速く実行され、バグが半サイクル早くトリガーされる可能性があります。 したがって、半クロックサイクルの両端は危険です。短いが、十分に有効なクロックサイクルを目指す必要があります。

モジュールの変更は非常に簡単です。SCLが「ハイに駆動」されている(つまり、まったく駆動されていない)場合は、I2Cモジュールのマスタークロックを停止します。 これには、バス容量が仕様を超えると自動クロックストレッチが発生するため、はるかに長いI2Cバスが許可されるという副作用があります。

これ: httphttp//news.gmane.org/gmane.linux.kernel.rpiが役に立ちますか?

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で制御しようとしているプロジェクトがあります。正直言って、あきらめてビーグルボードに切り替えるか、PiにSPI経由でFPGAと通信させてI2C処理を実行するところです。 。

私はそれを行うことができるはずのメールにボードを持っています(配達予定:明日)。 SPIコネクタ、I2Cコネクタ。 そのボードで試してみるのはいいプロジェクトでしょう。 情報を入手したい場合は、私にメールを送ってください。

現在の状況:スレーブがATMEGAの場合、「最初のサイクルのみが失敗する可能性がある」というGertの動作と互換性のある動作が見られます。また、スレーブが私のATTINYの1つである場合、バグが完全に発生しています。

テストした遅延は次のとおりです。
i2c_delays_atmega
このテストセッション中に観察された最短のSCLパルスは4.5マイクロ秒でした。

attinyスレーブでテストしているところ、ACKのテスト済み遅延は次のとおりです。
i2c_delays_attiny

最小パルス幅は41ns(私の測定分解能)です:
i2c_delays_attiny2

ああ。 それを見つけた! バイトのACKの前のクロックストレッチは「危険」であるように見えますが、ACK後のクロックストレッチは問題ありません。

私と他の人は確かに繰り返し開始の問題にぶつかっています。 http://cpansearch.perl.org/src/MDOOTSON/HiPi-0.26/BCM2835.xsのprochipi_i2c_read_register_rsでユーザースペースハックがあり

カーネルにI2Cハードウェアを無視させ、同じピンでビットバンギングされたGPIOベースのI2Cを使用させることはできませんか? そのためのオーバーヘッドは、ハードウェア自体のバグよりも許容できると思います。

どのようなオーバーヘッドが予想されますか? 現在のドライバーのデフォルトは100kHzクロックです。 したがって、i2cインターシャルセンサーから10バイトを読み取るには約1msかかります。 ビットバンを実行すると、CPUサイクルが常にかき回される可能性があります。

私の好みは、ドライバーがモジュールパラメーター(またはそれがより便利な場合は別のモジュール)を介してオプションでビットバンギングi2cをサポートすることです。

多くのデバイスはクロックストレッチを使用しないため(または制限された量のクロックストレッチを使用するため、低速で正しく動作できます)、そのような場合でもハードウェアI2Cドライバーの方が適しています。

カーネル自体には、GPIOピン上のビットバンギングI2C用のドライバーがあり、このドライバーは、ユーザースペースからのビットバンギングよりもはるかに低いオーバーヘッドであり、ハードウェアI2Cドライバーと同じAPIを公開します。 私の提案は、そのドライバーとハードウェアI2Cドライバーの両方をモジュールとしてコンパイルしてから、デフォルトでハードウェアドライバーをロードすることです。

@フェロイン
PiでビットバンのI2Cドライバーを使用していますか?
それを構築するためにどの.configオプションを追加しましたか? ソースパッチはありますか?
使用するドライバーを選択するにはどうしますか(modprobe?異なる/ dev /デバイス?)

Piでドライバーを使用したことはありませんが、BeagleBoardで正常に使用している友人がいます。
構成オプションはI2C_GPIOです。
それとbroadcomドライバーの両方がモジュールとして構成されている場合、ドライバーの選択はカーネルモジュールをロードするのと同じくらい簡単です。
GPIOモジュールには、SDAおよびSCLとして使用するGPIOを指定するためのパラメーターが必要です。パラメーターが何であるかはわかりませんが、dirvers / i2c / busses /i2c-gpio.cの十分に文書化されていないソースに基づいています。適切なパラメータは 'sda = X scl = Y'のようです。ここで、XとYは使用するピンです。

i2c-gpioモジュール自体は、パラメーターをモジュールに渡す方法を提供していません。 したがって、プラットフォームデータを登録し、少なくともバス番号、SDA、およびSCLピンを構成する別のモジュールが必要です。 私はそのようなモジュールの概念実証を書き、ピン0と1でも機能しましたが、i2c-bcm2708がロードされていませんでした(pcf8574はi2cdetectによって検出され、gpio-pcf857xモジュールでいくつかのLEDを駆動できました)。 しかし、ピンを変更するときにpcf8574を焼いたので(現在、他のi2cチップはありません)、実際にテストすることはできませんでした。 これがコードです

@kadamsi
sda_pin / scl_pinモジュールパラメータを作成すると便利な場合があります。 プルリクエストと同じように。
誰かがこれが彼らのために働くことを確認できますか?

これは見た目ほど簡単ではありません。プラットフォームデータ構造がずっと渡されることを期待しています。

一方、プラットフォームは、今日使用するGPIOを指示しないため、変更する作業を行うことは合理的に聞こえます。 (通常、プラットフォームデータは「/ this /コンピューターの配線方法」を指定します。)

@popcornmix
設定可能にする予定ですが、昨日は時間が足りませんでした。 また、一度に複数のバスを作成できるようにしたいと思います。 たぶん、GPIOS exportunexport sysfsファイルのように動的な方法で(しかし、そのようなバスをきれいにアンエクスポートできるかどうかはわかりません)? ああ、私は別のpcf8574を見つけ、外部プルアップ抵抗を使用した場合、さまざまなGPIOピンでもうまく機能することを確認できました。 残念ながら、テストするためのより洗練されたI²Cデバイスはありません。 それで、デフォルトのカーネルツリーでそのようなモジュールを提供することに興味がありますか?

@kadamski
このようなモジュールをテストするためのセットアップがありません。 ただし、チップが提供するハードウェア機能(I2Cなど)には、より多くの人が使用できるようにカーネルドライバーが必要です。 I2Cハードウェアに特定の周辺機器の使用を妨げるバグがある場合、ちょっとした代替手段は価値があるように聞こえます。

したがって、使用していない人には無害に見える(つまり、モジュールとして構築され、ロードされるまで何もしない)新しいドライバーを作成し、それが正しく機能しているという証拠(つまり、ユーザーレポートの確認)がある場合、私はPRを受け入れてうれしいです。

HWはBCM2837(RPi 3)で修正されていますか?

私の推測は:いいえ。 しかし、今日はおそらくこれをテストする時間がありません。

BCM2837I2Cは変更されていません。

それは残念ですが、情報をありがとう。

それは非常に迷惑です。

同意する。 問題がまだ存在することを示すBCM2837エラッタまたは同様のリンクを持っている人はいますか? ニュースを伝えなければならないときに便利でしょう。 または@ P33M 、Broadcomで働いている場合、おそらくあなたは権威あると引用することができますか?

彼は権威がありますが、Broadcomでは機能しません。

それは良い。 しかし、私はすでにグーグルで検索していて、P33Mが他の場所でM33Pであることを除けば、私が便利に渡すことができるIDを見つけるのに苦労しています。 これは問題ありませんが、彼は引用するのに最適な情報源ではないことを意味します。 :-)したがって、エラッタリンクは便利です。

@ P33MはRaspberryPiで動作します。 あなたは彼の言うことを権威あるものとして扱うことができます。

正誤表はないと思いますが、おそらくあるはずです。 私は彼を残しました
彼の身元を確認するかどうか!

14:30 2016年3月15日、RalphCorderoy [email protected]書きました:

それは良い。 しかし、私はすでにグーグルで検索しており、P33MがM33Pであることは別として
他の場所では、私が便利に渡すことができるIDを見つけるのに苦労しています。 どちらでもいいです
しかし、彼は引用するのに最適な情報源ではないことを意味します。 :-)したがって、エラッタリンクは
ハンディ。


あなたがコメントしたのであなたはこれを受け取っています。
このメールに直接返信するか、GitHubで表示してください。
https://github.com/raspberrypi/linux/issues/254#issuecomment -196845789

@RalphCorderoy私はRaspberryPi(trading)Ltdの従業員です。私の答えは信頼できます。

@ P33M 、Ta、

これは私が取り組んでいるプロジェクトに影響を与えています。 幸い、スレーブデバイスのファームウェアを完全に制御でき、応答に半周期の遅延(クロックストレッチ)を追加するという回避策を追加して、不正な動作をスキップすることができました。

問題の適切な分析はadvamation.comで見つけることができます。

BroadcomのI2C実装でこれは悪いハードウェアですか、それともハードウェアを正しく動作させるためにカーネルを微調整することは可能ですか?

私が開発している製品でもこれに遭遇したので、私はこの問題を購読しました
AVRとPiの間でi2cを使用します。 今、私はそれを再考する必要があります。
信頼できる形式のi2cビットバンギングを使用した人はいますか?

@ mwilliams03このプロジェクトに興味があるかもしれません。

特に、ここにI2Cの問題に関する情報があります。 また、AVRのTWIモジュールには、クイック読み取りを妨げる問題があることにも注意してください。

おかげで@ pdg137 、私はそれを試してみました、そして最初に私はエラーなしで120万の読み取りを得て、それでも続けています。

@rewolffは、この問題が解決されたようです。 その場合は、この問題を閉じてください。

そして今....レベルシフターと40cmの延長ケーブルを追加します..それで動作しますか? これにより、波形の「上」側で十分な遅延が発生する可能性があり、突然、バグが再び発生します。

私の知る限り、broadcomと従業員は、このバグはバイトの最後のビットの後の最初の5マイクロ秒(実際には30分)に制限されていると考えています。 次に、10マイクロ秒を追加するだけで、さらに2つの半時計に物事が持ち越され、問題はないはずです。 私のテストでは、5マイクロ秒ごとに時計が伸びるのを止める「悪い」瞬間を見つけました。

SPIとI2Cの対称性により、次のデータバイトが「次のデータ」割り込みで「計算」されると、AVRコードで簡単になります。...(読み取りを継続できるインターフェイスを公開しているため、16バイトのバッファー必ずしも十分ではありません。)

私は確信していません。

RespberryPiとATMEGA324PAの間でSMBusの問題が発生しています-これらはこの問題に関連している可能性がありますか? https://stackoverflow.com/questions/39274784/talking-smbus-between-raspberr-pi-and-atmega-324pa-avr-not-clock-stretching

私の知る限り、broadcomと従業員は、このバグはバイトの最後のビットの後の最初の5マイクロ秒(実際には30分)に制限されていると考えています。

@rewolff :Broadcomの従業員に同意する必要があります。 私のテストでは、Raspberry Pi3と100kHz I2C(CPUがスロットルされると62 kHzに減速します)を使用すると、 advamation.com

アニメーションは健全なようです。 しかし、それは私の経験と一致していません。 たぶん私はテストを設定する必要があります。 しばらく時間がかかる場合があります。 それは他のもので忙しいです。

しかし、これが当てはまる場合、割り込みルーチンの「usleep(10)」(ハードウェアクロックストレッチを使用)は通常、トリックを実行し、物事がロックされないようにします。 私はこれが事実ではなかったとかなり確信しています。 :-(

@rewolff :Raspberry Pi 3で、CPUが600 MHzにスロットルされ、デフォルトのI2C速度が

@kadamskiのi2c-gpio-paramモジュールをRaspberryPiカーネルに含めることは可能でしょうか? このアプローチは私のアプリケーション(AVRソフトウェアI2Cスレーブ)では非常にうまく機能しているようであり、ラズベリーカーネルに必要なヘッダーをインストールするのはやや面倒なので、利用できるようにしておくと便利です。

また、この問題全体の根底にあるHWバグに対処するための良い回避策にもなります。

@onnokort 2015年11月以降、現在のカーネルに存在するi2c-gpioオーバーレイのような意味ですか? https://github.com/raspberrypi/linux/blob/rpi-4.4.y/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
オーバーレイのREADMEから:

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これを閉じることはできますか? かなりの時間が経ちましたが、私の読書からのdtparamのものはまともなオプションのようです。

I2Cハードウェアで確実にうまく機能しないデバイスに推奨される回避策は、ピンをビットバッシュするi2c-gpioオーバーレイを使用することです。

それ以外の場合、アドレスACKフェーズでのクロックストレッチはアップストリームドライバによってサポートされます。

さらに2セント: https

親愛なる皆さん、今日、私は東アジアのパッケージGY-955のBNO055をテストしました。これは、Pi 2B(BMC2835)を​​使用して100_000Hzで非常に醜い動作をします。 テストでは、I2Cバスの周波数を50_000から400_000 Hzに変更し、100_000 Hzで問題が見つかりましたが、50_000、85_000、115_000、125_000Hzの場合、Adafruit(Adafruit_Python_BNO055)のコードはI2C接続150_000で問題なく動作します。 HzはBNO055には速すぎるようです。動作しますが、値が間違っている場合があります。 告白します。オシロスコープで周波数をテストしませんでした。ファイル/ sys / class / i2c-adapter / i2c-1 / of_node / clock-frequencyを読み取っただけなので、不確実性が残っています。 ここで、ADAでBNO055への完全なインターフェイスの実装を開始します。
Facit:BMC I2C処理のハードウェアバグは100_000Hzでのみ発生するため、確認する必要があります。

参考までに、ハードウェアのバグは、スレーブデバイスがクロックストレッチを実行し、0.9〜0.999I2Cクロック周期の後にSCLラインを解放するときに発生します。 ラインが上昇し始め、piハードウェアは次のように言います。ああ、彼はクロックストレッチをしなかったので、クロックラインを再びローに引くことで次のクロックパルスを提供できます。

このバグは、クロック周期の残り時間が、clkラインがラズベリーの「HIGH」しきい値を通過するのに十分であるが、スレーブデバイスの場合は通過しない場合、またはスレーブにノイズフィルタリングがあり、<x%の間にハイと見なされる場合に発生します。通常のI2Cクロックサイクルはグリッチです。

これは「100kHzでのみ発生する」だけでなく、スレーブデバイスの応答時間が異なる値である必要があることを除いて、他の多くの周波数でも発生します。

クロックが100kHzであるとすると、通常のサイクルは5usの高さと5usの低さになります。 ここで、t = 0で、piがクロックラインをローに引き下げることによって最後のクロックサイクルを開始するとします。 t = 5usで、piはクロック信号を解放しますが、スレーブはまだビジーであり、クロックをローに保ちます。 t = 9usでスレーブが完了し、クロック信号を解放します。 t = 10usで、piはクロック信号を見て、次のように考えます。OK、クロックストレッチがないので、続行すると、クロック信号が再びローになります。 クロック信号は1usの間だけハイになり(静電容量とプルアップ抵抗の時定数のために少し少なくなります)、スレーブには見えない可能性があります。 これで、9マイクロ秒後ではなく、10.5秒後に別のデバイスの準備が整います。 100kHzで、piは「まだ低い、クロックストレッチ、さらに5マイクロ秒待ちます。4.5マイクロ秒のクロックパルスを取得し、動作します。しかし、このデバイスを90kHzで実行すると、問題が発生します。 piは開始から11マイクロ秒を調べ、クロック信号は1マイクロ秒未満の間ハイになっています->問題。

これについて不平を言う人は、それらの他のデバイスを持っている人ではありません。 これらはデフォルトの100kHzで動作します。 しかし、バグはまだ非常に現実的であり、あなたと私が持っているデバイス以外のバス速度でそれらのデバイスで発生するでしょう。

応答をありがとう、それは私が選んだ周波数で信頼できる転送を得た理由を非常によく説明しています:
100_000 Hzでは、9〜9.99 µsecの期間で問題が発生します
85_000 Hzでは、問題は1_000_000 / 85_000 * .9 = 10,59 µsec> 9.99秒で始まります。したがって、クロックストレッチは無視されます。85_000Hz未満のすべての周波数では、問題の開始点は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の情報を読みました。
ピリオドの.9ではなく.5が記録されました)。

上手。 これは、スレーブが有効なクロック信号として何を検出するかによって異なります。 そして、バスのRCがどれだけの遅延をもたらすか。 私の場合、スレーブとして使用するAVRは、2クロックサイクル未満のパルスをグリッチと見なします。 8MHz(+/- 10%!!!)の内部RCクロックでは、パルスを検出するには少なくとも250nsである必要があります。 I2C仕様には5マイクロ秒が必要であるため、公式に必要なものと機能しなくなったものの間には20倍の「マージン」があります。

最初は、スレーブのクロックストレッチを増やして12usと言うと少し生成すると思いました。 これは、バス容量が問題を再び引き起こすのに十分な遅延を追加するまで機能します。 したがって、回避することは非常に困難です。 標準の100kHzi2cを使用しないようにクライアントに指示する必要があるのは面倒です。

申し訳ありませんが、完全な実装とテストのシナリオを作成するには時間がかかりました。
あなたが私に与えてくれたすべての情報に感謝します、それは非常に役に立ちました。
私のテストシナリオは、2つのMEMS(GY-055としてパッケージ化されたBNO055、MPU-9250 / 6500としてパッケージ化されたMPU9255、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を読み取ることで確認されました。
私のコードは、MEMSからのデータの読み取りとPCFのデータの書き込みを0.1秒の遅延で100回実行します。
結果:

  • MEMSの初期化は成功しました。
  • I2Cバスを介したMEMSデータからの読み取りは、すべてのサイクルで成功しました。
  • I2Cバスを介したPCFへのデータの書き込みは、すべてのサイクルで成功しました。

したがって、MEMSとPCFは、標準の100kHzよりも高いクロックを受け入れます。
古い環境では、AVRへの通信はシリアル回線を介して行われます。2番目の環境では、通信はUSB経由で行われますが、完了していません。実際には、BNO055が原因で発生したI2Cバスの問題につまずいたと思います。私の環境では、Pi 2bの回避策を見つけましたが、Pi3でも機能することを願っています。これが次のテストです。 次に、他の2つのMEMS、1つのVL53L0Xと1つのBME280を統合する必要があります。新しい周波数で動作し、バス容量がこれらすべての要素を受け入れることを願っています。

現在、RPi3モデルB +でこの問題を処理していますが、Advamationの記事で説明されているものとは異なる結果が表示されます。 シリコンは最近復活していませんでしたね。

短いバージョンでは、read-preACK、write-preACK、またはwrite-postACKでストレッチするとうまくいくようです。 長く伸ばすか、まったく伸ばさないようにする必要があるのは、read-postACKだけです。 ただし、確かなことを言う前に、実験をクリーンアップする必要があります。

まず、用語についてのメモ。 Advamationの記事には次のように書かれています。

したがって、Raspberry Piを使用したI2Cは、次の場合にのみ機能します。
スレーブがクロックストレッチをまったく使用していない、または
スレーブは、I2C-read-ACKフェーズの最後/直後(ACK / NACKの読み取り後)にのみクロックをストレッチしますが、その後0.5クロック周期を超えます。

「I2C-read-ACK-phase」という用語はやや曖昧に見えます。 I2C読み取りコマンドの場合(つまり、ポストアドレスR /W̅ビットが設定されている場合)、スレーブは括弧とは逆に、A̅C̅K̅ビットを読み取らずに書き込みます。 ここで「read-postACK」と言うときは、R /W̅ビットがアドレスの直後に設定されている(おそらくSMBusのようにプロトコルによって変更されていない)ため、スレーブはA̅C̅K̅応答を書き込んだばかりです。

このあたりで示唆されているように、RPiがSCLがスレーブによってローに保持されていることを検出すると、内部SCLクロックを半サイクル(5μS)遅らせるようです。 このバグは、スレーブがほぼ半サイクルの間SCLをローに保持した場合にトリガーされます。 それが発生した場合でも、RPiはSCLをHighに設定し、その後すぐにSCLクロックがトリガーされたときにSCLをプルダウンします。 これにより、ラントクロックパルスが発生します。これは、一部のデバイスではパルスとして認識され、他のデバイスでは認識されない場合があります。 (参考: I2C仕様は、5μSの公称SCLハイタイムを意味し、RPiのI2Cインターフェイスのデフォルト速度である100kHzで4.0μSの最小時間を確立します。)

私の実験では、read-preACK、write-preACK、およびwrite-postACKフェーズで、RPiは許容される最大SCLハイタイムが4μS程度であることを保証します。 これらのフェーズでは、SCLクロックを押し戻すことをいとわないようでした。 RPiはSCLラインをリリースした直後にサンプリングし、SCLがまだ低い場合は、SCLクロックを半位相戻したと思われます。

ただし、read-postACKフェーズでは、SCLラインが約6〜9μSの間ローに保持されている場合、RPiがラントクロック(<4μS、多くの場合2μS以下)を放出することがわかりました。 このフェーズでは、Broadcomのエンジニアは別の道をたどり、大容量のラインで半フェーズを遅らせる必要がなくなる可能性を低くしようとしているのではないかと思います。 悲しいことに、これまで見てきたように、それは不十分です。

したがって、私の現在のコードは、読み取りのread-postACKフェーズ(ADC変換など)で1/2サイクルを超えてSCLを拡張する必要があります。 私が失敗した場合

私が実行している現在のテストでは、PIC16F1619をスレーブデバイスとして使用しています。 スレーブデバイスはループを使用して、プリACKとポストACKの両方の読み取りコマンドと書き込みコマンドの両方でクロックをストレッチします。 このループとオーバーヘッドの長さは、3μS(RPiがSCLをローに保持する時間未満)から0.35μS刻みで90μSまで変化します。 RPiにPythonプログラムがあり、2つのレジスタの値が異なり、それらを読み戻し、読み戻し値が正しいことを表明します。 使用されている値

ピクアン、
Broadcomは、この問題は最初のクロックストレッチでのみ発生すると宣言することで、これを軽視してきました。 そうではないと思います。 あなたはそれを確認することができるはずです。 Advamationはbroadcomの声明に従っているようです。

@rewolffまあ、彼らの解釈には何かがあるかもしれません。 「最初のクロックストレッチ」とは、「特定のステージで、SCLが複数のクロック変換によってストレッチされるのは初めて」を意味する場合、その説明は正確です。複数のクロックサイクルでストレッチする場合は、そうです。フェーズでは、0.5サイクル以上ストレッチすると、良好な状態になります。 少なくとも、私がこれまでに行った漠然とした実験では、 より正確な実験はまだ来ていません。

RPiのI2Cがクロックストレッチを処理できる場合とできない場合を示し、BCMがエンジニアに送信できる再現を取得するために、いくつかのより良い実験を実施できてうれしいです。

悲しいことに、この問題を修正するために必要な非常に重要なシリコン回転があります。 SCLが(内部または外部ソースによって)ローに保持されている場合、SCL分周器クロックを刻む必要はありません。 それにはおそらくシリコンレベルの変更が必要になりますが、これは費用がかかります。 ほとんどのECOは金属レベルです。これは…まあ、安くはありませんが、シリコンよりもはるかに安価です。

ここでの私の主な目標は、いくつかの実験的証拠を使用して、RPiで機能するスレーブと機能しないスレーブのタイプを特徴づけることです。

BroadcomにI2Cコントローラーを再設計するよう説得するには、再現シナリオなど、より堅実なデータが必要なようです。 確かなデータがあっても、エンジニアは、次の改訂のためにシリコンを改訂する価値があることを経営陣に納得させる必要があります。

そうは言っても、BCMエンジニアが問題を明確に確認してテストできるように、再現可能なシナリオの設計に時間をかけます。 ただし、私の調査結果をBroadcomに伝えるには、ここのコミュニティメンバーに依存します。 私は彼らへのチャンネルを持っていません。

シリコンと金属の変更について、コミュニティに対する以前のコメントについて何かを明確にする必要があります。

SparkFunまたはAdafruitからボードを入手した場合、その動作を変更するために切断またははんだ付けできるトレースが含まれていることがよくあります。 ほとんどのI2Cボードには、アドレスを変更したり、プルアップ抵抗を有効または無効にするために変更できるトレースがあります。

マイクロチップの設計者も同じことをします。 マイクロチップの金属層には多くの変更を加えることができるため、シリコン層を変更する必要はありません。 これは、シリコン層の変更は困難で費用がかかるため(ボード上のチップの変更など)、金属層の変更ははるかに簡単です(ボード上のトレースの変更など)。

設計者は先を見越して、チップの動作を変更する金属接続(基本的にはジャンパー)を作成するため、金属層に多くの有用な変更を加えることができます。

しかし、彼らが計画していなかった変更があり、チップ内のトレースを再ルーティングすることによってどのように行うかを理解できない場合、彼らはシリコンを変更する必要があります。 シリコンにはさらに多くの計画、検証、マスキングが必要なため、変更するのは困難です。

多くの企業は、「十分に優れた」シリコン層を持っている場合、可能な限りそれを使用します。 チップの複数のリビジョンでシリコン層の一部を再利用します。

それがBCMの現状だと思います。シリコン層のこの部分を最初から再設計することを正当化する前に、このバグをドライバーや金属で修正できないという十分な証拠が必要です。

この問題を修正するためだけに既存のシリコンが再スピンする可能性はほとんどありません(予備の100万ドルを手に入れましたか?)。 しかし、将来のチップには修正があるかもしれません。

2018年9月5日水曜日02:13:19 AM -0700に、Joel RayHolveckは次のように書いています。

再現シナリオなど、より確実なデータが必要なようです。
BroadcomにI2Cコントローラーを再設計するように説得します。 でもで
確かなデータの場合、エンジニアは経営陣に次のことを納得させる必要があります。
次の改訂のためにシリコンを改訂する価値があります。

彼らはすでに6年と3つのシリコンの改訂を行っています
「修正しない」という彼らの決定を示しました。

0.5サイクル以上伸ばせば、体調は良好です。

そうは思わない。 「直前の」でCLKを離すたびに
Broadcomが再び見える」期間、短いパルスが発生します。簡単にできます
クロック信号のリリースをたとえば5マイクロ秒遅らせて
常に0.5サイクルから外れます。 しかし、それはうまくいきませんでした。

2018年9月5日水曜日02:28:53 AM -0700に、JamesHughesは次のように書いています。

のリスピンが発生する可能性は非常に低いです。
この問題を修正するためだけに既存のシリコン(予備の100万ドルを手に入れましたか?)。 未来
ただし、チップには修正がある可能性があります。

疑わしい。 KNOWNバグのあるBCM2835からBCM2836に移行しました
BCM2837とまったく同じバグでBCM2837と同じバグ。

では、なぜ次の改訂が異なると思いますか?

BCMにはターゲット市場があります:これらのチップ用の電話とTVスティック。 に
彼らのターゲット市場誰もソフトウェアをやっていない-汎用のI2C
AVRやPICなどのマイクロコントローラー。 彼らはこれを修正するつもりはありません。

この調査努力が必要なのは残念ですが、それは素晴らしいことです。 これをカバーするエラッタを以前に尋ねたとき、それはなかったと思いました。 これは変更され、URLがありますか? 理想的には、Broadcomは障害を正確に説明し、障害が発生したときにコミュニティを支援するため、互換性のあるコンポーネントの回避策や評価を自信を持って簡単に行うことができます。 関連するHDLのスニペットの範囲でさえ、それを正確に説明に変換しようとしない場合。

クロックストレッチを許可するときにハーフビットクロック除数を停止するという提案は良いものです。 それはうまくいくでしょう。

それに関する問題は、I2Cモジュールの一部が「フルクロック速度」で実行される必要があるということです。 現在、I2Cモジュールは通常200kHzより速く動作しないため、優れた低電力モジュールです。

私の投稿の主な理由は、元の投稿の冒頭で言ったことです。

現在、RPi3モデルB +でこの問題を処理していますが、Advamationの記事で説明されているものとは異なる結果が表示されます。 シリコンは最近復活していませんでしたね。

2013 Advamationの記事の後にI2Cハードウェアまたはドライバーに大幅な変更があり、コミュニティがそれらがこのバグにどのように影響するかを知っている場合は、実験に適切な変更を加える必要があります。

基本的な問題はハードウェアにあることは知っていますが、私が知っている限りでは、ドライバーの無関係に見えるレジスターを変更すると、実際にこのバグの動作が変わることが実験によってわかったかもしれません。 また、BCM2837がRPi 2と同じI2Cモジュールを備えていることも確認していません(この問題が最初に報告されて以来、I2Cハードウェアが変更されていないことを明確に確認できました)。 また、BCM283xのステッピングに関する情報も見つかりませんでした。 私が知っている限りでは、BCM2836の時代に金属の変化があった可能性があります。

Broadcomをバッシングしたり、将来のリビジョンをどのように変更する可能性があるかを推測したりすることには興味がありません。

ここでの私の主な目標は、現在の動作を明確に文書化することです。 時間の経過とともに変化しているようです。 私には、将来のユーザーが私の実験を再現して結果がまだ有効かどうかを確認したり、改善を行ったり、他の条件をテストしたりできるようにするという副次的な目標があります。 Broadcomのエンジニアが必要に応じてテストを簡単に再現できるようにするという、もう1つの副次的な目標があります。 これらは両方とも、実験を公開する必要があることを意味します。これは、私自身の傲慢さのために、実験を公開する場合、実験をより厳密にするように駆り立てられます。

私の現在の実験計画は、スレーブ実装としてPIC16F1619を使用することです。 クロックストレッチ実験を行うのに十分な速度と汎用性があり、操作が簡単で、他の実験者が私の結果を再現できるほど一般的です。 結果があいまいな場合は、FPGAを使用して実験を作成することもできます。 スレーブとしてビットバッシング構成の別のRaspberryPiを使用して妥当な粒度を取得できるかどうかはわかりますが、リアルタイムテストを実行するには、OS全体がないものが必要になると思います。

出てきた別のいくつかのことに対処するには:

元の投稿が不完全だったことをお詫びします。 誤って初期ドラフトを投稿しました。 私が行った変更はごくわずかなので、そのままにしておきます。

SCLが外部的に低く抑えられている間にクロック除数を停止するという考えに独創性を主張することはありません。 私はそれをどこか別の場所で読んだが、どこか覚えていない。 raspberrypi.orgのI2CクロックストレッチスレッドのGertvan Looからのものだと思いましたが、今は見つからないので、他の場所で見たに違いありません。 電力プロファイルが大幅に変わるとは思いませんが、

I2C HWブロックは、bcm2835 / 6/7で修正/変更されておらず、修正される可能性は低いです。これは、チップの再スピンが必要であり、非常に高価であるためです。

Advamationが誰であるかはわかりませんが、RPF(T)グループには認識されていないため、記事の正確性を保証することはできません。

親愛なる皆さん、私はPi 2Bと3で非常に奇妙な現象を起こしました、私は説明しようとします:
6月末にBNO055の実装を開始したとき、古いRaspbian(現在はバージョンではありません)を使用し、i2cdetectを使用して無効なI2Cアドレスを多数取得しました。 そのために私はネットを調べました、そして私は良い情報でこのフォーラムを見つけました。 そのために、上記のようにI2C周波数を変更すると、すべてのゴーストが消えて作業できるようになります。 8月中旬にRaspbianをraspbi-dev4.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周波数を設定するのを忘れましたが、ゴーストは表示されませんでした。 バスではマイクロコントローラーを使用せず、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仕様を見てください。
  • I2Cデバイスには5Vがあります。 RaspberryPiは3.3VでI / Oを実行します。 電圧が異なると、問題が発生する可能性があります。 (BNO055には3.3Vが必要なので、5Vで使用している場合は、問題が発生します。)

私たちは特定の問題について話していると言いました。 一部のデバイスはこの問題のためにゴーストを作成する可能性がありますが、多くのデバイスはそうではありません。 この問題のためにデバイスがゴーストを作成する場合、デバイスは多くのゴーストを作成しません。 あなたの問題は違うと思います。

「SDカードのリークに気づいた」と言ったらどういう意味かわかりません。 これは重要な問題ですが、このWebページの問題で説明している問題ではありません。 この会話は特定のバグについてです。 そのバグはSDカードには影響しません。

最近のラズビアンがI2Cの動作を変えたとは思いません。 Raspbianではこのバグを修正できないと思います。 私たちは間違っているかもしれません。 これについて教えてくれてありがとう。

あなたが私たちを助けるためにこの情報を私たちに伝えているだけなら、私たちはあなたに感謝します。 この情報を教えて助けを求める場合は、RaspberryPiフォーラムで質問することをお勧めし

この情報を教えてくれてありがとう!

回答ありがとうございますが、SDカードの問題はO / Sによって発生しました。(Unix)ホストでカードを確認しましたが、問題はありませんでした。新しいインストール後も同じCADが機能します。
I2Cバス上のゴーストは、より高い頻度で消え、再インストール後は表示されなくなります。R/ Cの問題と反射は、除外できると思います。 3.3Vの問題は知っていますが、最小の1レベルはそれよりも少ないです。
BNO055パッケージには電圧調整器があります。
また、I2Cの問題は以前と同じだろうと思いましたが、現時点では、Raspbianのソースコードを調べて違いを検出する時間(および関心)がないので、関心があります。作業環境で。
要素のリストは、私が怠惰なのでシリアルラインやUSB経由で接続するマイクロコントローラーではなく、BCMがサポートするAndoid環境(実際のUnixを使用)で作業していることを示すだけです。 あなたの環境では私よりも条件が厳しいので、問題が少なくなるかどうかはわかりませんが、願っています。

こんにちはhmf2015、
これはフォーラムではありません。 これはバグトラッカーです。 このコメントリストでは、問題とは関係のないバグについて説明しています。 適切なフォーラムまたはヘルプデスクと問題について話し合ってください。 繰り返しになりますが、「同じかもしれませんか?私の説明がそのバグの解決に役立つかもしれません」という質問に感謝します。 しかし、あなたが見ているものは無関係であることが確実にわかったので、この議論をこれ以上「汚染」しないでください。

@popcornmix
こんにちは、ずっと前に、再起動中のI2Cステートマシンの問題について言及し、この問題に関するコードを投稿しました。
意味がわかりませんが、I2Cに接続されているWM8731コーデックに問題があります。
2-3の再起動後、I2Cバスは完全にハングアップします。 i2cdetectは、1行目以外の情報を表示せず、電話を切ります。 回復する唯一の方法は、パワーダウン/アップサイクルです。
これはあなたが言及した問題のように見えますか?
私は4.19メインカーネルを使用しています。

@ sergey-suloev i2cdetectが8または16アドレスの後でスキャンを続行しない場合、これはこの問題とは無関係であると言えます。 この問題は、デバイスがクロックストレッチを実行するときにポップアップし、次のクロックサイクルの準備がまだ整っていないことを示します。 I2Cがほぼ40年前に設計されたとき、それはハードウェア実装でも考えられていたかもしれません。 しかし、今日では、ハードウェアに実装されたものにとって10マイクロ秒は時間の経過であるため、ハードウェアは常に次のクロックサイクルを処理する準備ができています。

このページは役に立ちましたか?
0 / 5 - 0 評価