MSP430: ¿cómo dejar que el temporizador ISR interrumpa el Serial RX ISR?

Estoy trabajando en un MSP430 conectado a la PC vía serial. El MSP430 también se comunica con otras placas mediante una interfaz serial de bits. Estoy usando el periférico del temporizador para hacer bit bang en la serie, y estoy usando el UART para hablar con la PC.

Cuando llegan comandos de la PC, se ejecuta la interrupción USCIAB0RX_VECTOR, y mientras se ejecuta, bloquea otras interrupciones. Sin embargo, algunas veces mi rutina serial RX toma un poco de tiempo, lo que retrasa la interrupción del temporizador y descarta la interfaz bit-bang.

En el ISR de RX en serie, me gustaría permitir que la interrupción del temporizador aún reciba servicio, pero me gustaría evitar que el RX en serie se interrumpa solo (lo que no debería suceder para mi aplicación específica, pero me gustaría protegerse contra esto por si acaso)

  • ¿Debería simplemente enmascarar manualmente la interrupción RX en serie en la parte superior del ISR en serie y luego habilitar las interrupciones globales?
  • ¿También necesito desenmascarar la interrupción serial RX al final?
  • ¿Necesito borrar manualmente cualquier indicador de solicitud de interrupción?
  • Después de que regrese el ISR del temporizador, ¿continuará el ISR en serie y luego regresará al bucle principal?

  • ¿Existen posibles condiciones de carrera que deba tener en cuenta?

  • ¿Hay una solución mejor?
  • ¿Hay un artículo sobre interrumpir e interrumpir? (Ya he leído sobre interrupciones anidadas en la guía del usuario)

Respuestas (3)

No conozco esta MCU específica, pero la pregunta es bastante genérica.

La respuesta obvia a todos los problemas como estos es mantener los ISR lo más reducidos posible. A lo sumo, deberían introducir datos en un búfer de anillo, que luego es procesado por el programa principal. (Una MCU con DMA hubiera sido aún mejor, pero no creo que tenga DMA en MSP430).

Si el ISR sigue siendo demasiado lento después de tales optimizaciones, entonces no tiene otra opción que hacer lo que sugiere: habilite la máscara de interrupción global en la parte superior del UART ISR y deje que la interrupción de mayor prioridad tenga prioridad. Sin embargo, tenga en cuenta que cuando permite que se sumen más interrupciones a un ISR que ya se está ejecutando, permite una mayor profundidad de pila.

¿También necesito desenmascarar la interrupción serial RX al final?

¿Supongo que tienes que hacer eso desde el ISR sin importar la naturaleza de la aplicación? Así es como funcionan la mayoría de MCU. Y sí, si toca la máscara de interrupción global, tendrá que borrar la interrupción específica después de que haya terminado de servirla, es decir, después de haber copiado los datos recibidos en las variables locales.

Después de que regrese el ISR del temporizador, ¿continuará el ISR en serie y luego regresará al bucle principal?

Si ha cambiado la máscara de interrupción global, entonces sí.

¿Existen posibles condiciones de carrera que deba tener en cuenta?

Siempre debe tenerlo en cuenta cada vez que comparta datos entre un ISR y otra cosa. No importa si el ISR solo escribe y el programa principal solo lee, etc., a menos que pueda garantizar que cada acceso sea atómico, lo que generalmente no puede hacer a menos que escriba el código en ensamblador.

En un lenguaje de alto nivel, es posible que deba usar alguna variable de semáforo. Cómo se implementa esto depende de la aplicación. Depende particularmente de si puede darse el lujo de perder algunos datos del ISR o si tiene que capturar todos los datos.

¿Hay una solución mejor?

DMA o una MCU multinúcleo.

Con respecto a "¿ No creo que tenga DMA en MSP430? ": 223 de los 421 microcontroladores MSP430 diferentes que figuran actualmente en TI.com tienen DMA, comenzando con el MSP430F5131 en el extremo inferior del rango de precios ($1,20), que tiene 3 canales DMA.
Con respecto a " cada acceso es atómico, lo que generalmente no puede hacer a menos que escriba el código en ensamblador ", por lo general, esto se haría mediante el equivalente del cli(); bloque de código atómico ; sti();en C, por lo tanto para la familia MSP430:__enable_interrupt(); // enable all interrupts --> GIE = 1 (HIGH) __disable_interrupt(); // disable all interrupts --> GIE = 0 (LOW)

Mueva sus rutinas de manejo de paquetes RX desde el vector de interrupción. La función de interrupción debe ser lo más corta posible (en su caso, coloque un byte en un búfer para su posterior procesamiento y señale al programa principal que hay un byte pendiente). Decidir sobre las prioridades, ¿qué interfaz es más importante? Periférico o PC? ¿Puede uno de ellos esperar?

Una posible solución es servir al UART desde la interrupción del temporizador, sin dejar que se interrumpa por sí mismo. Se puede verificar si un personaje ha llegado al UART y almacenarlo en un búfer con algunas instrucciones. A continuación, realiza el mantenimiento de la broca. Salir de la interrupción del temporizador permite que el código del modo de usuario se ejecute hasta la próxima interrupción del temporizador. Cuando no esté golpeando un poco, puede optar por habilitar la interrupción UART y aumentar el tiempo entre las interrupciones del temporizador para obtener más tiempo en el modo de usuario.