I2C falla de lectura / escritura bajo carga de interrupción pesada

10

En mi sistema, estoy usando I2C y me doy cuenta de que bajo una gran carga de interrupción (de otras fuentes), la comunicación I2C se interrumpe fácilmente. ¿Es este comportamiento esperado para I2C? Hubiera esperado a pesar de la carga de interrupción, todavía estaría bien ya que I2C no es exactamente una interfaz de tiempo crítico, el reloj se proporciona con datos.

Actualizar:

El procesador es STM32. Las interrupciones se deben a ADC, no puedo desactivar las interrupciones durante los eventos de lectura, por lo tanto, debo encontrar una solución donde pueda hacer que la comunicación i2c sea más estable. El STM32 es maestro y el esclavo es otro dispositivo (acelerómetro).

Actualización2:

Cuando conecto un analizador lógico al reloj con un pequeño cable volador, el problema desaparece. Curiosamente, no hay carga de interrupción, leer y escribir funciona bien, cuando hay carga de interrupción, no lo hacen. Sin embargo, si conecto la sonda al reloj, leer y escribir también funciona bajo carga de interrupción. Creo que hay un problema de capacitancia en alguna parte.

Ktc
fuente
1
Su pregunta es muy genérica porque todo depende del diseño de su sistema. El manejo de I2C realmente depende de los dispositivos en el bus. ¿Puedes ignorarlos y pasar a lo posterior? En un FPGA, puede diseñar la lógica para cuidar mucho de usted y evitar esto. Nuevamente, necesitamos más información sobre el microcontrolador y qué otras cosas tiene. Por lo general, una buena solución aquí es usar un RTOS y diseñar adecuadamente las tareas.
Gustavo Litovsky
Hay dos cosas a tener en cuenta, caída de voltaje en los pullups o en la alimentación de su maestro y esclavo i2c, o problemas de emi o capacitancia. En cuanto a la carga de interrupción, ¿quiere decir que su maestro se está deteniendo para manejar una interrupción? Algunas virutas no permitirán el estiramiento infinito del reloj.
Passerby
@GustavoLitovsky tiene razón, pero el 80% de los ciclos de la CPU están prestando servicio a la interrupción de ADC y no hay tiempo suficiente para hacer un ciclo de lectura durante la ventana que no es ISR. Por lo tanto, la lectura se interrumpirá sin importar qué tan bien diseñe el sistema operativo.
Ktc
@ Passerby puede que tengas razón. El problema desapareció cuando conecté la sonda del analizador lógico a la línea del reloj.
Ktc
¿Cuál es su valor actual para las dominadas? ¿Has intentado cambiarlos a un valor diferente? (Pruebe 10k o 4k7 o 2k solo para una primera aproximación)
Tom L.

Respuestas:

9

Este es un problema de software, pasa demasiado tiempo dando servicio a las interrupciones y su rutina I2C no puede manejarlo (por lo que son dos cosas que no están bien). He pasado por varias situaciones similares.

Primero: debe hacer lo menos posible en las interrupciones, solo leer y almacenar los datos, no hacer ningún procesamiento que pueda hacer fuera del ISR, las matemáticas pueden tomar MUCHOS ciclos de CPU y la CPU no puede hacer nada más mientras en esa interrupción.

Segundo: Investigue DMA para automatizar las cosas, de modo que sus interrupciones se conviertan en un proceso automatizado en segundo plano.

Tercero: si I2C es importante, ponga ESO en una interrupción también, ¡pero asegúrese de resolver las prioridades!

Cuarto: descubra por qué su rutina I2C está fallando, I2C en sí puede resistir tiempos muy intermitentes, pausas y esperas, etc., por lo que su rutina puede necesitar modificaciones para permitir esto.

Quinto: vea si puede "encadenar" las interrupciones, puede descubrir que puede realizar el servicio de las lecturas de ADC de manera más eficiente, o poner el ADC en un modo diferente donde trabaje más para usted antes de interrumpir (por ejemplo, espere a que todas las lecturas estén disponibles, luego lea todo en un solo golpe, en lugar de 8 interrupciones separadas para 8 lecturas de canal ADC separadas).

Sexto: use un osciloscopio o un analizador lógico, y ahorre pines de E / S en el tablero, para rastrear cuánto tiempo pasa en cada bit de código, para ver si puede acelerarlo. (Establezca el pin alto cuando ingrese una función / ISR, vuelva a configurarlo bajo al salir).

Séptimo: decida si realmente necesita leer tanto el ADC, ¿ir más lento empeorará las cosas? Es contrario a la intuición, pero a veces su funcionamiento más lento en realidad da mejores resultados, haciendo el trabajo de promediar la señal por usted y reducir los picos / transitorios que podrían causar problemas o requerir un procesamiento adicional para eliminarlos. Mejoramos una rutina PID de control del motor simplemente ejecutándola 1/4 de la velocidad, liberando una carga de tiempo de CPU en el proceso.

John U
fuente
Gracias por las sugerencias El problema de alguna manera apunta al hardware.
Ktc
4

Un esclavo de autobús que está ocupado con otras cosas tiene la capacidad de alargar el reloj para ganar tiempo hasta que pueda continuar con su comunicación. Lo hace al no enviar inmediatamente el pulso de reloj ACK / NACK, manteniendo la comunicación en un estado intermedio hasta que esté listo para responder.

El estiramiento del reloj es la forma adecuada de lidiar con este tipo de situación. Un dispositivo que no se estira y hace otras cosas malas (bloqueo / reinicio del bus, NACKs una dirección o comando válido, etc.) puede ser problemático y pone una carga adicional en el maestro para mantener las cosas ordenadas (tiene que repetir comandos , realizar un seguimiento de los NACK, etc.)

Adam Lawrence
fuente
Tienes razón pero el problema es el anfitrión. El anfitrión está ocupado con otras cosas, no esclavo. Así que no estoy tan seguro de poder estirar el reloj.
Ktc
¿Está utilizando el hardware I2C incorporado o está eliminando el protocolo de las líneas GPIO? No hay un intervalo de tiempo de espera I2C específico definido en el estándar, por lo que los esclavos deben esperar indefinidamente a que el maestro termine un paquete.
Adam Lawrence
Yo uso las API STM32 IC2. Consulte la actualización, parece un problema de capacitancia.
Ktc
1

Dependiendo de las capacidades del STM32 (nunca he usado uno), puede probar uno de los siguientes enfoques. Si puede proporcionar más detalles sobre lo que está tratando de hacer y tiene un argumento convincente sobre por qué cada interrupción es necesaria en la forma en que la tiene ahora, entonces se puede pensar en una respuesta más específica. Sin embargo, específicamente en su caso, I2C es lo suficientemente lento para que esto no sea un problema con rutinas de interrupción bien escritas.

  • Las interrupciones para cualquier cosa generalmente se pueden deshabilitar. Hay como máximo una o dos interrupciones no enmascarables en cualquier controlador habitual, una de las cuales se restablece. Si no necesita el control de algo por interrupción (ADC o I2C, en su caso), entonces convierta ese código periférico en uno que no use interrupciones, y luego desactive las interrupciones.

  • Los manipuladores de interrupciones no deben ser largos. Intente hacer lo menos posible desde el vector de interrupción mismo. El enfoque minimalista extremo de las interrupciones es simplemente establecer un indicador desde la rutina del controlador de interrupciones y hacer que, por ejemplo, el bucle principal haga todo el trabajo pesado a partir de ahí. Lo que requiere su aplicación específica y arquitectura de firmware puede no ser tan simple como eso, pero realmente vale la pena hacer un esfuerzo para ver cuánto realmente hay que hacer desde dentro de las interrupciones.

  • Si tiene DMA periférica, úsela en lugar de interrumpir en cada byte. Por lo general, sería más fácil colocar el ADC en DMA en lugar de I2C, pero diferentes chips tienen implementaciones diferentes. No me sorprendería si hubiera una manera limpia de colgar un intercambio de I2C a la DMA también. DMA le permite reducir la cantidad de interrupciones y deja al núcleo de su procesador libre de tener que lidiar con cada bloque de datos.

  • Intente identificar las instancias específicas donde está viendo corrupción de datos y el mecanismo por el cual está ocurriendo la corrupción de datos. Esto es mucho más difícil de hacer, pero con el uso creativo de un osciloscopio / analizador lógico moderno es posible que pueda ver algunos de los problemas. Específicamente, asegúrese de que el problema tenga que ver con el tiempo y no con la memoria (que es una posibilidad con una combinación de código terrible y un compilador liberal)

EDITAR: Algunas notas específicas con respecto a esta instancia del problema, de sus comentarios sobre la pregunta:

  • Tener un 80% de CPU utilizado para leer el ADC generalmente no es algo que valga la pena. Recopilar datos es inútil si no puede actuar sobre ellos o incluso guardarlos.
  • Incluso si de alguna manera está recolectando (de manera útil) una gran cantidad de datos, las interrupciones de ADC no deberían ser tan largas como para suprimir por completo el periférico I2C durante un tiempo suficiente para que pierda datos. I2C funciona a, como máximo, 100 / 400KHz. Necesitaría una interrupción muy, muy larga para interrumpir el tiempo suficiente para que parezca algo más serio que la fluctuación del reloj en I2C.
Chintalagiri Shashank
fuente
Gracias. Nuestro sistema requiere este tipo de ISR complejo y largo, es una larga historia. Sin embargo, tiene razón, I2C debe mantenerse incluso bajo esta carga de interrupción y no puede. Sospecho que el problema está en el hardware, vea la actualización.
Ktc
Por lo que vale, en mi experiencia, la mayoría de los casos de uso que parecen exigir un ISR increíblemente largo son en realidad aquellos que merecen un RTOS. Y sí, según su última edición, parece un problema de hardware. Intente colocar un pequeño condensador en la línea donde estaba su analizador lógico y probablemente estará bien. Sin embargo, por qué eso es necesario es algo más difícil de responder. Verificaría las resistencias pullup I2C (puede ser demasiado baja para la capacitancia de su bus) y verificaría las hojas de datos de cualquier búfer / repetidor I2C que pueda estar usando.
Chintalagiri Shashank
0

En un sistema dado, podría haber ruido entrando al reloj y a los buses de datos. El hecho de que su analizador lógico elimine el problema lo demuestra. Para una implementación práctica y más rápida, solo siga la señal dada por su observación. En un bus i2c con implementación de 400kbits / seg, basado en una observación similar, conecté 2M en paralelo con 12pf a tierra desde el reloj y los puntos de datos y descubrí que el problema está resuelto. Esto elimina / filtra el ruido fuera de la banda de interés requerida para la comunicación i2c específica. Por favor intente y aconseje.

usuario41360
fuente