Pautas disponibles para el procesamiento impulsado por interrupciones

3

¿Hay alguna guía disponible para la cantidad de código que se debe tener en una sección crítica del procesamiento controlado por interrupciones?

Mi regla de oro personal es que la parte crítica (es decir, entre inhabilitar interrupciones y habilitar interrupciones), de cualquier procesamiento dirigido por interrupciones no debe ser más de una docena de líneas de código (incluidas las de cualquier función / biblioteca). / macro llamado), y que el procesamiento debe ser lo más lineal posible.

Esperaría algo como:

disable_interrupts
if error_condition:
   set_error_flag
else:
   small_data_transfer
   set_ready_flag
enable_interrupts

Sin embargo, se me ha pedido que examine un proyecto existente en el que algunas de las interrupciones tienen manejadores en los que los gráficos de llamadas no caben en una hoja de A1 (todo en la sección crítica).

Para aclarar esto, se trata de un proyecto "simple" sin un sistema operativo / programador implementado, y todos de los manejadores de interrupciones comienzan por desactivar todas interrupciones, es decir, los autores originales. considera que cada operación en cada ISR es crítica, (incluso el mantenimiento se encuentra dentro de una sección de habilitar / habilitar). Hay una gran cantidad de interrupciones y dependencias de hardware, pero por lo que puedo ver, algunos de los ISR ejecutarán miles de líneas dentro de la sección "crítica".

Sé que esto es un problema y realmente necesita ser reescrito por completo pero no puedo encontrar ningún estándar, incluido MISRA, al que pueda señalar en lugar de solo decir " en mi experiencia "- para convencer a la gerencia del proyecto que necesito señalar algunos estándares aceptados.

Entonces, de ahí mi pregunta: ¿Alguien puede señalarme algún estándar o guía que pueda usar para respaldar mi experiencia? (O, por supuesto, estoy totalmente equivocado).

    
pregunta Steve Barnes

4 respuestas

3

En general, la distribución del tiempo de CPU entre el código ISR y el código no ISR depende mucho de la aplicación.

Si la mayor parte del trabajo se realiza en un código que no es de ISR, entonces sí, generalmente desea mantener los ISR lo más cortos posible (pero no más corto, parafraseando una cita famosa).

Sin embargo, he visto (y he creado) aplicaciones DSP en tiempo real en las que el 90% del trabajo se realiza en el ISR, y el código no ISR solo maneja tareas que no son críticas en el tiempo, como la configuración , estado e interfaz de usuario.

Cualquiera de los dos enfoques es perfectamente válido en sistemas profundamente integrados.

    
respondido por el Dave Tweed
2

La pauta general es que las secciones críticas deben ser lo más cortas posible.

Lo que realmente necesita hacer es tener en cuenta la longitud de la sección crítica cuando verifique la capacidad de programación del conjunto de tareas. Hacer esto depende de cómo esté programando las tareas, pero creo que podría ser tan simple como agregar el tiempo de ejecución de la sección crítica al tiempo de ejecución de cada tarea de menor prioridad.

    
respondido por el Joe Hass
2

Creo que debe considerar el tiempo de ejecución del código ininterrumpido, ya que el tiempo de respuesta (latencia) más rápido y la variabilidad de ese tiempo (jitter) que necesita del microcontrolador. Puede que no sea intuitivo lo que es, puede ser algo "urgente" pero no "importante".

Por ejemplo, un controlador que diseñé hace algunos años tenía que lidiar con las entradas RS-232, para actualizar la salida usando el algoritmo de control, para controlar el ADC de doble pendiente, para escanear una pantalla LED y un teclado (incluido el rebote) , escriba a una EEPROM lenta, y para controlar una señal acústica electromagnética (y probablemente haya olvidado algunas otras cosas). El tiempo de respuesta más crítico fue la interrupción periódica de la señal acústica (cada 250useg), seguida de la pantalla LED, principalmente por razones cosméticas. Entonces, si el 10% de jitter en el interruptor de la señal acústica fue aceptable, eso es 25usec de código ininterrumpido (que no era muchas instrucciones, pero suficiente para hacer ciertas cosas atómicas). Ese procesador en particular admitía interrupciones anidadas, por lo que IIRC I terminó haciendo que el código de interrupción periódica volviera a ingresar después de la primera sección.

Si está aplazando las interrupciones pendientes durante largas secciones de código, puede estar bien, si sus requisitos de latencia y fluctuación de fase son bastante relajados en relación con el tiempo de ejecución de las "partes críticas".

Mi enfoque habitual es minimizar el tiempo de ejecución del código en los ISR y volver lo más rápido posible (tal vez rellenar cosas como tokens de eventos de entrada de rebotes en colas circulares, establecer marcas y salir). Por ejemplo, si un algoritmo de control complejo debe ejecutarse cada 200 ms con una fluctuación máxima de 20 ms, establecería una bandera cada 200 ms en la interrupción del temporizador y sondeará esa bandera fuera del ISR.

Además de cumplir con los requisitos de diseño, este enfoque mejora la confiabilidad.

En cuanto a encontrar algún tipo de guía que indique esto ... sugiero mirar algunas de las pautas de software críticas para la seguridad. Es posible que no lo encuentre expresado directamente, pero puede inferirlo de otras afirmaciones. UL1998 IEC 60730 etc. Este documento de la FAA indica:

  

Las interrupciones y su efecto en los datos deben recibir atención especial en áreas críticas para la seguridad. Análisis debe   verifique que las rutinas de manejo de interrupciones e interrupciones no alteren los elementos de datos críticos utilizados por otras rutinas.

y

  

Una preocupación particular para la seguridad es garantizar la integridad de los datos críticos de seguridad contra la inadvertencia   alterado o sobrescrito. Por ejemplo, verifique si el procesamiento de interrupción está interfiriendo con la seguridad crítica   datos.

Ambos se vuelven más difíciles a medida que aumenta el tamaño del código de interrupción.

Las interrupciones frecuentes (en relación con la fluctuación máxima y la latencia) se pueden analizar como una disminución efectiva de la velocidad del procesador en lugar de tener que lidiar con las acumulaciones en el peor de los casos de interrupciones largas en los momentos más críticos, lo que aboga por una rápida Ejecución y código simple dentro de ISRs.

    
respondido por el Spehro Pefhany
1

Para mí, evitar las interrupciones de anidamiento no parece tan malo ni tan absurdo. De hecho, las interrupciones anidadas pueden causar más problemas de los que solucionan.

Me refiero específicamente a la memoria utilizada para guardar / restaurar el contexto al ingresar / salir del ISR. Comúnmente en arquitecturas simples, cada ISR guardará todo el contexto requerido del código que interrumpió, por ejemplo, en la pila del procesador. Al desarrollar el software, uno necesita tener en cuenta esta memoria.

Si, por ejemplo, ISR A requiere que se guarden / restauren 10 bytes de contexto, ISR B necesita 15 e ISR C necesita 12 bytes, el cálculo / estimación simplemente es:

En cualquier lugar durante la ejecución de secciones no críticas, se puede activar cualquiera de los ISR. Ahora, si los ISR no pueden anidarse, la memoria máxima requerida para el contexto es max( 10, 15, 12 ) = 15 bytes. Si cada uno de los ISR puede interrumpir cualquier otro de esos 3 ISR, el peor de los casos será 10 + 15 + 12 = 37 bytes de contexto que deben almacenarse al mismo tiempo . Por lo tanto, en cada instante durante la ejecución (del código no atómico), debe haber al menos suficiente memoria disponible para esos 37 bytes de contexto, frente a 15 en el caso de no anidación.

Por supuesto, mientras más ISR se unan al "juego de anidación", más se vuelve visible el problema.

Si tiene varias tareas que se ejecutan simultáneamente y los ISR guardan el contexto en la pila actual del código que están interrumpiendo, debe tener en cuenta el tamaño del contexto de peor caso por tarea .

Este argumento, por supuesto, depende de la arquitectura de HW que estés usando. Es posible que no se aplique si el Controlador de interrupciones / HW es más avanzado y tiene características especiales para manejar el cambio de contexto a / desde ISRs.

Además, los ISR complejos tienden a requerir que se guarden / restauren más datos de contexto que los simples, por lo que generalmente se recomiendan ISR pequeños y concisos porque ofrecen múltiples beneficios:

  1. rápido tiempo de ejecución, posiblemente produciendo
    1. secciones críticas más cortas y por lo tanto
    2. menos jitter
  2. contexto más pequeño, lo que resulta en
    1. menos uso de memoria en el peor de los casos y (dependiente de la arquitectura)
    2. incluso menos tiempo de ejecución (al no tener que transferir tanta información de estado de A a B a A)

Al final, si todos los ISR se reducen a su mínimo, como cuando solo se establece una marca, la pregunta de si se debe o no permitir los ISR de anidación se puede responder claramente a favor de no anidar, ya que el beneficio de los ISR de anidación desaparece .

    
respondido por el JimmyB

Lea otras preguntas en las etiquetas