los esclavos interfieren cuando comparten la línea de bus i2c

Soy muy nuevo en microcontroladores y estoy usando PIC18F4620 (maestro) para comunicarme con el sensor de color TCS34725 (esclavo) y el reloj en tiempo real DS1307 (esclavo, integrado) a través de I2C. En este momento, estoy experimentando algún tipo de interferencia entre esos dos. Si ejecuto cualquiera de ellos individualmente sin que el otro esté conectado al puerto, entonces funciona bien. Si el otro está conectado sin siquiera haber sido inicializado, entonces se cuelga durante el proceso de lectura. Sus direcciones de esclavos no son las mismas, así que no veo por qué sucede esto. Este es el código para el sensor de color.

 /* Initialize LCD. */
initLCD();

I2C_Master_Init(100000); //Initialize I2C Master with 100 kHz clock

while(1){
    /*read the id */
    I2C_Master_Start();
    I2C_Master_Write(0b01010010);
    I2C_Master_Write(0b10010010);
    I2C_Master_RepeatedStart();
    I2C_Master_Write(0b01010011);
    id = I2C_Master_Read(NACK);
    I2C_Master_Stop();   
    __delay_ms(200);

    /* Configure the RGBC Time register */
    I2C_Master_Start();
    I2C_Master_Write(0b01010010);
    I2C_Master_Write(0b10000001);
    I2C_Master_Write(0);
    I2C_Master_Stop();
    __delay_ms(200);

    /* Configure the Control register */
    I2C_Master_Start();
    I2C_Master_Write(0b01010010);
    I2C_Master_Write(0b10001111);
    I2C_Master_Write(0);
    I2C_Master_Stop();
    __delay_ms(200);

    /* Configure the Control register */
    I2C_Master_Start();
    I2C_Master_Write(0b01010010);
    I2C_Master_Write(0b10000000);
    I2C_Master_Write(0b00001011);
    I2C_Master_Stop();
    __delay_ms(200);

    /* Read red data */
    I2C_Master_Start();
    I2C_Master_Write(0b01010010);
    I2C_Master_Write(0b10010110);
    I2C_Master_RepeatedStart();
    I2C_Master_Write(0b01010011);
    tmp[0] = I2C_Master_Read(ACK);
    tmp[1]= I2C_Master_Read(NACK);
    I2C_Master_Stop();
    __delay_ms(1000);
    rC = (tmp[0])|(tmp[1]<<8);

    /* Read green data */
    I2C_Master_Start();
    I2C_Master_Write(0b01010010);
    I2C_Master_Write(0b10011000);
    I2C_Master_RepeatedStart();
    I2C_Master_Write(0b01010011);
    tmp[0] = I2C_Master_Read(ACK);
    tmp[1]= I2C_Master_Read(NACK);
    I2C_Master_Stop();
    __delay_ms(1000);
    gC = (tmp[0])|(tmp[1]<<8);

    /* Read blue data */
    I2C_Master_Start();
    I2C_Master_Write(0b01010010);
    I2C_Master_Write(0b10011010);
    I2C_Master_RepeatedStart();
    I2C_Master_Write(0b01010011);
    tmp[0] = I2C_Master_Read(ACK);
    tmp[1]= I2C_Master_Read(NACK);
    I2C_Master_Stop();
    __delay_ms(1000);
    bC = (tmp[0])|(tmp[1]<<8);

    /* Display data on the LCD */
    __lcd_home();
    __lcd_clear();
    printf("id: %d", id);
    __delay_ms(500);


    __lcd_clear();
    printf("r:%u,b:%u", rC, bC);
    __lcd_newline();
    printf("g:%u", gC);
    __delay_ms(1000);

    id = 0;
    rC = 0;
    bC = 0;
    gC = 0;
}

Este es el código para RTC

void main(void) {
   /* Write outputs to LATx, read inputs from PORTx. Here, all latche (LATx)
    * are being cleared (set low) to ensure a controlled start-up state. */  
    LATA = 0x00;
    LATB = 0x00; 
    LATC = 0x00;
    LATD = 0x00;
    LATE = 0x00;

    /* After the states of LATx are known, the data direction registers, TRISx
     * are configured. 0 --> output; 1 --> input. Default is  1. */
    TRISA = 0xFF; // All inputs (this is the default, but is explicated here for learning purposes)
    TRISB = 0xFF;
    TRISC = 0b10000000; /* RC3 is SCK/SCL (SPI/I2C),
                         * RC4 is SDA (I2C),
                         * RC5 is SDA (SPI),
                         * RC6 and RC7 are UART TX and RX, respectively. */
    TRISD = 0x00; // All output mode on port D for the LCD
    TRISE = 0x00;

    /************************** A/D Converter Module **************************/
    ADCON0 = 0x00;  // Disable ADC
    ADCON1 = 0b00001111; // Set all A/D ports to digital (pg. 222)

    /* Initialize LCD. */
    initLCD();

    I2C_Master_Init(100000); //Initialize I2C Master with 100 kHz clock
    /* Set the time in the RTC.
     * 
     * To see the RTC keep time, comment this line out after programming the PIC
     * directly before with this line included. */

    RTC_setTime();

    /* Declare local variables. */
    unsigned char time[7]; // Create a byte array to hold time read from RTC
    unsigned char i; // Loop counter

    /* Main loop. */
    while(1){
        /* Reset RTC memory pointer. */
        I2C_Master_Start(); // Start condition
        I2C_Master_Write(0b11010000); // 7 bit RTC address + Write
        I2C_Master_Write(0x00); // Set memory pointer to seconds
        I2C_Master_RepeatedStart(); // Start condition
        I2C_Master_Write(0b11010001); // 7 bit RTC address + Read
        for(i = 0; i < 6; i++){
            time[i] = I2C_Master_Read(ACK); // Read with ACK to continue reading
        }
        time[6] = I2C_Master_Read(NACK); // Final Read with NACK
        I2C_Master_Stop(); // Stop condition

        /* Print received data to LCD. */
        __lcd_home();
        printf("%02x/%02x/%02x", time[6],time[5],time[4]); // Print date in YY/MM/DD
        __lcd_newline();
        printf("%02x:%02x:%02x", time[2],time[1],time[0]); // HH:MM:SS
        __delay_ms(1000);
    }
}

void RTC_setTime(void){
    /* Writes the happynewyear array to the RTC memory.*/

    I2C_Master_Start();           // Start condition
    I2C_Master_Write(0b11010000); //7 bit RTC address + Write
    I2C_Master_Write(0x00);       // Set memory pointer to seconds

    /* Write array. */
    for(char i=0; i<7; i++){
        I2C_Master_Write(happynewyear[i]);
    }

    I2C_Master_Stop();            //Stop condition
}
¿Qué valor tienen sus resistencias pullup I2C? ¿Tiene un osciloscopio o un analizador lógico simple que pueda usar para observar el bus? ¿Qué sucede si ni siquiera realiza ninguna transacción, sino que simplemente mide el voltaje del bus con un medidor? Cuando tiene un dispositivo conectado pero sin usar, todavía le está dando energía, ¿verdad?
@ChrisStratton: el rango PIC18F tiene pullups internos que creo que son ~ 40k, que presumiblemente es lo que se usa aquí dada la ausencia de mención de pullup externo. Si este es el caso, entonces esta pregunta es potencialmente un duplicado de electronics.stackexchange.com/questions/1849/… (la respuesta es: menor resistencia)
@ChrisStratton Las resistencias pull up están preconstruidas en la placa de desarrollo que estoy usando, que es de 10k. No tengo acceso a un osciloscopio rn, pero puedo usarlo el lunes. Sí, todavía le doy poder al dispositivo sin usar.
@Jules Sí, hay pullups internos, pero creo que el valor es de 10k aunque.
10K es un poco grande. Intente al menos como un experimento agregando 2.2K también, o al menos 4.7K.
Según la fórmula en electronics.stackexchange.com/questions/1849/… , 10k solo sería apropiado para capacitancias de hasta aproximadamente 100pF, que podría alcanzar fácilmente con un par de dispositivos, especialmente si está conectando módulos separados con alambres razonablemente largos. Para un sistema de 5v, la resistencia mínima es de aproximadamente 1,6k. Probar 2.2k definitivamente sería sensato.
¿Por qué dice "TCS34725 (esclavo) y DS1307 (esclavo, a bordo)" ? ¿Eso significa que el TCS34725 no está en la misma placa, pero está conectado a través de cables? ¿Qué longitud tienen los cables, entonces?
recomendación contra el uso de pull-ups internos para I2C: ¿ Qué sucede si omito las resistencias pullup en las líneas I2C?
Dos piezas de información arrojarían luz sobre su problema: (1) El esquema. Si no tiene acceso a un paquete EDA, un boceto a lápiz servirá. Pero una foto de la protoboard no serviría. (2) Captura de pantalla del osciloscopio de la transacción I2C cuando el bus no funciona. Otra captura de pantalla del osciloscopio para la transacción I2C cuando el bus funciona.
@ChrisStratton Muchas gracias, resolví el problema agregando 1k pull ups.
Gracias a todos, resolví el problema agregando 1k pull ups.
@sop: No, acabas de crear otro problema que aparentemente aún no te ha afectado. Deja de adivinar y hurgar al azar en las cosas. Deténgase y comprenda realmente lo que está sucediendo, lo que hace cada parte y qué límites hay en la especificación. Le han hecho una serie de preguntas, la mayoría de las cuales no ha respondido. Este sitio web funciona en ambos sentidos. Los voluntarios aquí ayudarán, pero también queremos comprender finalmente cuál era realmente el problema, cómo se resolvió finalmente, etc. Una vez que responda las preguntas que le hicieron, puedo explicarle qué otro problema ha creado ahora.

Respuestas (1)

No miré el código porque, por un lado, es un montón de llamadas de alto nivel sin mostrar lo que realmente sucede a nivel de bus.

Sin embargo, esto es probablemente un problema eléctrico. Posiblemente el segundo esclavo cargue las lineas de bus para que algo no funcione. No has dicho nada sobre la tasa de bits o los pullups. Esos importan. Tal vez los pullups tienen una impedancia demasiado alta y/o está tratando de usar una tasa de bits demasiado rápida. Mire las líneas con un alcance y vea lo que realmente está sucediendo. Asegúrese de que cada línea suba, que llegue allí sólidamente en un poco de tiempo.

Muchas gracias, resolví el problema agregando 1k pull ups.