El bus I2C se bloquea en un solo maestro - Sistema de un solo esclavo

Estaba tratando de desarrollar una función de controlador I2C para leer datos de un sensor de proximidad (Cypress CY8CMBR3102) e inicialmente la función funcionó muy bien y con éxito. Pero mientras lee continuamente datos del dispositivo, el esclavo mantiene baja la línea SDA y el indicador de arbitraje del bus se establece en la MCU (NXP MKE04Z64). Esto está bloqueando toda comunicación futura.

Intenté la siguiente solución en mi código, pero no funcionó.

  • Cada vez que quiero leer desde el dispositivo, mantengo los pines I2C como GPIO y verifico el nivel en el bus de datos.

  • El módulo I2C se habilitará solo si el bus de datos está en estado alto.

  • Si el bus se mantiene bajo, el pin SCL se registra como un GPIO hasta que el esclavo libera SDA.

Cuando probé la solución anterior en el dispositivo, el código se atasca en el bucle donde cronometro el pin SCL hasta que SDA vuelve a estar alto. Lo que significa que sincronizar SCL no ayuda a liberar el bus del esclavo.

Sin embargo, si desenchufo el esclavo o realizo un reinicio de energía, el bus se libera ya que el esclavo se está reiniciando.

Sigo sin poder encontrar la causa de este problema. Supervisé las líneas usando un DSO y no encontré ningún ruido significativo en las líneas.

1. ¿Cuál podría ser la posible razón de este bloqueo de autobús?

2. ¿Cómo detectar y recuperar una vez bloqueado el autobús?

Los detalles de nuestra configuración son los siguientes:

-> Maestro único - Esclavo único

-> Maestro - NXP MKE04Z64 Brazo Cortex M0+

-> Esclavo - Controlador de proximidad Cypress CY8CMBR3102 Capsense

-> Reloj I2C de 400 KHz

-> Los pines MCU son de drenaje abierto con pull-ups externos de 4.7K.

-> Maestro y Esclavo están en tableros separados interconectados con un cable de 6 cm de largo.

Además, la hoja de datos destaca la función "Sin paradas de bus ni alargamiento del reloj durante las transacciones", lo que significa que el sensor debería funcionar sin problemas... si el maestro sigue las reglas, por supuesto. Tiene amplia información sobre los requisitos de tiempo. ¿Seguiste todas las pautas? Especialmente "tiempo libre de bus" y la posibilidad de que el dispositivo responda NACK cuando se encuentra en transición entre estados.
Sí, hice el firmware de acuerdo con las instrucciones dadas en la hoja de datos. Supongo que el esclavo ni siquiera ACK una vez si hay un problema de sincronización con el sistema. El Esclavo está respondiendo muy bien durante algún tiempo después de encenderlo. El momento en que el autobús se bloquea es totalmente aleatorio. Eso puede suceder después de un minuto, 1 hora o incluso puede funcionar sin problemas por tiempo indefinido. Todavía no sé la causa.
Deberá tener una ruta para hacer un reinicio de hardware del periférico (si es posible) o, de lo contrario, deberá identificar el conjunto de condiciones que causan esto y evitarlas. Podría valer la pena algún tipo de fuzzing automatizado combinado con una prueba para esta condición atascada para ver si puede encontrar una causa repetible. Compruebe también las erratas conocidas y póngase en contacto con los ingenieros de aplicaciones del proveedor. Si es posible, elija modos sin bloqueo en los que active una lectura y regrese más tarde para sondear los resultados, en lugar de cualquier modo que se detenga hasta que termine.
¿Cómo funciona la "lectura continua de datos"? No puede leer datos indefinidamente. En algún momento, debe enviar la condición de parada y restablecer el puntero de datos. Y lo más importante, cada operación debe comenzar con la dirección y repetir la condición de inicio hasta que el esclavo ACK. La mayoría de las bibliotecas de firmware de MCU que he visto no admiten este comportamiento de fábrica. Finalmente, debe usar la función HI para leer el sensor solo cuando sea necesario, sin sondear los mismos datos una y otra vez.
@Maple Por "Leer datos continuamente" quise decir que estoy ejecutando la secuencia de lectura varias veces con las condiciones y tiempos de INICIO Y DETENCIÓN adecuados. Déjame verificar sobre la función HI que estás diciendo.
@ChrisStratton Tienes razón, la única opción que me queda es tomar el control del poder del esclavo para hacer un reinicio de energía cuando está bloqueado. Pero no creo que sea un método confiable para implementar en un producto comercial. He registrado una queja en Cypress support. Déjame ver si puedo hacer algún otro método que no sea el sondeo de datos una y otra vez.
Tenga en cuenta que desconectar el esclavo por sí solo probablemente no funcione; también debe bajar ambas líneas I2C al mismo tiempo para evitar fugas de corriente a través del reloj desde la resistencia pullup que alimenta el chip lo suficiente como para retener el estado problemático. Y deberá asegurarse de que las tapas de los filtros de suministro realmente se descarguen por completo, no solo para caer a alrededor de 0.8v donde la corriente consumida cae a cero sin necesariamente borrar el estado.

Respuestas (1)

Parece que esto tuvo algo que ver con mi MCU maestro (NXP MKE04Z64) . Profundicé un poco más en los viejos foros de NXP y descubrí que muchas personas tenían el mismo problema de bloqueo del bus I2C de los MCU Kinetis E Series y NXP aún no ha respondido. Tal vez algo esté mal con el diseño del chip. Intenté GPIO golpeando el mismo esclavo en lugar de usar el módulo I2C y el problema se resolvió. También intenté conducir el mismo esclavo desde otro MCU donde funcionó muy bien.