I2C: ¿Es legal un inicio repetido entre diferentes direcciones de esclavos?

Estoy escribiendo código I²C para una aplicación en la que solo tengo un maestro, pero varios esclavos. En todas las hojas de datos que he leído (no solo para este proyecto), la condición de inicio repetido solo se usa para cambiar entre escribir y leer y escribir en/desde el mismo esclavo o viceversa. Por supuesto, esas hojas de datos no mostrarían otros esclavos (¿por qué deberían hacerlo, de todos modos?).

¿Es legal omitir la condición de parada entre transferencias a/desde diferentes esclavos?

¿Algunos esclavos se comportan mal cuando se direccionan después de una condición de inicio repetida, después de que se hayan direccionado antes a diferentes esclavos?

Sé que la segunda pregunta no puede responderse con seguridad con un "no", pero si alguno de ustedes tuvo problemas en una situación así antes, eso es suficiente para mí.

Respuestas (3)

La condición de inicio repetido se agregó a la especificación para permitir que un maestro en una configuración de maestro múltiple mantenga el control sobre el bus mientras inicia una nueva operación. También funciona en una configuración de un maestro, como se puede ver en la página 9 de la especificación : la condición de inicio repetido se describe en una descripción general, por lo que funciona para ambos modos. Además, después de una condición de inicio repetida, la dirección se envía nuevamente, por lo que también debería funcionar al cambiar la dirección.

Sin embargo, no es muy común, por lo que algunos esclavos (aunque nunca he visto uno, pero Michael Karas lo ha dicho en su respuesta ) podrían esperar una condición de parada, lo que podría causar problemas al omitir la condición de parada. Por lo tanto, le recomendaría que incluyera la condición de parada solo para estar seguro, aunque su implementación no sería "incorrecta" siguiendo la especificación. Una condición de parada no cuesta tanto tiempo.

Sé que la condición de parada no cuesta mucho tiempo; el fondo está más orientado a la implementación. Estoy escribiendo un código I2C controlado por interrupciones para un AVR, y tener que insertar paradas tiene un impacto en la implementación.
Ya veo, buen punto. La respuesta sigue siendo la misma: debería funcionar, siguiendo la especificación.
@Christoph: Entonces, el problema raíz parece ser una arquitectura mal pensada en cuanto a lo que sucede en el código de interrupción, lo que hace el primer plano y cómo la aplicación interactúa con todo. No hay una razón legítima por la que no puedas enviar una parada al final de cada mensaje.
@Olin: Aún no está pensado, por lo que aún no puede estar mal pensado. ¿Cómo es posible que la inserción de condiciones de parada al final de cada operación no tenga un impacto en la implementación en comparación con no insertar una parada y enviar un inicio repetido? La implementación será diferente.
La pregunta es cuánto impacto tendrá. @OlinLathrop dice que cuando el impacto es grande, su implementación está mal pensada, por lo que la implementación debería ser de esa manera que agregar una condición de parada no sería tan difícil de agregar a la implementación.
Michael y usted han hecho la misma declaración básica. Aceptaría ambas respuestas, pero desafortunadamente no puedo.

Mi recomendación es terminar siempre cada transacción con cada dispositivo con una secuencia de parada. Tendrá muchas más posibilidades de éxito al hablar con varios tipos de dispositivos alternativos que intente conectar en el futuro.

Específicamente, he visto dispositivos que se comportan mal cuando falta una parada al final de la transacción.

De hecho, hubo un trabajo que hice, hace algunos años, diseñando algunos dispositivos esclavos en piezas tipo FPGA. Me pareció esencial decodificar la condición de parada y usarla para restablecer la máquina de estado de transacciones del esclavo. La razón principal de esto es que pueden suceder cosas extrañas en el autobús, cosas que el lado maestro del autobús ni siquiera esperaba que sucedieran. Cuando una operación en curso se corrompe por estas "cosas inesperadas", pueden surgir estragos de los que cuesta algo de trabajo recuperarse. La mejor estrategia de diseño para los dispositivos es que diseñen y utilicen la secuencia de parada para producir el restablecimiento de la interfaz. Cuando se sigue esta estrategia, el fabricante de dispositivos recibe muchas menos llamadas de soporte y un lote de clientes más satisfecho.Red de 2 C que consta de un par de secuencias START -> STOP. Esto se puede utilizar en el software del controlador de nivel superior del lado maestro como parte de un bucle de reintento cuando las comunicaciones del dispositivo han fallado por una razón u otra.

Si investiga en la web, puede encontrar ciertas notas de aplicaciones que describen varios tipos de esquemas de "reinicio de bus" I 2 C involucrados que intentan recuperar dispositivos que se han colgado debido a eventos inesperados en el bus. Algunos de estos incluyen hacer secuencias de inicio y parada con 9 o 27 ciclos de reloj en el medio. Otros han mostrado cómo conectar la energía al dispositivo objetivo usando un FET en la línea Vcc para efectuar un "restablecimiento interno" en el dispositivo esclavo.

Si todos diseñaron para simplemente restablecer la secuencia de parada, todos los problemas extraños de I 2 C que pueden ocurrir se pueden resolver de una manera simple sin tener que recurrir a esquemas como se explica en estas notas de la aplicación. He experimentado una gran mejora en la robustez de los dispositivos I 2 C más nuevos que utilizo en mis propios proyectos de diseño integrado. Esto es un gran alivio en comparación con los sensores de temperatura LM75 de hace 10-15 años que necesitaban activación de energía de sus pines Vcc para proporcionar un funcionamiento confiable O algunos DAC/ADC I 2 C de 8 bits sin nombre que requerían reinicios de recuperación de tipo relojes adicionales.

Entonces, basado en años de experiencia, quiero recomendar nuevamente que no intente hacer esta secuencia de inicio repetida / esquema de dirección cambiada. Siempre siga la secuencia más simple que haga el trabajo para un dispositivo I 2 C específico. Y asegúrese de que cada transacción finalice con una secuencia de parada y proporcione una función de reinicio de bus que sea un par de secuencias de inicio y parada.

Sé que probablemente hay muchos lectores aquí que están implementando software de comunicaciones I 2 C que está diseñado asumiendo que los dispositivos siempre funcionarán. Me gustaría señalar que hay una gran cantidad de aplicaciones integradas de misión crítica en las que esta técnica es inaceptable. Se hace necesario detectar todos los errores posibles en una transacción y luego agregar otra capa por encima de esto que incluye reintentos y recuperación de restablecimiento de bus intentado. Y finalmente, si el comportamiento crítico del producto depende del canal I 2 C que ha fallado, tome medidas cuidadosas para apagar el dispositivo de manera ordenada y segura.

Me gusta el diseño del protocolo I2C, pero mucho del hardware existente... no tanto. Parecería que hay una serie de cosas que el protocolo debería poder proporcionar, pero las implementaciones de hardware no pueden. Por ejemplo, no veo ninguna razón por la que no debería ser posible tener varios dispositivos esclavos I2C en el bus que responderían de manera sensata al comando "Obtener números de serie de 48 bits en orden numérico comenzando con XXXXXX" si se pudiera habilitar el hardware de arbitraje I2C en modo esclavo, y se vuelve a habilitar cada seis bytes. Aunque no se me ocurre ninguna implementación...
... excepto quizás para el 8749 (cuyo hardware I2C solo procesa un bit a la vez) que podría hacer tal cosa.
Olvidé mencionar: un par de inicio/parada no funcionará para restablecer el bus si se leen datos de un esclavo. Si, por ejemplo, una EEPROM en serie está leyendo una secuencia de ceros, entonces, durante ocho bits de cada grupo de nueve, mantendrá el SDA bajo; si el maestro no pulsa SCL suficientes veces para que el esclavo lo libere, no podrá emitir una parada/arranque. Además, muchas EEPROM y dispositivos similares ignorarán cualquier transacción que no termine con una secuencia de parada adecuada. Por lo tanto, a menudo es deseable asegurarse de que la secuencia utilizada para reiniciar el autobús no pueda confundirse con una parada legítima.

He estado escribiendo un software para un microcontrolador como maestro con varios dispositivos esclavos y quería estar seguro de que el maestro reconocía el caso cuando el esclavo no respondía.

Tenía un software ejecutándose y hablando con un esclavo, así que pensé en cambiar para usar una dirección diferente a la que ningún esclavo respondería. Accidentalmente usé esta dirección no válida en la etapa justo después de un inicio repetido donde el dispositivo se vuelve a direccionar en modo de lectura para que lea el contenido de su registro.

Resulta que, al menos para este dispositivo en particular, ignoró la dirección no válida y continuó con normalidad y recibí todos los datos habituales.

Mi conclusión provisional aquí es que los dispositivos I2C, una vez que la primera dirección ha pasado al bus, continuarán ignorando las transacciones o respondiendo a las transacciones hasta la siguiente condición de parada.