8 votos

¿Cómo se establece la frecuencia de reloj entre el maestro y el esclavo en el protocolo I2C?

Esta es una pregunta de seguimiento de ¿Qué ocurre si omito las resistencias pullup en las líneas I2C?

En un reloj de pared digital que diseñé (usando el RTC DS1307 y el MCU ATmega328), accidentalmente omití las resistencias pull-up que deben ser conectadas a ambas líneas I2C. Al final tuve la suerte de que los pull-ups internos en las líneas I2C del ATmega eran suficientes para (apenas) permitir la comunicación entre los dispositivos. El resultado fueron largos tiempos de subida en las líneas I2C y reducción de la velocidad a 32kHz como se ve en las tomas de alcance de abajo.

Editar: En realidad, la frecuencia es exactamente de 100kHz - hay 2 picos por 20us en la traza verde. Al principio pensé que había una reducción a 32kHz porque mi osciloscopio calculaba la frecuencia en la traza amarilla.

Scope shot 1 Scope shot 2

Lo que me desconcierta ahora es cómo los dispositivos decidieron que 32kHz era suficiente para que la comunicación tuviera lugar. El Hoja de datos del DS1307 dice que el dispositivo soporta una frecuencia de 100kHz en el bus I2C. ¿Cómo es que terminó usando 32kHz en su lugar? ¿Existe algún tipo de fase de apretón de manos en la que se establece la frecuencia?

Al final, mi pregunta es realmente esta: ¿Cómo se establece la frecuencia de reloj entre el maestro y el esclavo en el protocolo I2C?

No he podido encontrar esa información buscando en la red.

En caso de que esto importe, estoy usando Arduino IDE 1.03 y mi firmware maneja el RTC usando el DS1307RTC Arduino lib (a través de sus funciones RTC.read() y RTC.write() ). Esta librería utiliza a su vez Wire.h para hablar con el RTC.

4 votos

El estándar para I2C es aquí

1 votos

¿No podría ser que usted codificara arbitrariamente esa frecuencia sin saberlo?

0 votos

@Warren Esa referencia es realmente útil, gracias. No pude conseguir que Google me llevara a LA ESPECIAL. En cambio, me llevó al artículo de Wikipedia y a otros documentos tangenciales. Aun así, no pude entender cómo se determina la velocidad. Creo que lo que quiero saber está en la sección 3.1.7 Sincronización del reloj Pero agradecería mucho que alguien me lo explicara en términos más sencillos, ya que todavía está un poco por encima de mi cabeza.

5voto

Alex Andronov Puntos 178

Para que se produzca un flanco de reloj ascendente en I2C, el maestro debe afirmar el reloj, lo que puede hacer que algunos esclavos se unan para afirmarlo también, y luego el maestro y todos los esclavos deben coincidir en liberar el reloj. Hasta que todos los dispositivos liberen el reloj, éste permanecerá afirmado y todos los dispositivos verán que está afirmado.

Una vez que cada dispositivo ha liberado el reloj, entonces cada dispositivo esclavo "rearmará" el circuito de retención del reloj a menos que o hasta que esté listo para el siguiente flanco ascendente [algunos dispositivos están siempre "listos" para los flancos ascendentes tan rápido como el maestro puede enviarlos, y por lo tanto no necesitan un circuito de retención del reloj en absoluto; otros pueden saber a veces que no estarán interesados en ningún flanco ascendente hasta que aparezca la siguiente condición de inicio, y no rearmar su circuito de retención del reloj hasta entonces]. Cuando el maestro ve que el reloj se libera, espera un tiempo mínimo para asegurar que cualquiera que necesite rearmar un circuito de retención de bus tenga la oportunidad de hacerlo, y entonces reafirmar el reloj y asegurar que se mantiene el tiempo suficiente para permitir que cualquier circuito de retención de bus armado se una para mantenerlo. El ciclo puede entonces repetirse.

Los dispositivos esclavos no suelen tener una velocidad mínima de funcionamiento, pero sí una máxima. Algunos dispositivos sincronizan toda su lógica I2C a un reloj interno, por lo que pueden requerir uno o dos ciclos para armar o activar su circuito de retención de reloj. Además, el I2C requiere que los dispositivos determinen con un 100% de fiabilidad si los bordes del cable de reloj se producen antes o después de los bordes del cable de datos; dado que los cambios en la línea de datos suelen producirse casi inmediatamente después de la caída de los bordes del reloj, los dispositivos pueden añadir un cierto retraso en el momento en que perciben los cambios en la línea de datos. Esto requiere añadir un retardo entre cualquier momento en que el maestro cambie su salida de datos y el momento en que suba su reloj. Siempre que todos los dispositivos cumplan con su requisito de retardo mínimo, el maestro puede retrasar todo lo que quiera; sin embargo, cuanto más se retrase el maestro, más tiempo tardará en enviar los datos.

4voto

mk117 Puntos 113

Siguiendo con los comentarios:

Sí, la frecuencia está codificada en algunos registros específicos relacionados con I2C. En tiempo de ejecución.

Dicho esto, su biblioteca Arduino puede hacer algunos sondeos y mediciones del tiempo de subida en el bus para determinar una velocidad de reloj viable. Veamos.


Después de investigar un poco el código fuente, la respuesta está en twi.h

#ifndef TWI_FREQ
#define TWI_FREQ 100000L
#endif

Otra pieza de ese mismo archivo:

TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2;

Dónde TWBR significa Registro de velocidad de transmisión de dos hilos Sospecho.

Yo diría que eso es evidencia suficiente y definitivamente diría que sí, que su frecuencia I2C es fijada directamente por su librería sin ninguna negociación. Si quieres cambiarlo, te sugeriría que #define TWI_FREQ antes de #incluir twi.h (o indirectamente a través de Wire.h)

1 votos

_"Si quieres cambiarlo, te sugiero #undef y #define en TWI_FREQ después de incluir Wire.h"_ No, eso es incorrecto. La forma twi.h está escrito, debe #define su costumbre TWI_FREQ antes de usted #include twi.h . (¿Y qué tiene que ver "Wire.h" con todo esto?)

0 votos

En realidad, la frecuencia siempre ha sido exactamente 100kHz - hay 2 picos por 20us en la traza verde. Inicialmente pensé que había una reducción a 32kHz porque mi osciloscopio calculaba la frecuencia en la traza amarilla. Esto hace que tu respuesta sea correcta. ¡¡¡Gracias!!!

3voto

Passerby Puntos 28913

De La Sitio web de Arduino - Referencia detallada de la biblioteca de cables :

La llamada twi.init() es interna a la biblioteca Wire. Realiza las siguientes tareas: establece la frecuencia de reloj que el hardware TWI utilizará si/cuando es el maestro en el bus I2C. Se establece en el código fuente a 100kHz, pero teóricamente al menos puedes reajustar esta frecuencia redefiniendo TWBR antes de llamar a Wire.begin(), eg: TWBR=400000L debería ponerla a 400kHz.

La biblioteca RTC que se utiliza no cambia TWBR. Otra cosa que estés usando puede haberla cambiado. O el largo y lento tiempo de pull-up de los súper débiles pull-ups internos han causado efectivamente que el motor i2c del ATMega sea más lento. El motor comprueba si la línea es alta o baja antes de cambiarla.

Dicho esto, la frecuencia de reloj i2c es arbitrario Hasta la frecuencia máxima soportada por cualquier dispositivo en el bus (y tal vez algunas decenas de Hz más). Un poco más rápido y empezarás a tener problemas de lectura y escritura. Algunos dispositivos tienen frecuencias mínimas antes de que se agoten, pero he visto dispositivos de 400khz trabajar a 10khz. La velocidad del reloj la decide únicamente el maestro (es decir, tú, el codificador).

Hay una opción para estirar el reloj por parte del esclavo (mantiene la línea de reloj baja hasta que esté listo, y la especificación i2c requiere que el maestro compruebe esto), pero las imágenes del alcance no parecen indicar que esto está sucediendo aquí.

Si añadieras unos pullups externos adecuados, sin cambiar ningún código, deberías ver que la frecuencia se acerca más a los 100kHz que la Wire Library define como estándar

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X