ATMEGA TWI / I2C Slave - ¿Cómo implementar el estiramiento del reloj?

Estoy programando un esclavo TWI basado en un ATMEGA644PV.

Está funcionando en general, el maestro puede enviar y leer datos del esclavo. Hasta ahora, todo bien.
Pero en algunas solicitudes de lectura, el esclavo requiere "más tiempo" para preparar los datos. Me gustaría utilizar la ampliación del reloj para hacer que el maestro espere hasta que los datos estén listos.

La ficha técnica de ATMEGA señala:

El Esclavo puede extender el período bajo de SCL bajando la línea SCL. Esto es útil si la velocidad del reloj configurada por el Maestro es demasiado rápida para el Esclavo, o si el Esclavo necesita más tiempo para procesar entre las transmisiones de datos.

Esto es exactamente lo que quiero, pero no entiendo cómo implementar esto en el nivel del controlador. No veo forma de indicarle al hardware esclavo I2C que no debe ACK de inmediato, sino que debe extraer el SCL durante un período de mi elección.

Por lo que obtengo, solo puedo decirle al esclavo que ACK o, bueno, no ACK en absoluto después de ser direccionado o de transferir un byte de datos.

¿Me estoy perdiendo algo obvio aquí? Esta es la primera vez que miro I2C desde la vista de un esclavo.

Respuestas (2)

Los procesadores Atmel Atmega (incluido el Atmega644) realizan automáticamente la ampliación del reloj cada vez que la interfaz I2C necesita que el software realice una acción.

Esta acción podría ser cuando un esclavo ha recibido un byte de datos y los datos deben eliminarse del registro de datos antes de que se pueda recibir el siguiente byte o cuando se necesitan datos para transmitir. Ocurre cada vez que se establece la bandera TWINT.

La hoja de datos no destaca mucho el hecho, pero se menciona en algunos lugares (como en la sección 19.5.5 en la página 207 en la hoja de datos del 12/02).

Solo tengo la hoja de datos del 9/2015, pero creo que encontré lo que quieres decir. "Mientras la bandera TWINT está configurada, el período bajo de SCL se extiende". Me perdí totalmente ese. Y dado que la bandera siempre debe borrarse manualmente, esto tiene sentido. Entonces, después de recibir el direccionamiento SLA+R, creo que implementaré una devolución de llamada de mi controlador para llenar el búfer de salida ANTES de borrar la bandera. Gracias por la indicación, sabía que era algo más o menos obvio.

Consulte el siguiente esquema para ver la interfaz más utilizada entre los dispositivos maestro y esclavo I2C. Esta interfaz no utiliza la ampliación del reloj. El maestro genera todas las señales de reloj en SCL con SW2 (y el esclavo solo recibe estas señales de reloj).
Los datos se pueden transferir en ambos sentidos : de maestro a esclavo con SW1 o de esclavo a maestro con SW3. Por supuesto, ambos extremos deben ponerse de acuerdo sobre quién puede controlar la línea de datos SDA, para evitar colisiones. Por "control", me refiero a que el interruptor está cerrado, cortocircuitando la línea de datos a tierra. Un interruptor abierto permite que la línea SDA se eleve hasta el voltaje de suministro a través de la resistencia pull-up. Un interruptor cerrado tiene el "control" de la línea SDA, tirando de ella a tierra (bajo). Un bus inactivo tiene todos los interruptores abiertos.

esquemático

simule este circuito : esquema creado con CircuitLab En el esquema anterior, el maestro cronometra SW2 a una velocidad de 100k ciclos por segundo (o 400k para alta velocidad), esperando que el esclavo se mantenga al día. En un sistema de reloj extendido, el maestro inicia un ciclo de reloj cerrando SW2 y abre SW2 poco tiempo después (que normalmente terminaría ese ciclo de reloj). Pero monitorea la línea del reloj con BUF4 para ver si R2 realmente ha retrocedido al estado inactivo alto. Si el interruptor esclavo SW4 mantiene la línea de reloj baja, eso es un estiramiento de reloj, retrasando más transferencias de datos:

esquemático

simule este circuito Un dispositivo esclavo muy a menudo no tiene forma de realizar un estiramiento de reloj, porque SW4 no existe, o si existe, no hay forma de cerrarlo. Pero cualquier microcontrolador tiene pines GPIO que pueden hacer la función SW4: bajar a tierra. La temporización de SW4 es crítica: se debe bajar solo mientras SW2 también baja, para hacer la función de extensión del reloj esclavo. Entonces, el pseudocódigo para controlar el pin GPIO (SW4) en el esclavo es así:
Initialize GPIO pin to be an input (read). When Slave must clock-stretch, continually monitor GPIO pin, looking for "low". While SCL is low, change GPIO to be output pin, set to logic "0". Keep low until Slave is ready to continue. Once Slave is ready, change GPIO to be input, clearing the clock-stretch.

la transferencia de bits de datos ACK o NACK se usa principalmente para garantizar que el maestro y el esclavo estén vivos y sincronizados.

Gracias por la respuesta. Pero estoy usando el módulo TWI de hardware Atmega. Esto anula la funcionalidad GPIO de los pines, por lo que no tengo control directo sobre ellos. La pregunta era más sobre cómo usar/decirle al módulo TWI que quiero estirar el reloj. Soy consciente del principio general.
@Rev1.0 Puede usar cualquier pin GPIO como la camilla de reloj desplegable: no tenía la intención (y no le aconsejaría) de usar el pin de reloj I2C como ese GPIO. Use un pin GPIO diferente.
Sí, probablemente sería posible usar un GPIO separado. Sin embargo, ya resolví el problema según la respuesta de Kevin. La solución deseada era usar las funciones del módulo de hardware TWI para estirar el reloj, que ahora está funcionando. Gracias de cualquier manera.