i2c en diferentes dispositivos de nivel lógico

Tengo un problema al hacer que LPC2148 funcione con el sensor SRF10. LPC es un dispositivo de 3.3v con i2c compatible con 5v (al menos el documento de usuario afirma eso). Por otro lado, hay un dispositivo SRF10 que es de 5v. He probado con ambos niveles como pull-up lvl conectado con una resistencia de 4.7k (tengo 3 dispositivos en la misma línea, así que usé una resistencia de mayor valor).

Lo extraño es que a veces lee el valor correctamente pero falla al leer valores de 2 registros... Básicamente, no funciona.

Mala lectura de I2c

Ahora, lo que es extraño en esta imagen, es que el nivel lógico en SDA es 0 por defecto y debería ser 1. ¿Eso significa que pull-up no está haciendo bien el trabajo? ¿Podría estar relacionado con las diferencias de nivel lógico entre uc y esclavo?

EDITAR: 01.03

Aquí está mi implementación del estado 0x50, a_chn es i2c0 o i2c1

void slaveDataReceived (uint8_t a_chn)
{
uint8_t k;
volatile unsigned char *i2cConClear;
volatile unsigned char *i2cConSet;
volatile unsigned char *i2cData;

if (a_chn == 1) {
    i2cData = (volatile unsigned char *)(0xE005C008);
    i2cConClear = (volatile unsigned char *)(0xE005C018);
    i2cConSet = (volatile unsigned char *)(0xE005C000);
    }
else {
    i2cData = (volatile unsigned char *)(0xE001C008);
    i2cConClear = (volatile unsigned char *)(0xE001C018);
    i2cConSet = (volatile unsigned char *)(0xE001C000);
    }   

k = *i2cData;
appendToDataBuffer (a_chn, k);
if (i2cDataRcv[a_chn] == i2cDataHead[a_chn]){
    I2CMasterState[a_chn] = I2C_IDLE;
    *i2cConSet = I2CON_SET_STO;
    *i2cConClear = I2CON_CLR_AAC;
    }
else {
    *i2cConSet = I2CON_SET_AA;
    }
*i2cConClear = I2CON_CLR_SIC;   
}
Si está leyendo/escribiendo desde todos los dispositivos, excepto solo 2 registros de un dispositivo, eso debería indicarle que el bus i2c está funcionando correctamente, y posiblemente sea su código o el srf10 el que tiene errores. En cuanto a que el SDA sea bajo, no debería importar hasta que se intente una condición de inicio en su configuración maestra única. ¿Alguno de los otros dispositivos i2c no es tolerante a 5v? ¿La línea sube si coloca solo el LPC y el SRF10 en el bus y nada más? ¿Puede leer todos los registros con solo LPC y SRF en el bus?
Los tres dispositivos son de 5v y solo lpc es de 3.3v (pero tolerante a 5v). Intenté desconectar todos los dispositivos excepto uno y obtengo el mismo comportamiento. SRF está funcionando como lo probé en AVR (5v). SRF tiene 4 registros. Primero está la revisión, que pude leer y obtuve 5 como valor (que debería estar bien). El segundo no se usa pero devuelve 0x80 al leer. (también leído correctamente). Y los registros 3-4 tienen un valor de 16 bits. Leer esos registros devuelve valores extraños. (Tengo un entorno de "calibración" en el que probé los valores de lectura y concluí que son basura).
Desde la salida de su osciloscopio, ¿le está dando un retraso lo suficientemente grande? El guardabosques no responderá durante el alcance. Verifique su código para ver si puede encontrar por qué la salida SDA se mantiene baja antes de que se habilite la transmisión i2c, eso podría ser lo que está arruinando las cosas (pero en mi humilde opinión, no creo que sea un problema demasiado grande). Aparte de eso, alguien más podría intervenir.
Sé que entre el rango y la lectura se necesitan al menos 65 ms, he puesto 100 ms. Este bajo nivel antes y después de la lectura es algo extraño. Cuando uso pines SDA/SCL como GPIO y creo una señal cuadrada, todo funciona normalmente. Independientemente del pull-up que esté conectado a las líneas. La salida es de LA, no del alcance. Lo verifiqué también con el alcance y obtuve un nivel bajo como -0.3v y un nivel alto como ~ 3v.
Es probable que estos problemas superen las capacidades de un analizador lógico. Le recomiendo que use un osciloscopio para verificar las comunicaciones porque puede haber niveles lógicos muy marginales que generalmente funcionan y luego fallan.

Respuestas (1)

Veo condiciones válidas de inicio y reinicio en su forma de onda, por lo que no creo que SDA sea la 'polaridad incorrecta'. La condición de inicio válida está antes de escribir 0xC0 (indicado por el primer punto verde en la captura) y el reinicio válido es el segundo punto verde (antes de 0xC1). El hecho de que SDA permanezca bajo después de que el maestro ACK ACK del esclavo no debería ser un problema siempre que el maestro lo libere antes del próximo flanco ascendente de SCL.

Un problema podría ser el tamaño de los pull-ups. Si está tratando de operar a más de 100 kHz, es posible que necesite pull-ups más rígidos para asegurarse de que los bordes estén nítidos.

Otro problema es que el maestro debe NACK el último byte leído esperado, incluso si se trata de datos válidos, ya que muchos esclavos esperan un NACK antes de permitir que se produzca una condición de parada válida. Para sus lecturas de un solo byte, el maestro debe NACK el byte de datos. Para los registros de 16 bits, debe ACK el primer byte y NACK el segundo. He visto bastantes dispositivos esclavos colgar el bus o funcionar mal si la última lectura no es 'terminada' por un NACK.

He notado que LPC es ACK todo. Pero como dice la hoja de datos, NACK es el valor predeterminado. Borré explícitamente ACK en la interrupción de recepción del último byte, pero todavía lo ACK. Desde el nivel lógico, ¿el ACK es 1 o 0? ¿Quizás porque mi SDA está bajo todo el tiempo, ACK está predeterminado? En ese caso, ¿el valor de pull-up es demasiado grande?
Creo que no hay posibilidad de que esto esté relacionado con el pull-up. Si desconecta el esclavo del bus, ¿ve NACK? (El maestro puede ser y reconocerse a sí mismo)
@Gossamer Acks son lógica 0 (la línea se baja activamente). Nacks son lógica 1 (se libera la línea, se utiliza pull-up). Si su frecuencia de reloj es demasiado rápida para el pull-up, eso podría ser un problema, pero de lo contrario tiene comunicaciones que funcionan utilizando ese pull-up.
Bueno, parece que tenía demasiados ACK en el código. Me guió la documentación de LPC21xx en la que afirmaban que casi todos los estados deberían establecer el bit ACK en el registro. También lo eliminé *i2cConSet = I2CON_SET_STO;del código en la publicación de la pregunta. Todos esos o algunos de esos cambios recientes en el código hicieron que i2c funcionara ahora. Ahora tengo que analizar qué causó exactamente los problemas al volver a habilitar el código anterior línea por línea.
¡Bien hecho! Sufrí un poco al escribir mi propio código maestro I2C y entiendo lo complicado que puede ser hacer que las cosas funcionen, especialmente en el lado del protocolo.