Comunicación I2C con AVR: ¿cómo dejar que las líneas “floten”?

3

Estoy intentando implementar I2C utilizando un controlador AVR sin los registros TWI internos designados.

El protocolo I2C requiere que el dispositivo maestro maneje las líneas SDA y SCL para comenzar con el fin de abordar y comenzar una transacción de comunicación. El problema que tengo es que después de que se envía una dirección a través de la línea serie, debe dejar que la línea de datos "flote" (es decir, que el resistor de pull-up la coloque hacia arriba) para que el esclavo pueda bajar la línea para una señal ACK.

Soy capaz de abordar con éxito el dispositivo I2C, pero cuando intento que la línea "flote" tengo un poco de problema. Tenía la impresión de que en un estado de entrada ALTO-Z (tri-estado que es - DDRX 0, PORTX 1 para un pin en particular) esencialmente se modelaría como:

Sinembargo,elestadodelalíneaSDAsiguesiendoalto,apesardequeeldispositivoI2CestárespondiendoconunbitACKalreducirlalínea.Séqueestoesciertoporqueestablezcounretrasoconsiderabledespuésdeconfigurarelpincomoentrada.Duranteesteretraso,lalíneasemantienealta.Sinembargo,siquitoelcablequeatalaMCUalalíneaSDA,caeráaBAJOdebidoaldispositivoesclavo.

Enresumen,¿cómomanejael"soltar" de una línea para asegurarse de que su potencial esté controlado por los dispositivos en su línea de datos I2C en lugar de ser influenciado por la MCU?

/* Pin and direction register manipulations */ 
#define I2C_CLKDEL              10 //10uS
#define I2C_PORT                PORTB
#define SDA                     PB0 
#define SCL                     PB1
#define set_high(port, pin)     (port    |=  (1<<pin))
#define set_low(port, pin)      (port    &=  ~(1<<pin))
#define set_in(portDDR, pin)    (portDDR &=  ~(1<<pin))
#define set_out(portDDR, pin)   (portDDR |=  (1<<pin))

void clkStrobe(void){
    set_high(I2C_PORT, SCL); 
    _delay_us(I2C_CLKDEL); 
    set_low(I2C_PORT, SCL); 
    _delay_us(I2C_CLKDEL);
}

uint8_t sendByte(uint8_t byte){ //MSB first
    uint8_t count = 8, ack; 
    set_low(PORTB, SCL);  

    while( count-- ){
        if( byte & 0x80 )
            set_high(PORTB, SDA);
        else
            set_low(PORTB, SDA); 
        byte <<= 1;
        _delay_ms(I2C_CLKDEL); 
        clkStrobe();  
    }
    //set as input and read in the I2C port data
    set_in(I2C_PORT, SDA);
        _delay_ms(1000); 
    ack = PINB;  
    set_out(I2C_PORT, SDA); 
    clkStrobe();    //clock in the ACK bit 

    return (ack & (1<<SDA)); //return ACK bit 
}

Se insertó un gran retraso después de que se estableció SDA en la MCU como entrada para la prueba. La línea sigue siendo alta. Si se quita la línea SDA de la MCU (el cable ya no está conectado), la línea SDA es controlada por el dispositivo I2C al que se dirige (el dispositivo está enviando ACK). Claramente estoy haciendo algo mal aquí.

    
pregunta sherrellbc

1 respuesta

2

Para set_in, estás pasando I2C_PORT , que es PORTB , pero necesitas pasar DDRB .

    
respondido por el microtherion

Lea otras preguntas en las etiquetas