Linux: Solución de error de I2C Broadcom.

Creado en 20 mar. 2013  ·  73Comentarios  ·  Fuente: raspberrypi/linux

El broadcom BCM2835 tiene un error (de hardware) en el módulo I2C.

El BCM implementa el "alargamiento del reloj" de mala manera:

En lugar de garantizar un "tiempo alto" mínimo para el reloj, el BCM permite que el reloj I2C funcione internamente, y cuando llega el momento de darle la vuelta al reloj, verifica si el reloj se ha elevado o no, y si está bajo, hace un "estiramiento del reloj". Sin embargo, si solo unos pocos nanosegundos antes de esta verificación, el esclavo libera la señal de reloj que indica que está listo para un nuevo reloj, el pulso de reloj puede llegar a ser tan corto como 40ns. (eso es lo más bajo que puedo medir y eso, por supuesto, es bastante raro). Con un reloj I2C de 100 kHz (10 microsegundos), los momentos "malos" para liberar el reloj están separados por 5 microsegundos.

Mis esclavos requieren un pulso de reloj de al menos 500ns. (que debería ser un factor diez más corto de lo que debería generar el maestro cuando está configurado para funcionamiento a 100 kHz).

Ese es un error de hardware sobre el que no podemos hacer mucho en este momento. (Sugerencia para los chicos del hardware: en lugar de implementar el estiramiento del reloj de esta manera: inhiba el conteo del contador CLOCKDIV mientras el reloj permanece bajo. Esto probablemente extenderá el reloj algunos relojes rápidos en cada ciclo, pero el cumplimiento de los estándares mejorará sustancialmente ).

Cuando esto ocurre, el BCM enviará un byte, con un primer pulso de reloj muy corto. El esclavo no ve el primer pulso de reloj, por lo que cuando al final de ese byte es el momento de ACK de ese byte, el esclavo todavía está esperando el octavo bit. El BCM interpreta esto como un "NAK" y aborta la transferencia I2C. Sin embargo, en ese momento, el esclavo ve su octavo pulso de reloj y emite un "ACK" (baja la línea SDA). Esto, a su vez, significa que el BCM no puede emitir una condición de "INICIO" adecuada para la siguiente transferencia.

Solución de software sugerida para reducir el impacto de este error de hardware: cuando se cancela una transferencia debido a un "NAK" para un byte, emita un solo ciclo de reloj adicional antes de la PARADA para sincronizar el esclavo. Probablemente esto deba hacerse en software.

Esto solo ocurre en la "ruta de error" cuando el esclavo no ACK un byte. Tal vez sea mejor hacer esto solo cuando NO sea el primer byte de una transferencia, ya que el error no puede ocurrir en el primer byte de una transferencia.

¿Esta solución de software pertenece al controlador? Si. Es un controlador para una pieza de hardware que tiene un error. Es deber del conductor hacer que este hardware defectuoso funcione lo mejor posible.

Bug

Comentario más útil

Hola hmf2015,
Este no es un foro. Este es un rastreador de errores. Esta lista de comentarios analiza un error que no está relacionado con sus problemas. Discuta su problema con un foro o servicio de ayuda adecuado. Una vez más, agradecemos su pregunta: "¿Quizás es lo mismo? ¿Quizás mi descripción ayude a resolver ese error?" pero ahora sabemos con certeza que lo que está viendo no está relacionado, por favor no "contamine" esta discusión más.

Todos 73 comentarios

Si una solución alternativa en el controlador hace que funcione mejor para la mayoría de los usuarios, asegúrese de incluirla.
¿Tiene un parche adecuado?

No aún no.

1) Todavía no he profundizado en el controlador I2C. Hace aproximadamente un año, tenía planes de escribirlo yo mismo, pero antes de empezar, alguien más lo había escrito. Entonces, alguien que ya conozca a este controlador podría estar mejor equipado para hacer esto como un proyecto de cinco minutos. Me tomaría al menos varias horas conocer al conductor.
2) Vale la pena discutirlo primero si usted (y tal vez otros) está de acuerdo en que se justifica una solución o solución.
3) Solo quería documentar esto como una "tarea" que no deberíamos olvidar ...
4) Tal vez alguien sugiera una solución alternativa diferente.

Hablando de soluciones provisionales: la solución alternativa también podría desencadenarse porque la línea SDA sigue siendo baja cuando intentamos iniciar una nueva transacción. Esa es claramente una situación de "problema".

El caso "sale mal" puede ser poco común en los casos "normales". Mucha gente tendrá un módulo hardware-i2c en el bus I2C. Cuando se inventó I2C, "10us" podría haber sido un período de tiempo "muy corto" para que algunos chips manejaran las solicitudes, por lo que era necesario alargar el reloj. Hoy en día, cualquier implementación de I2C de hardware debería poder manejar "I2C rápido" hasta incluso más rápido.

Esto se combina con la forma en que los chicos de atmel implementaron sus módulos asíncronos. En lugar de que el módulo se ejecute en el reloj proporcionado externamente (esclavo i2c o esclavo SPI), el módulo aún se ejecuta en el reloj del procesador. Y sincroniza todas las señales entrantes pasándolas a través de un montón de filpflops. Buen diseño de hardware. En mi humilde opinión, la alternativa es mejor: ejecutar el módulo fuera del reloj externo y sincronizar cuando los datos pasen al otro dominio de reloj (cpu). Esto permitiría, por ejemplo, que el módulo SPI funcione a 20MHz, aunque la CPU funcione a solo 8.

De todas formas. Basta de divagaciones de hardware.

Solución alternativa sugerida: emita un ciclo de reloj adicional cuando, al comienzo de una transacción, la línea SDA aún esté baja. (debe comenzar alto para poder emitir una condición de "inicio").

En primer lugar, sé poco sobre I2C. He hablado con Gert y otros sobre soluciones alternativas.

Hay dos problemas conocidos con I2C:

  1. El problema de estiramiento del reloj que ha descrito
  2. Problema con la máquina de estado I2C al reiniciar

En primer lugar, la opinión de Gert es que no hay una solución infalible.
Si el esclavo I2C no admite la extensión del reloj, está bien.
Si el reloj I2C se alarga en una cantidad limitada, reducir la frecuencia del reloj I2C puede evitar el problema
Cambiar a un controlador que golpea un poco para los esclavos que no caen en los casos anteriores es una solución segura.

No sé si su propuesta funcionará. Me interesaría saber si reduce el problema o lo soluciona por completo.

Gert dice que tiene una descripción del error que intentará liberar.

Para 2, en el controlador GPU I2C tenemos un código que soluciona un problema con la máquina de estado:

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

No estoy seguro de si la gente se está enfrentando a este problema, pero el pegado podría ser útil si es así.

No es posible erradicar por completo este error de hardware.

Cuando sucede, el maestro y el esclavo no están de acuerdo en el número de ciclos de reloj. Por lo tanto, los datos, interpretados por el esclavo, y los datos como maestro (= raspberry pi = controlador / aplicación) previstos difieren. Es posible que esté escribiendo un valor completamente falso en un registro en alguna parte. Muy molesto.

Mi solución alternativa sugerida al menos haría que la siguiente transacción funcione. El impacto se reduciría a la mitad: solo una transacción fallida en lugar de dos. No eliminaría el problema.

Si el esclavo I2C no admite la extensión del reloj, está bien.

Si el esclavo I2C no requiere alargamiento de reloj ...

Si el reloj I2C se alarga en una cantidad limitada, reducir la frecuencia del reloj I2C puede evitar el problema

Si. Tengo 10 dispositivos "en el campo" en una ubicación. Aparentemente, la frecuencia de reloj (reloj RC) de tres de los módulos es diferente de tal manera que terminan "terminados" con el reloj estirándose exactamente en el momento equivocado. La reducción de la frecuencia del reloj solucionó los problemas de esos módulos.

Si el retardo de alargamiento del reloj NO es fijo, pero, digamos, varía en más de 5 microsegundos, existe una probabilidad más o menos estadística de resolver el problema. En mi caso, el esclavo requiere 0,25 microsegundos de ancho de reloj. Entonces, el estiramiento del reloj termina en el 5% del tiempo previo al momento de cambio de reloj para el BCM, entonces las cosas salen mal. Entonces, en este caso, aproximadamente 1 de cada 20 transferencias saldría mal. (Las especificaciones dicen un mínimo de 250 ns para un pulso de reloj. De hecho, eso no significa que no se verá si es más corto. Creo que las posibilidades de que se vea van linealmente del 100% en> 250 ns al 0% en < 125ns.)

Pasé ayer estirando el período de estiramiento del reloj de tal manera que caería alrededor de la marca de 2.5 microsegundos en la ventana de oportunidad de 5 microsegundos. Si apunto al inicio de la ventana y mi reloj RC corre un poco rápido, presionaría el "0" que desencadena el error. Si apunto a 5, lo mismo. Así que ahora estoy apuntando al medio, lejos de los lugares malos. Pero cambie el reloj I2C a 80kHz, y BAM, estoy apuntando bien al punto sensible ... (y si no sucede con 80kHz, sucederá con algún valor entre 80 y 100).

Aquí está la descripción de Gert del error I2C:
https://dl.dropbox.com/u/3669512/2835_I2C%20interface.pdf

¡Jaja! He instrumentado mi tablero de pruebas exactamente de la misma manera. Corté la traza SCL y monté un conector de puente de 0.1 "allí. Aunque no estoy midiendo, hay un puente normal allí, o un conector hembra con una resistencia de 100 ohmios cuando lo estoy.

No creo que solo ocurra el primer reloj. Eso significaría que podría solucionar el problema NO estirando el reloj (como probablemente hacen la mayoría de los chips I2C de hardware), o haciendo que el reloj dure al menos un ciclo completo.

He instrumentado mi código esclavo i2c de tal manera que puedo hacer que el reloj cambie en incrementos de 0.5 microsegundos. Puedo ordenarle que cambie el estiramiento del reloj a XXX sobre I2C y luego funciona así durante 50 milisegundos antes de volver a los valores predeterminados. (en caso de que no funcione, necesitamos que vuelva a funcionar. De esta manera puedo escanear rápidamente un rango completo de valores para estas configuraciones, mientras monitoreo las líneas SDA y SCL con un analizador lógico. Enviando un "retardo de uso XXX" y luego enviar una picadura toma 25 milisegundos. Luego, incrementar un contador en el script y enviar el "siguiente retraso" toma el script de shell alrededor de 100ms. Entonces puedo escanear 100 valores posibles en aproximadamente 10 segundos.

HE visto que el error ocurre en retrasos más largos. Entonces, la teoría: "solo ocurre en el primero" no es correcta.

En cuanto al manejador de interrupciones "súper eficiente": Sí, yo también puedo hacerlo. La cuestión es: la función de extensión del reloj me permite poner el código "manejar este byte" en la rutina de interrupción y no preocuparme de que tarde unos microsegundos o milisegundos. En teoría, el alargamiento del reloj asegurará que el maestro espere a que termine de manejar este byte antes de continuar con el siguiente. Ese plan está totalmente roto con el error en el 2835. Ahora solo hago que el reloj se detenga, y luego espero terminar de manejar el byte en los 70 microsegundos que siguen.

Tengo que "conteo cíclico" para apuntar a la mitad del medio reloj de 5 microsegundos para poder liberar el estiramiento del reloj. Si apunto al inicio (para causar un período alto de reloj de 4.9 microsegundos), el reloj de mi esclavo podría estar funcionando un poco más rápido y provocar que el error se active medio ciclo antes. Entonces, ambos extremos del ciclo de medio reloj son peligrosos, tengo que apuntar a un ciclo de reloj corto, pero lo suficientemente válido.

En mi humilde opinión, el cambio en el módulo es simple: cuando SCL es "impulsado alto" (es decir, no impulsado en absoluto), detenga el reloj maestro del módulo I2C. Esto tiene el efecto secundario de permitir buses I2C mucho más largos porque el alargamiento automático del reloj ocurre cuando la capacitancia del bus está por encima de las especificaciones.

Gracias por intentar ayudar, iz8mbw, pero esos no tienen nada que ver con este error (de hardware).

He medido mi reloj I2C y sale como 100 kHz, que el controlador cree que debería ser. El controlador tiene un objeto de "fuente de reloj" que consulta por la frecuencia y lo usa. Todavía no he instrumentado a mi controlador para imprimir la frecuencia.

Solo como información para las personas que quieran VER el error en acción, tengo algunas "pruebas" en forma de volcado del analizador lógico.
Hmm, puedo adjuntar imágenes, pero no el volcado binario de LA. Ese está aquí: http://prive.bitwizard.nl/LA_with_bug_scan_50_to_100_microseconds_delay.bin.gz

En la imagen LA_with_bug_shot1.png verás la breve ráfaga de actividad: "establecer retraso en XXX" luego una pequeña ráfaga que intenta escribir unos 10 bytes, pero se aborta debido a un NACK. A la derecha verá un paquete de 10 bytes adecuado. La línea SDA permanece baja hasta la próxima ráfaga que está desalineada (todos los bits se desplazan y en mi esclavo el contador "x-byte-en-paquete" no se ha reiniciado por la condición de inicio no existente al inicio de ese paquete .

En la imagen LA_with_bug_shot2.png me acerqué a la sección donde ocurre el pulso corto. Este es el pulso más largo que he visto fallar: 290ns. (¡encima de la especificación de la hoja de datos para el Atmel!)
LA_with_bug_shot1
LA_with_bug_shot2

¡Oh, de ahí de donde vino eso!

Tengo un proyecto que estoy tratando de controlar con I2C desde una raspberry pi y, honestamente, estoy cerca de rendirme y cambiar a una beagleboard o hacer que Pi hable con una FPGA a través de SPI, que luego hace las cosas de I2C .

Tengo una placa en el correo que debería poder hacer eso (entrega prevista: mañana). Conector SPI, conector I2C. Sería un buen proyecto para probar con esa placa. Envíame un correo electrónico si quieres estar informado.

Situación actual: Veo un comportamiento compatible con el de Gert: "solo el primer ciclo puede salir mal" cuando el esclavo es un ATMEGA, y veo el error con toda su fuerza cuando el esclavo es uno de mis ATTINY.

Estos son los retrasos que probé:
i2c_delays_atmega
y el pulso SCL más corto observado durante esta sesión de prueba fue de 4,5 microsegundos.

Ahora probando con el esclavo attiny, los retrasos probados para el ACK son:
i2c_delays_attiny

y el ancho de pulso mínimo es 41ns (mi resolución de medición):
i2c_delays_attiny2

¡Ah! ¡Lo encontré! Parece que el reloj que se extiende antes del ACK de un byte es "peligroso", pero el reloj se extiende DESPUÉS del ACK está bien ...

Yo y otros ciertamente estamos golpeando el problema del inicio repetido. Tengo un truco de espacio de usuario en http://cpansearch.perl.org/src/MDOOTSON/HiPi-0.26/BCM2835.xs en proc hipi_i2c_read_register_rs. Esto parece funcionar para los usuarios que han informado que lo han probado o que han incorporado el código C (aunque son solo 5 personas), aunque no había descubierto correctamente cómo determinar que la etapa TX se había completado. Supongo que necesito aprender a compilar módulos del kernel y ejecutar pruebas existentes con el código anterior.

¿No podríamos simplemente forzar al kernel a ignorar el hardware I2C y usar I2C basado en GPIO bitbanged en los mismos pines? Creo que la sobrecarga para eso sería más aceptable que los errores en el hardware en sí.

¿Qué gastos generales esperas? El controlador actual tiene como valor predeterminado el reloj de 100 kHz. Entonces, leer 10 bytes de un sensor intertial i2c toma aproximadamente 1 ms. Si haces bitbang, es probable que estés agitando los ciclos de la CPU todo ese tiempo ...

Mi preferencia sería que el controlador admita opcionalmente bitbanging i2c a través de un parámetro de módulo (o tal vez un módulo separado si es más conveniente).

Muchos dispositivos no utilizan la extensión del reloj (o la extensión del reloj en una cantidad limitada, por lo que pueden funcionar correctamente a velocidad reducida), por lo que el controlador I2C de hardware sigue siendo preferible en esos casos.

El kernel en sí tiene un controlador para I2C bitbanged en pines GPIO, este controlador tiene una sobrecarga mucho menor que bitbangging desde el espacio de usuario y expone la misma API que los controladores I2C de hardware. Mi sugerencia sería compilar tanto ese controlador como el controlador I2C de hardware como módulos, luego cargar el controlador de hardware por defecto.

@Ferroin
¿Utiliza el controlador I2C bitbanged en Pi?
¿Qué opciones .config ha agregado para construirlo? ¿Algún parche de origen?
¿Qué debe hacer para elegir el controlador a utilizar (modprobe? ¿Diferentes / dev / dispositivos?)

No he usado el controlador en el Pi, pero tengo un amigo que lo usa con éxito en un BeagleBoard.
La opción de configuración es I2C_GPIO.
Si tanto eso como el controlador de broadcom estuvieran configurados como módulos, elegir el controlador sería tan simple como cargar el módulo del kernel.
El módulo GPIO necesita parámetros para decirle qué GPIO usar como SDA y SCL, no sé cuáles son los parámetros, pero según la fuente no muy bien documentada en dirvers / i2c / busses / i2c-gpio.c, parece que los parámetros apropiados son 'sda = X scl = Y' donde X e Y son los pines que debe usar.

El módulo i2c-gpio en sí no proporciona ninguna forma de pasarle parámetros. Por lo tanto, necesita otro módulo que registre los datos de la plataforma y configure al menos el número de bus, los pines SDA y SCL. Escribí una prueba de concepto de dicho módulo e incluso funcionó en los pines 0 y 1 pero sin i2c-bcm2708 cargado (pcf8574 fue detectado por i2cdetect, pude manejar algunos LED con el módulo gpio-pcf857x). Pero luego quemé mi pcf8574 al cambiar los pines (y no tengo ningún otro chip i2c en este momento), así que no pude probarlo. Aqui esta el codigo

@kadamsi
Hacer los parámetros del módulo sda_pin / scl_pin puede ser útil. Al igual que una solicitud de extracción.
¿Alguien puede confirmar que esto funciona para ellos?

Eso es menos trivial de lo que parece: espera que se le pase una estructura de datos de plataforma hasta el final.

Por otro lado, la plataforma no dicta qué GPIO vas a utilizar hoy, por lo que esforzarte para cambiarlo parece razonable. (normalmente, los datos de la plataforma especifican: "¿Cómo está / esta / la computadora conectada?"

@palomitasmix
Estoy planeando hacerlos configurables, simplemente no tuve suficiente tiempo ayer. También me gustaría poder crear más de un autobús a la vez. ¿Quizás de forma dinámica, como archivos GPIOS export y unexport sysfs (pero no estoy seguro de si es posible no exportar limpiamente dicho bus)? Ah, y encontré otro pcf8574 y pude confirmar que también funcionó bien en diferentes pines GPIO cuando se usan resistencias pullup externas. Desafortunadamente, no tengo dispositivos I²C más sofisticados para probar. Entonces, ¿está interesado en proporcionar dicho módulo en el árbol del kernel predeterminado?

@kadamski
No tengo una configuración para probar módulos como este. Sin embargo, cualquier característica de hardware que proporcione el chip (como I2C) debe tener controladores de kernel para permitir que más personas los utilicen. Si el hardware I2C tiene errores que impiden que las personas usen ciertos periféricos, entonces vale la pena usar una alternativa de bitbanging.

Por lo tanto, si produce un nuevo controlador que parece inofensivo para las personas que no lo usan (es decir, construido como un módulo, y no hace nada hasta que se carga), y hay alguna evidencia (es decir, algunos informes de usuario de confirmación) que está funcionando correctamente, entonces Estoy feliz de aceptar un PR.

¿Se ha corregido el HW en BCM2837 (en RPi 3)?

Mi conjetura es: no. Pero probablemente no tenga tiempo para probar esto hoy.

BCM2837 I2C no se modifica.

Eso es lamentable, pero gracias por la información.

eso es muy molesto.

Estoy de acuerdo. ¿Alguien tiene un enlace a erratas BCM2837, o similar, indicando que el problema aún existe? Sería útil cuando tengamos que transmitir la noticia. O @ P33M , tal vez se le pueda citar como autoritario si trabaja para Broadcom.

Tiene autoridad, aunque no trabaja para Broadcom.

Eso es bueno. Pero ya busqué en Google, y aparte de que P33M es M33P en otro lugar, lucho por encontrar una identificación que pueda transmitir de manera útil. Lo cual está bien, pero significa que no es una buena fuente para citar. :-) Entonces, un enlace de erratas sería útil.

@ P33M funciona para Raspberry Pi. Puede tratar lo que dice como autoritario.

No creo que haya una lista de erratas, probablemente debería haberla. Lo dejé
para confirmar su identidad, ¡o no!

El 15 de marzo de 2016 a las 14:30, RalphCorderoy [email protected] escribió:

Eso es bueno. Pero ya busqué en Google, y aparte de que P33M es M33P
en otro lugar, lucho por encontrar una identificación que pueda transmitir. Lo cual está bien,
pero significa que no es una buena fuente para citar. :-) Entonces, un enlace de erratas sería
práctico.

-
Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente o véalo en GitHub:
https://github.com/raspberrypi/linux/issues/254#issuecomment -196845789

@RalphCorderoy Soy un empleado de Raspberry Pi (comercio) Ltd. Mi respuesta es autorizada.

@ P33M , Ta, eso

Esto está afectando un proyecto en el que estoy trabajando. Afortunadamente, tengo control completo sobre el firmware del dispositivo esclavo y pude agregar el uso de la solución alternativa de agregar un retraso de medio período adicional (estiramiento del reloj) en mis respuestas, lo que evita el mal comportamiento.

Se puede encontrar un buen análisis del problema en advamation.com .

¿Es este hardware defectuoso en la implementación I2C de Broadcom o hay posibles ajustes del kernel para que el hardware se comporte correctamente?

Me acabo de suscribir a este problema porque también me he encontrado con un producto que estoy desarrollando.
que usa i2c entre un AVR y Pi. Ahora necesito repensarlo.
¿Alguien ha usado alguna forma confiable de golpe de bits i2c?

@ mwilliams03 , puede que esté interesado en este proyecto , en el que establecí con éxito una comunicación I2C de 100 kHz y 400 kHz entre una Raspberry Pi y un AVR. No estoy golpeando bits, sino que estoy usando el soporte de hardware I2C e insertando retrasos en puntos clave. Resultó que el AVR es lo suficientemente lento como para que a 400 kHz no se necesiten retrasos adicionales.

En particular, aquí hay información sobre los problemas de I2C . Tenga en cuenta también que el módulo TWI del AVR tiene un problema que impide las lecturas rápidas .

gracias @ pdg137 , lo probé y en el primer intento obtuve 1.2 millones de lecturas sin errores y aún así.

@rewolff parece que este problema se ha resuelto. Si ese es el caso, cierre este problema.

Y ahora .... agregue una palanca de cambios de nivel y 40cm de cable de extensión .. ¿Funciona entonces? Lo más probable es que esto cause suficiente retraso en el lado "ascendente" de las formas de onda y, de repente, el error vuelve a aparecer.

Por lo que puedo decir, broadcom y los empleados todavía piensan que este error está restringido a los PRIMEROS 5 microsegundos (en realidad, medio reloj) después del último bit de un byte. luego, con solo agregar 10 microsegundos, las cosas se trasladarán a dos medios relojes más y no debería haber problemas. En mis pruebas, encuentro "malos" momentos para detener el reloj que se extiende cada 5 microsegundos.

Debido a la simetría entre SPI e I2C, es más fácil en mi código AVR si el siguiente byte de datos se "calcula" en la interrupción de "datos siguientes" ... (Expongo una interfaz donde se permite continuar leyendo, por lo que un búfer de no siempre es suficiente).

No estoy convencido.

Tengo problemas con SMBus entre un Respberry Pi y un ATMEGA 324PA. ¿Podrían estar relacionados con este problema? https://stackoverflow.com/questions/39274784/talking-smbus-between-raspberr-pi-and-atmega-324pa-avr-not-clock-stretching

Por lo que puedo decir, broadcom y los empleados todavía piensan que este error está restringido a los PRIMEROS 5 microsegundos (en realidad, medio reloj) después del último bit de un byte.

@rewolff : Tendría que estar de acuerdo con los empleados de Broadcom. En mis pruebas, con una Raspberry Pi 3 y 100 kHz I2C (que se ralentiza a 62 kHz cuando la CPU está acelerada), obtengo resultados similares a la

La animación parece sólida. Sin embargo, no coincide con mi experiencia. Quizás debería configurar una prueba. Puede que tarde un poco. Está ocupado con otras cosas.

Pero si este fuera el caso, simplemente un "usleep (10)" en mi rutina de interrupción (con estiramiento del reloj del hardware) normalmente haría el truco y haría que las cosas no se bloqueen. Estoy bastante seguro de que este no fue el caso. :-(

@rewolff : En la Raspberry Pi 3, he visto que la CPU se acelera a 600 MHz, lo que resulta en una velocidad I2C predeterminada de 62 kHz. Por lo tanto, debe dormir 17 microsegundos en el ISR de su esclavo si el ISR comienza en el borde descendente de SCL. O si cree que la CPU podría reducirse a menos de 600 MHz, duerma más tiempo.

¿Sería posible incluir el módulo i2c-gpio-param de @kadamski en el kernel de Raspberry Pi? Puedo confirmar que este enfoque parece funcionar bastante bien para mi aplicación (software AVR esclavo I2C) y es algo engorroso instalar los encabezados requeridos para el kernel de frambuesa, por lo que tenerlo disponible sería genial.

También sería una buena solución para abordar el error de HW que subyace a todo este problema.

@onnokort ¿ Te refieres a la superposición i2c-gpio presente en los núcleos actuales desde noviembre de 2015? https://github.com/raspberrypi/linux/blob/rpi-4.4.y/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
Del archivo README para superposiciones:

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 : Impresionante, gracias, aprendí algo nuevo hoy. No probé esto todavía, pero sí, se ve exactamente lo que estaba buscando (y lo encontré en i2c-gpio-param).

@popcornmix @ 6by9 ¿Se puede cerrar esto? Llevo mucho tiempo, y las cosas de dt param de mi lectura parecen ser una opción decente.

La solución alternativa recomendada para los dispositivos que definitivamente no funcionan bien con nuestro hardware I2C es usar la superposición i2c-gpio, que ataca a los pines.

De lo contrario, el controlador ascendente admite el alargamiento del reloj en la fase ACK de dirección.

Queridos todos, hoy he probado el BNO055 en el paquete GY-955 de Asia Oriental que se comporta muy feo a 100_000 Hz con un Pi 2B (BMC2835). Para las pruebas, cambié la frecuencia del bus I2C de 50_000 a 400_000 Hz y encontré problemas a 100_000 Hz, pero para 50_000, 85_000, 115_000 y 125_000Hz el código de Adafruit (Adafruit_Python_BNO055) funciona bastante bien con la conexión I2C, 150_000 Hz parece ser demasiado rápido para el BNO055, funciona pero los valores a veces son incorrectos. Lo confieso, no probé la frecuencia con un osciloscopio, solo he leído el archivo / sys / class / i2c-adapter / i2c-1 / of_node / clock-frequency, por lo tanto, queda cierta incertidumbre abierta. Ahora empiezo a implementar una interfaz completa para el BNO055 en ADA.
Facit: El error de hardware en el manejo de BMC I2C aparece solo a 100_000 Hz, debe confirmarse.

Solo para su información, el error de hardware ocurre cuando el dispositivo esclavo estira el reloj y libera la línea SCL después de períodos de reloj I2C de 0.9 a 0.999. La línea comenzará a subir y el hardware pi dirá: Oh, no hizo estiramiento del reloj, así que puedo proporcionar el siguiente pulso de reloj bajando la línea del reloj nuevamente.

El error ocurre cuando el tiempo restante en el período del reloj es suficiente para que la línea clk pase el umbral "HIGH" para la frambuesa pero no para los dispositivos esclavos O cuando el esclavo tiene filtrado de ruido y considera un alto durante <x% del El ciclo normal del reloj I2C es un error.

Esto no "sólo ocurre a 100 kHz", sino también a muchas otras frecuencias, excepto que el tiempo de respuesta del dispositivo esclavo tiene que ser un valor diferente.

Supongamos que el reloj es de 100 kHz, por lo que un ciclo normal sería 5us alto y 5us bajo. Ahora suponga que en t = 0 el pi inicia el último ciclo de reloj bajando la línea del reloj. En t = 5us, pi libera la señal del reloj, pero el esclavo sigue ocupado y mantiene el reloj bajo. En t = 9us, el esclavo finaliza y libera la señal de reloj. En t = 10us, pi mirará la señal del reloj y pensará: Ok, no hay alargamiento del reloj, así que continúa, y vuelve a bajar la señal del reloj. La señal del reloj ahora solo ha sido alta durante 1us (un poco menos debido a la capacitancia y la constante de tiempo de las resistencias pullup) y es posible que el esclavo no la vea. Ahora, un dispositivo diferente no está listo después de 9 microsegundos, sino después de 10,5. Ahora, a 100 kHz, el pi verá "todavía bajo, el reloj se alarga, espera otros 5 microsegundos. Ahora obtendremos un pulso de reloj de 4,5 microsegundos y todo funcionará. Pero ejecuta este dispositivo a 90 kHz y se mete en problemas. Ahora el pi se verá en 11 microsegundos desde el principio, y la señal del reloj habrá estado alta durante menos de un microsegundo -> Problemas.

Las personas que se quejan de esto NO son las que tienen esos otros dispositivos. Esos funcionan a los 100 kHz predeterminados. Pero el error sigue siendo muy real y ocurriría en esos dispositivos simplemente a velocidades de bus distintas a las de los dispositivos que tenemos tú y yo.

Gracias por la respuesta, explica muy bien, por qué obtuve una transferencia confiable en las frecuencias que elegí:
a 100_000 Hz los problemas surgen en el período de 9 a 9,99 µseg.
a 85_000 Hz los problemas comienzan en 1_000_000 / 85_000 * .9 = 10,59 µseg> 9,99 s, por lo tanto, se ignora el alargamiento del reloj, supongo, para todas las frecuencias inferiores a 85_000 Hz el punto de inicio de los problemas es superior a 10,59 µseg .
a 115_000 Hz el ciclo del bus es 1_000_000 / 125_000 = 8,7 µseg <9 µseg, por lo que el alargamiento del reloj se detecta correctamente, para todas las frecuencias superiores a 115_000 Hz el ciclo del bus es inferior a 8,7 µseg.
Entonces, cuando tengo problemas, puedo calcular la frecuencia que necesito.
(Leí la información en http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html,
se anotó .5 en lugar de .9 de un punto).

Bien. Depende de lo que su esclavo detecte como una señal de reloj válida. Y cuánto retraso introduce el RC en su autobús. En mi caso, el AVR que uso como esclavo considera que los pulsos de menos de dos ciclos de reloj son una falla. Con un reloj RC interno de 8MHz (+/- 10% !!!), el pulso debe ser de al menos 250ns para ser detectado. Las especificaciones I2C requieren 5 microsegundos, por lo que hay un factor de 20 "margen" entre lo que se requiere oficialmente y lo que ya no funciona.

Al principio pensé en aumentar un poco la extensión del reloj en mi esclavo produce un poco para decir 12us. Eso funciona hasta que la capacitancia del bus agrega suficiente retraso para causar un problema nuevamente. Así que es muy difícil evitarlo. Es molesto tener que decirles a sus clientes que no utilicen el i2c estándar de 100 kHz.

Lo siento, pero necesitaba algo de tiempo para escribir una implementación completa y un escenario de prueba.
Te agradezco toda la información que me diste, fue muy útil.
Mi escenario de prueba está construido con 2 MEMS (BNO055 empaquetado como GY-055, MPU9255 empaquetado como MPU-9250/6500, el registro WHO_AM_I dice MPU9255) y 1 extensor GPIO PCF 8574 (empaquetado PCF 8574).
El reloj I2C en Pi (2b) se estableció en 125 kHz, verificado mediante la lectura / sys / class / i2c-adapter / i2c-1 / of_node / clock-frequency.
Mi código se ejecuta 100 veces leyendo datos de MEMS y escribiendo datos para PCF con un retraso de 0.1 seg.
Resultado:

  • La inicialización del MEMS se realizó correctamente.
  • La lectura de los datos MEMS a través del bus I2C se realizó correctamente en todos los ciclos.
  • La escritura de datos en el PCF a través del bus I2C fue exitosa en todos los ciclos.

Por lo tanto, MEMS y PCF aceptan un reloj superior al estándar de 100 kHz.
En un entorno mayor, la comunicación con el AVR se realiza a través de una línea serial, en mi segundo la comunicación se hará a través de USB, pero no está terminada, real me tropecé con los problemas del bus I2C causados ​​por el BNO055, pero creo para mi entorno, encontré una solución para un Pi 2b y espero que también funcione con un Pi 3, esa es la próxima prueba. Y luego tengo que integrar otros 2 MEMS, 1 VL53L0X y 1 BME280, espero que funcione con la nueva frecuencia y la capacitancia del bus acepte todos estos elementos.

Estoy jugando con este problema ahora en un RPi 3 Modelo B +, y veo resultados diferentes a los que describe el artículo de Advamation. El silicio no se aceleró recientemente, ¿verdad?

La versión corta es que las cosas parecen funcionar si me estiro en read-preACK, write-preACK o write-postACK; la única vez que necesito asegurarme de estirarme largo o nada es read-postACK. Sin embargo, todavía necesito limpiar mi experimento antes de poder decir algo seguro.

Primero, una nota sobre terminología. El artículo de Advamation dice:

Entonces, I2C con Raspberry Pi solo funciona si
el esclavo no usa la extensión del reloj en absoluto, o
el esclavo alarga el reloj solo al final / directamente después de una fase I2C-read-ACK (después de leer ACK / NACK), pero luego en más de 0,5 períodos de reloj.

El término "I2C-read-ACK-phase" parece algo ambiguo. Si es un comando de lectura I2C (es decir, el bit R / W̅ de post-dirección está establecido), el esclavo estaría escribiendo el bit A̅C̅K̅, no leyendo, al contrario del paréntesis. Cuando digo "read-postACK" aquí, me refiero a que el bit R / W̅ se estableció justo después de la dirección (y presumiblemente no cambió por el protocolo como lo hace SMBus), por lo que el esclavo acaba de escribir su respuesta A̅C̅K̅.

Como se ha insinuado por aquí, parece que si el RPi detecta que un esclavo mantiene el SCL bajo, retrasará su reloj SCL interno en medio ciclo (5μS). El error se activa si el esclavo mantiene el SCL bajo durante _ casi_ medio ciclo. Si eso sucede, entonces el RPi todavía dejará que SCL suba y luego lo bajará inmediatamente cuando su reloj SCL se active. Esto da como resultado un pulso de reloj runt, que algunos dispositivos pueden ver como pulso mientras que otros no. (Como referencia: la especificación I2C implica un tiempo máximo de SCL nominal de 5μS y establece un tiempo mínimo de 4.0μS a 100kHz, que es la velocidad predeterminada de la interfaz I2C del RPi).

En mis experimentos, en las fases read-preACK, write-preACK y write-postACK, el RPi aseguraría que el tiempo máximo de SCL máximo que permitiría fuera de 4μS aproximadamente. Parecía dispuesto a retrasar su reloj SCL en esas fases. Sospecho que el RPi muestreó la línea SCL poco después de que la soltó, y si SCL todavía estaba bajo, hizo retroceder su reloj SCL una media fase.

Sin embargo, en la fase de lectura-postACK, vi que el RPi emitiría relojes runt (<4μS, a menudo 2μS o menos) si la línea SCL se mantenía baja durante aproximadamente 6-9μS. Sospecho que en esta fase, los ingenieros de Broadcom siguen un camino diferente que intenta hacer menos probable que tengan que retrasar una media fase en una línea de alta capacitancia. Lamentablemente, como hemos visto, se queda corto.

Por lo tanto, mi código actual necesita estirar SCL más allá de ½ ciclo en la fase read-postACK de lecturas que pueden llevar un tiempo (como las conversiones ADC). Si no lo hago

Las pruebas actuales que estoy ejecutando utilizan un PIC16F1619 como dispositivo esclavo. El dispositivo esclavo utiliza un bucle para estirar el reloj tanto en los comandos de lectura como en los de escritura, tanto antes como después del AAC. La longitud de este bucle más la sobrecarga varía de 3μS (menos que el tiempo que el RPi mantiene SCL bajo) a 90μS en incrementos de 0.35μS. Tengo un programa Python en el RPi que aplicará valores diferentes a dos registros, luego los leerá y afirmará que los valores de lectura son correctos. Los valores que se utilizan

Piquan,
Broadcom ha minimizado esto al proclamar que este problema solo ocurre en el primer tramo del reloj. No creo que este sea el caso. Debería poder verificar eso. Advamation parece estar siguiendo las declaraciones de Broadcom.

@rewolff Bueno, puede haber algo en su interpretación. Si por "primer estiramiento del reloj" se refieren a "la primera vez en una etapa determinada que SCL se estira en más de una traducción de reloj", entonces su descripción es precisa: si se estira en más de un ciclo de reloj, entonces sí: en total fases, si se estira en> .5 ciclos, está en buena forma. Al menos, en los vagos experimentos que he hecho hasta ahora; aún están por llegar experimentos más precisos.

Estoy feliz de realizar algunos experimentos mejores para demostrar cuándo el I2C del RPi puede y no puede manejar los estiramientos del reloj, y obtener repros que BCM puede enviar a los ingenieros.

Lamentablemente, hay una revoluciones de silicio muy significativa que necesitarían para solucionar este problema; no necesitan marcar el reloj del divisor SCL cuando SCL se mantiene bajo (por una fuente interna o externa). Eso probablemente requerirá un cambio en el nivel de silicio, que es caro; la mayoría de los ECO son a nivel de metal, que es ... bueno, no es barato, pero es mucho más barato que el silicio.

Mi objetivo principal aquí es caracterizar los tipos de esclavos que funcionarían y no funcionarían con el RPi, con alguna evidencia experimental.

Parece que necesitamos datos más sólidos, como escenarios de reproducción, para convencer a Broadcom de que rediseñe el controlador I2C. Incluso con datos sólidos, los ingenieros deberán convencer a la gerencia de que vale la pena revisar el silicio para la próxima revisión.

Dicho esto, dedicaré algo de tiempo a diseñar escenarios reproducibles para que los ingenieros de BCM puedan ver y probar claramente el problema. Sin embargo, dependeré de los miembros de la comunidad aquí para comunicar mis hallazgos a Broadcom; No tengo un canal para ellos.

Debo aclarar algo sobre mi comentario anterior para la comunidad, sobre los cambios de silicio versus metal.

¿Sabe cómo, si obtiene una placa de SparkFun o Adafruit, a menudo tiene trazas que puede cortar o soldar para cambiar su comportamiento? La mayoría de las placas I2C tienen rastros que puede cambiar para cambiar la dirección, habilitar o deshabilitar las resistencias pull-up, etc.

Los diseñadores de microchip hacen lo mismo. Hay muchos cambios que pueden hacer en las capas metálicas de un microchip, para que no tengan que cambiar las capas de silicio. Esto se debe a que cambiar las capas de silicio es difícil y costoso (como cambiar el chip en una placa), mientras que las capas de metal son mucho más fáciles de cambiar (como cambiar las trazas en una placa).

Se pueden hacer muchos cambios útiles en las capas de metal, porque los diseñadores piensan en el futuro y hacen conexiones de metal (puentes, esencialmente) que cambian el comportamiento de un chip.

Pero si hay un cambio que no planearon y no pueden averiguar cómo realizarlo redirigiendo los rastros dentro del chip, entonces tienen que cambiar el silicio. El silicio necesita mucha más planificación, verificación y enmascaramiento, por lo que es difícil de cambiar.

Muchas empresas, si tienen una capa de silicio que sea "suficientemente buena", la utilizarán el mayor tiempo posible. Reutilizarán algunas partes de la capa de silicio en múltiples revisiones del chip.

Sospecho que ahí es donde está BCM: necesitan una buena evidencia de que este error no se puede solucionar en los controladores o el metal antes de que puedan justificar la reingeniería de esta parte de la capa de silicio desde cero.

Es extremadamente improbable que haya un respin del silicio existente solo para solucionar este problema (¿tiene $ 1M de repuesto?). Sin embargo, los chips futuros pueden tener una solución, quién sabe.

El miércoles, 05 de septiembre de 2018 a las 02:13:19 AM -0700, Joel Ray Holveck escribió:

Parece que necesitamos datos más sólidos, como escenarios de reproducción, para
convencer a Broadcom de rediseñar el controlador I2C. Incluso con
datos sólidos, los ingenieros tendrán que convencer a la dirección de que
vale la pena revisar el silicio para la próxima revisión.

Ya han tenido seis años y 3 revisiones de silicio en las que
han demostrado su decisión: "no arreglará".

si se estira en> .5 ciclos, está en buena forma.

No lo creo. Cada vez que suelte CLK en el "justo antes del
broadcom mira de nuevo "período de tiempo, obtienes pulsos cortos. Puedo fácilmente
retrasar la liberación de la señal del reloj por decir 5 microsegundos inútiles para
estar siempre fuera del ciclo 0.5. Pero eso no funcionó.

El miércoles, 05 de septiembre de 2018 a las 02:28:53 AM -0700, James Hughes escribió:

Es extremadamente improbable que se repita la
silicio existente solo para solucionar este problema (¿tiene $ 1M de repuesto?). Futuro
Sin embargo, los chips pueden tener la solución.

Lo dudo. Pasamos de BCM2835 con error CONOCIDO al BCM2836 con
el mismo error en el BCM2837 con exactamente el mismo error en el BCM2837B0.

Ahora bien, ¿por qué cree que la próxima revisión será diferente?

BCM tiene un mercado objetivo: teléfonos y dispositivos de TV para estos chips. En
su mercado objetivo nadie está haciendo software-I2C con fines generales
microcontroladores como AVR y PIC. NO van a arreglar esto.

Es una pena que se requiera este esfuerzo de investigación, por muy bueno que sea. Cuando pregunté antes por una errata que cubre esto, se pensó que no había ninguna. ¿Ha cambiado eso ahora y hay una URL? Idealmente, Broadcom ayudaría a la comunidad describiendo con precisión la falla y cuándo ocurre, de modo que las soluciones alternativas o las evaluaciones de componentes compatibles sean más fáciles de resolver con confianza. Incluso en la medida del fragmento de HDL relevante si no quieren intentar traducir eso con precisión en una descripción.

La sugerencia de detener el divisor de reloj de medio bit cuando se permite el alargamiento del reloj es una buena idea. Funcionaría.

El problema con eso es que parte del módulo I2C necesitaría ejecutarse a "velocidad de reloj completa". Ahora, el módulo I2C es agradable de bajo consumo porque normalmente no funciona a más de 200 kHz.

La razón principal de mi publicación fue lo que dije al principio de mi publicación original :

Estoy jugando con este problema ahora en un RPi 3 Modelo B +, y veo resultados diferentes a los que describe el artículo de Advamation. El silicio no se aceleró recientemente, ¿verdad?

Si tuvimos cambios significativos en el hardware o controlador I2C después de la redacción de Advamation de 2013 , y la comunidad sabe cómo pueden afectar este error, entonces debería hacer los cambios apropiados en mis experimentos.

Sé que el problema fundamental está en el hardware, pero por lo que sé, alguien puede haber descubierto mediante un experimento que cambiar un registro aparentemente no relacionado en el controlador en realidad cambia el comportamiento de este error. Tampoco he confirmado que el BCM2837 tenga el mismo módulo I2C que el RPi 2 (la última vez que pude encontrar una confirmación definitiva de que el hardware I2C no había cambiado desde que se informó por primera vez de este problema). Tampoco he encontrado ninguna información sobre ninguno de los pasos de BCM283x; Por lo que sé, podría haber habido un cambio de metal en la era BCM2836.

No me interesa criticar a Broadcom, especular sobre cómo pueden cambiar futuras revisiones, ni nada por el estilo.

Mi objetivo principal aquí es documentar claramente el comportamiento actual; parece que ha cambiado con el tiempo. Tengo un objetivo secundario: permitir que los usuarios futuros reproduzcan mis experimentos para ver si los resultados siguen siendo válidos o para realizar mejoras o probar otras condiciones. Tengo otro objetivo secundario: permitir que los ingenieros de Broadcom reproduzcan las pruebas fácilmente si así lo desean. Ambos significan que necesito publicar mis experimentos, lo que también ayuda: debido a mi propia arrogancia , si publico mis experimentos, estaré más motivado para hacerlos rigurosos.

Mi plan experimental actual es utilizar un PIC16F1619 como implementación esclava; es lo suficientemente rápido y versátil para hacer los experimentos de alargamiento del reloj, lo suficientemente fácil para trabajar y lo suficientemente común como para que otros experimentadores puedan reproducir mis resultados. Si los resultados son ambiguos, también podría construir un experimento con una FPGA. Podría ver si puedo obtener una granularidad razonable usando otra Raspberry Pi en una configuración de ataque de bits como esclava, pero sospecho que necesitaré algo sin un sistema operativo completo para hacer pruebas en tiempo real.

Para abordar otro par de cosas que surgieron:

Lamento que mi publicación original estuviera incompleta; Publiqué accidentalmente un borrador inicial. Lo dejaré como está, ya que los cambios que hice son bastante menores.

No pretendo originalidad sobre la idea de detener el divisor del reloj mientras SCL se mantuvo externamente bajo. Lo leí en otro lugar, pero no recuerdo dónde; Pensé que era de Gert van Loo en el reloj I2C estirando el hilo en raspberrypi.org , pero no puedo encontrarlo ahora, así que debo haberlo visto en otra parte. No estoy convencido de que cambie significativamente el perfil de potencia,

El bloque I2C HW no se ha arreglado / cambiado, y es poco probable que lo esté, en el bcm2835 / 6/7, ya que eso requeriría respins del chip, que es simplemente demasiado caro.

No sé quiénes son Advamation, pero no están relacionados con el grupo RPF (T), por lo que no puedo garantizar la precisión de los artículos.

Queridos todos, tengo un fenómeno muy extraño en mi Pi 2B y 3, trato de explicar:
cuando comencé a implementar el BNO055 a fines de junio, usé un Raspbian antiguo (ahora no tengo la versión) y obtuve muchas direcciones I2C no válidas usando i2cdetect. Para eso busqué en la red y encontré este foro con buena información. Para eso cambié la frecuencia I2C como se describió anteriormente y todos los fantasmas se desvanecen y puedo trabajar. A mediados de agosto actualicé Raspbian a creo que raspbi-dev 4.14.62-v7 + y el sistema se volvió un poco inestable, pero puedo trabajar. De una actualización a otra, el sistema se volvió más inestable, se observaron fugas en la tarjeta SD. Por lo tanto, reinstalé Raspbian a través de NOOBS (Linux raspbi-dev 4.14.62-v7 + # 1134 SMP Tue Aug 14 17:10:10 BST 2018 armv7l) y olvidé configurar la frecuencia I2C pero no aparecieron fantasmas. De acuerdo, no uso microcontrolador en el bus, solo MEMS y extensor GPIO, pero creo que hay una solución en el código i2c de Raspbian. Además, creo que las fugas detectadas provienen de una actualización imperfecta, estoy usando la misma tarjeta y no se detectan fugas.

@ hmf2015 Este problema se trata de un problema I2C muy específico. Los problemas con la tarjeta SD no son causados ​​por este problema I2C. Si su tarjeta SD no funciona correctamente, debe probar una nueva tarjeta SD. Algunas tarjetas no son buenas y dejan de funcionar rápidamente. Mi tarjeta SD dejó de funcionar el mes pasado y tuve que reemplazarla.

Por lo general, los fantasmas I2C no se deben a este problema. Ocurren con mayor frecuencia porque:

  • No tienes una buena fuente de alimentación. Me gusta este
  • Tus cables son demasiado largos. I2C no funciona bien con cables de más de 1 m.
  • Tus cables tienen acoplamiento capacitivo. Si tiene los pines I2C (SCL y SDA) entrelazados, eso puede crear un problema. A veces, la gente usa cables de par trenzado (como cables Ethernet) que tuercen los pines I2C y eso crea problemas. Si tiene que usar cables de par trenzado, tuerza SCL con Vss (tierra) y SDA con Vdd (3.3V). Mire la especificación I2C en la sección 7.5.
  • Su dispositivo I2C tiene 5V. La Raspberry Pi hace E / S a 3.3V. Si los voltajes son diferentes, eso puede causar problemas. (El BNO055 necesita 3,3 V, por lo que si lo está usando con 5 V, tiene un problema).

Dije que estamos hablando de un problema en particular. Algunos dispositivos pueden crear fantasmas debido a este problema, pero no muchos dispositivos. Si los dispositivos crean fantasmas debido a este problema, no crean muchos fantasmas. Creo que tu problema es diferente.

No sé a qué se refiere cuando dice que "notó fugas en la tarjeta SD". Ese es un problema importante, pero no es un problema del que hablamos en el número de esta página web. Esta conversación trata sobre un error en particular. Ese error no afecta a las tarjetas SD.

No creo que Raspbian reciente haya cambiado el funcionamiento de I2C. Creemos que Raspbian no puede solucionar este error. Podríamos estar equivocados. Gracias por contarnos sobre esto.

Si solo nos proporciona esta información para ayudarnos, se lo agradecemos. Si nos está brindando esta información para pedir ayuda, es posible que desee solicitarla en los foros de Raspberry Pi . Los foros hablan de muchas cosas, como I2C, tarjetas SD, extensores GPIO y muchas más cosas. Las cosas que está viendo pueden ser las mismas cosas de las que estamos hablando, pero pueden ser cosas diferentes. Las personas en los foros pueden ayudarlo a saber qué problemas está viendo.

¡Gracias por darnos esta información!

Gracias por la respuesta, pero el problema de la tarjeta SD fue producido por el O / S, revisé la tarjeta en mi host (Unix) y estaba bien, y ahora el mismo cad funciona perfectamente después de la nueva instalación.
Los fantasmas en el bus I2C se desvanecen por una frecuencia más alta y ahora, después de la reinstalación, no aparecen, los problemas de R / C y los reflejos que puedo, creo, excluir. Conozco los problemas de 3.3V, pero el nivel mínimo 1 es menor.
El paquete BNO055 tiene un regulador de voltaje.
También pensé que los problemas de I2C serían los mismos que antes, pero no es así, en este momento no tengo el tiempo (y el interés) de mirar el código fuente de Raspbian para detectar las diferencias, me interesa en un entorno de trabajo.
La lista de elementos solo debería mostrar que estoy trabajando en un entorno Andoid (con un Unix real) como admite BCM, no con un microcontrolador lo que conecto a través de una línea serie o USB ya que soy vago. En su entorno las condiciones son más restrictivas que las mías, por lo que no puedo decir si sus problemas disminuyen, pero espero.

Hola hmf2015,
Este no es un foro. Este es un rastreador de errores. Esta lista de comentarios analiza un error que no está relacionado con sus problemas. Discuta su problema con un foro o servicio de ayuda adecuado. Una vez más, agradecemos su pregunta: "¿Quizás es lo mismo? ¿Quizás mi descripción ayude a resolver ese error?" pero ahora sabemos con certeza que lo que está viendo no está relacionado, por favor no "contamine" esta discusión más.

@palomitasmix
hola, hace mucho tiempo mencionaste un problema con la máquina de estado I2C durante el reinicio y publicaste un código relacionado con este problema.
No estoy seguro de lo que quiso decir, pero tengo un problema con el códec WM8731 conectado a I2C.
Después de 2-3 reinicios, el bus I2C se cuelga por completo. i2cdetect no muestra ninguna información excepto la 1ª línea y también cuelga. La única forma de recuperarse es el ciclo de apagado / encendido.
¿Parece esto uno de los problemas que ha mencionado?
Estoy usando el kernel principal 4.19.

@ sergey-suloev Cuando i2cdetect no continúa escaneando después de 8 o 16 direcciones, diría que esto no está relacionado con este problema. El problema surge cuando los dispositivos se alargan el reloj para indicar que aún no están listos para el siguiente ciclo de reloj. Cuando se diseñó I2C hace casi 40 años, eso también podría haber sido concebible para implementaciones de hardware. Pero hoy en día, el hardware siempre está listo a tiempo para manejar el siguiente ciclo de reloj porque 10 microsegundos son siglos de tiempo para algo implementado en hardware.

¿Fue útil esta página
0 / 5 - 0 calificaciones