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

8

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

Actualización:

El procesador es STM32. Las interrupciones se deben a ADC, no puedo deshabilitar 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).

Update2:

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

    
pregunta Ktc

4 respuestas

8

Este es un problema de software, está gastando demasiado tiempo en el servicio de interrupciones & su rutina I2C no es capaz de manejarlo (entonces hay dos cosas que no están bien). He pasado por varias situaciones similares.

Primero: debe hacer lo menos posible en las interrupciones, solo lea & almacene los datos, no haga 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 esté en esa interrupción.

Segundo: investiga DMA para automatizar cosas, de modo que tus interrupciones se conviertan en un proceso casi automático en segundo plano.

Tercero: si I2C es importante, pon eso también en una interrupción, ¡pero asegúrate de definir las prioridades!

Cuarto: descubra por qué su rutina I2C está fallando, I2C puede soportar tiempos muy intermitentes, pausas y amp; espera etc. por lo que su rutina puede necesitar modificaciones para permitir esto.

Quinto: vea si puede "encadenar" las interrupciones, puede encontrar que puede revisar las lecturas del ADC de manera más eficiente, o poner el ADC en un modo diferente donde trabaje más por usted antes de interrumpirlo (por ejemplo, espere a que todas las lecturas se realicen) esté disponible, luego lea todo de una vez, en lugar de 8 interrupciones separadas para 8 lecturas de canales ADC separadas).

Sexto: use un osciloscopio o un analizador lógico, y pines IO de repuesto en la placa, para rastrear cuánto tiempo está gastando en cada bit de código, para ver si puede acelerarlo. (Establezca el pin alto cuando ingrese una función / ISR, ajústelo nuevamente 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 correr más lento en realidad da mejores resultados, haciendo el trabajo de promediar la señal para usted y reduciendo los picos / transitorios que podrían causar problemas o requerir un procesamiento adicional para eliminarlos. Mejoramos una rutina PID de control de motor simplemente ejecutando 1/4 de la velocidad, liberando una carga de tiempo de CPU en el proceso.

    
respondido por el John U
4

Un esclavo del bus que está ocupado con otras cosas tiene la capacidad de cronometrarse para ganar tiempo hasta que sea capaz de continuar su comunicación. Para ello, no envía inmediatamente el pulso de reloj ACK / NACK, manteniendo la comunicación en un estado intermedio hasta que esté listo para contestar.

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 (colgar / reiniciar el bus, NACK es una dirección o comando válido, etc.) puede ser problemático y supone una carga adicional para el maestro mantener las cosas ordenadas (tiene que repetir los comandos). , realizar un seguimiento de NACKs, etc.)

    
respondido por el Adam Lawrence
1

Dependiendo de las capacidades del STM32 (nunca he usado uno), puedes probar uno de los siguientes métodos. 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, uno de los cuales se restablece. Si no necesita interrumpa el control de algo (ADC o I2C, en su caso), entonces convierta ese código periférico en uno que no use interrupciones y luego deshabilite las interrupciones.

  • Los manejadores de interrupciones no deben ser largos. Trate de hacer lo menos posible desde el propio vector de interrupción. El enfoque minimalista extremo para las interrupciones es simplemente establecer una bandera desde dentro de la rutina del manejador de interrupciones y hacer que, por ejemplo, el bucle principal haga todo el trabajo pesado de ahí en adelante. Lo que su aplicación específica y la arquitectura de firmware requieren puede no ser tan simple como eso, pero realmente vale la pena esforzarse para ver cuánto hay que hacer realmente dentro de las interrupciones.

  • Si tiene DMA periférico, úselo 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 los diferentes chips tienen diferentes implementaciones. No me sorprendería si hubiera una manera limpia de separar un intercambio de I2C a DMA también. DMA le permite reducir el número de interrupciones y deja el núcleo del procesador libre de tener que lidiar con cada bloque de datos.

  • Intente identificar las instancias específicas en las que está viendo corrupción de datos y el mecanismo por el cual se produce la corrupción de datos. Esto es mucho más difícil de hacer, pero con el uso creativo de un moderno osciloscopio / analizador lógico 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 sobre esta instancia del problema, a partir de sus comentarios sobre la pregunta:

  • Tener un 80% de CPU utilizado para leer el ADC generalmente no es algo que valga la pena hacer. La recopilación de datos no sirve de nada si no puede actuar o incluso guardar los datos.
  • Incluso si de alguna manera está recolectando (útilmente) una gran cantidad de datos, las interrupciones de ADC no deberían ser tan largas como para suprimir completamente el periférico I2C durante un tiempo lo suficientemente largo como para hacer que pierda datos. I2C se ejecuta a, a lo sumo, 100 / 400KHz. Necesitarías una interrupción realmente larga para interrumpir el tiempo suficiente para que parezca algo más serio que el jitter del reloj en I2C.
respondido por el Chintalagiri Shashank
0

En un sistema dado, podría haber ruido ingresando el reloj y los buses de datos. El hecho de que su anlayser lógico elimine el problema lo muestra. Para una implementación práctica y rápida, simplemente siga las indicaciones de su observación. En un bus i2c con una implementación de 400 kbits / 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.

    
respondido por el user41360

Lea otras preguntas en las etiquetas