Interrupciones

De Wikitronica
Revisión del 09:53 17 may 2013 de Racuna (Discusión | contribuciones)

(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Saltar a: navegación, buscar

Este artículo no pretende abarcar una definición completa de lo que son las interrupciones, ya que mucha se ha hablado previamente de ellas en otros foros y enciclopedias. Sin embargo es necesario tener una breve descripción de lo que son.

Una interrupción es un recurso del cual disponen la mayoría de los procesadores y microcontroladores en el mercado hoy en día.Permiten cambiar la continuidad de ejecución de un program, para atender una necesidad, ya sea externa o interna.

Como ejemplo, un botón de RESET puede ser visto como una fuente de interrupción que de manera asíncrona detiene todos los procesos y reinicia el sistema por completo. Incluso, dependiendo del sistema, lo puede llevar a un estado inicial.

Las interrupciones se manejan de distintas formas según el procesador, fabricante, desarrollador, etc. Hablando a nivel de microcontroladores, la mayoría tienen algo en común, y es como atienden dicha interrupción. Al recibirse una señal de interrupción, se abre la brecha en la continuidad del programa en ejecución, y se recurre a un registro llamado “Handler”, el cuál, dependiendo del microcontrolador, contendrá el código de ejecución para atender la interrupción, o contendrá una dirección donde se encontrará dicho código.

Entre las utilidades de las interrupciones podemos encontrar cosas tan simples como cambiar el valor de un puerto de 0 a 1, hasta cosas tan complejas como lo es un despachador de tareas, he allí, el poder de este recurso.

Las interrupciones pueden tener fuentes internas y externas. Una fuente de interrupción interna puede ser por ejemplo, un error por overflow o la finalización de un contador; una fuente externa, puede ser un botón de reset, también una señal de control o un detector de cambios de nivel como el KBI o el IRQ.

Interrupciones en microcontroladores [Freescale]

Para explicar el funcionamiento de las interupciones para este fabricante de microcontroladores, tomaremos de ejemplo al MC9S08QE128 de la familia HCS08.

Las interrupciones en el MC9S08QE128 tienen un manejo por registros de vectores, con un vector asociado a cada tipo de interrupción (módulos). Esto significa, que para cada fuente de interrupción, existe un registro el cual tiene la dirección del manejador de dicha interrupción (la función que atiende a la interrupción). Este tipo de organización por vectores de interrupción, tiende a ser más sencillo de comprender y normalmente no es necesario realizar una encuesta exhaustiva de los registros para determinar la fuente de interrupción.

Cuando una interrupción se lleva a cabo, se hace una copia de los registros (Registros del CPU - MC9S08QE128) necesarios en la pila (STACK), de manera que al finalizar la atención de la interrupción con el comando RTI se pueda retornar a la misma instrucción que se estaba ejecutando.
En la siguiente imagen se muestra como se apilan los registros al entrar y al salir de la interrupción:

Uso del stack al entrar y al salir de la interrupción



Cuando se solicita una interrupción se siguen los sigientes pasos:
Flag--->Revisar máscara local--->Revisar máscara global--->Solicitar interrupcion al CPU

Para el control de las interrupciones, existen una máscara global y una máscara para cada fuente de interrupción.

La máscara global para las interrupciones se encuentra en el registro CCR (Condition Code Register), específicamente el bit I. Esta máscara inhibe la mayoría de las interrupciones, sin embargo, casi todos los RESET no se ven afectados por esta máscara.

RESETs:

Entre las interrupciones encontramos este tipo de excepciones, que normalmente pertenece al grupo de control del sistema.

Cuando se lleva a cabo un Reset:
-La mayoría de los registros de estado y control son reiniciados y se obtiene el handler
-Se desactivan todos los modulos
-Todos los pines se configuran como pines de proposito general de input en alta impedancia sin pullup
-Se activa la máscara de interrupciones (BIT I CCR)
-El stack pointer SP se ubica en 0x00FF.

Existen varias fuentes de reset:

-Power-on-reset (POR): Inicio del equipo
-External pin reset (PIN): Si está configurado, el pin /RESET será la fuente de la interrupcion
-Watchdog - COP (Computer Operating Properly): un modulo adicional que se encarga de verificar que el programa en ejecucion no se ha quedado en un loop infinito o en una traba.
-Opcode ilegal (ILOP): se trata de ejecutar una instruccion considerada ilegal.
-Bajo voltaje(LVD): ya sea por advertencia o deteccion de bajo voltaje.
-Reinicio forzado por debug.

Vectores de Interrupción para el [MC9S08QE128]:

En la siguiente imagen se pueden observar todos los vectores de interrupcion, además organizados por prioridad. Aqui se detallan las máscaras (ENABLE) para cada interrupción, así como su fuente (SOURCE).

Vectores de Interrupción para el MC9S08QE128

Fuentes de interrupciones:

WATCHDOG:

Generado por el Computer Operating Properly (COP)
Mask: Registro SOPT1, bit COPE

IRQ:

Interrupción externa manejada según la configuración del registro IRQSC

El pin IRQ se basa en una lógica de funcionalidad sencilla, ya que un nivel bajo aplicado al pin de habilitación de interrupción externa (IRQPE) implica que se desactiva la función IRQ y un uno habilita la función de IRQ. IRQ se dispara en un flanco descendente de reset y es configurable por software para ser detectado por flanco descendente o por flanco descendente y nivel bajo, lo que se hace a través del bit IRQMOD , tanto el bit IRQPE como IRQMOD se encuentran en el registro de control de interrupción externa (IRQSC).

El IRQ es habilitado con PTA5 al colocar RSTPE=0, el cual es el bit 0 del registro SOPT1.

Mask: Registro IRQSC, bit IRQPE

Más información: IRQ_(External_Interrupt_Request)_-_MC9S08QE128

LVD:

Interrupción generada por el detector de bajo voltaje

Se basa en un sistema de protección, se encarga de proteger el contenido de la memoria de variaciones en el voltaje de alimentación. Para configurar que se haga un reset cuando se detecte una baja de voltaje de alimentación se debe colocar el bit LVDRE=1. El voltaje que se tomara como bandera de que existe un voltaje bajo de entrada se configura en el bit LVDV.


Mask: Registro SPMSC1, bit LVDE (set), bit LVDIE (set), bit LVDRE (clear)

TPMx - TOF:

Overflow de contador
Mask: Registro TPMxSC, bit TOIE

Más información: PWM (Modulación de Ancho de Pulso)

TPMx - CHnIE:

Evento CCP (Capture\Compare\PWM) en el canal n
Mask: Registro TPMxCnSC, bit CHnIE

Más información: PWM (Modulación de Ancho de Pulso)

RTC:

Overflow del contador del Real Time Clock
Mask: Registro RTCSC, bit RTIE

Más información: RTC (Real-timer counter) - MC9S08QE128

SPIx:

Interrupción del módulo de recepción de datos perifericos serial

Mask: Registro SPIxC1, bit SPTIE, bit SPIE

Más información: SPI: Interfaz de Serial Periferico para el microcontrolador QE - MC9S08QE128

SCI - TX:

Interrupción del módulo de transmisión de datos serial
Mask: Registro SCIxC2, bit TIE, bit TCIE

Más información: SCI (Interfaz de Comunicación Serial) - MC9S08QE128

SCI - RX:

Interrupción del módulo de recepción de datos serial
Mask: Registro SCIxC2, bit RIE, bit ILIE; Registro SCIxBDH, bit LBKDIE, bit RXEDGIE

Más información: SCI (Interfaz de Comunicación Serial) - MC9S08QE128

ACMPx:

Comparador análogo, la interrupción se activa cuando una comparación ocurre en el módulo
Mask: Registro ACMPx, bit ACIE


Más Información: Comparador_Analógico_-_MC9S08QE128

ADC:

Conversor analógico-digital, interrumpe cuando se termina una conversión AD
Mask: Registro ADCSCI, bit AIEN

Más información:ADC (Conversor Analógico-Digital) - MC9S08QE128

KBIx:

Interrupción proveniente de cualquiera de los pines disponibles en los módulos KBI
Mask: Registro KBIxSC, bit KBIE

Más información: KBI (Keyboard interrupts) - MC9S08QE128

IICx:

El flag de la interrupción IICIF del registro IICxS se puede activar por:
- Se ha terminado de transmitir un byte
- Coincidencia de la dirección llamada, con la dirección de esclavo
- Arbitration lost: cuando hay varios masters y uno envía un 1 lógico cuando otro envía un 0 lógico, el primero pierde su condición de master y pasa a ser esclavo.
Mask: Registro IICxC1, bit IICIE

Más información en: I²C (Inter-Integrated Circuit) - MC9S08QE128

SWI:

Interrupción solicitada por software

Implementación de interrupciones en ASSEMBLER

Para habilitar y deshabilitar la máscara global de las interrupciones existen dos comandos:
CLI: Limpiar el bit I del registro CCR, activa las interrupciones
SEI: Activa el bit I del registro CCR, desactiva las interrupciones

Para activar una interrupción específica, se ha de modificar el bit correspondiente y se ha de tomar en cuenta las configuraciones que necesite.
Para activar o desactivar un bit específico en un registro se pueden utilizar los comandos
BSET y BCLR

Hay que recordar que estas dos instrucciones solo funcionan para direcciones de memoria entre $0000 y $17FF (dentro de PPAGE 0) por lo que no se pueden usar en registros como RTCSC.

Una vez configurados los registros necesarios, se ha de configurar el vector de interrupción deseado.
Todos los vectores de interupción estan compuestos de dos bytes, que representan la parte alta y la parte baja de la dirección del handler de la interrupción.

Es importante tomar en cuenta que si se desea asegurar que la rutina de interrupción sea accesible desde cualquier direccion sin importar el valor del PPAGE, la rutina ha de estar en la página de memoria 0,1 ó 3.

Para retornar de la interrupción usar la instrucción RTI

Ejemplo de código:


_Startup:
            LDHX   #RAMEnd+1        ; inicializa el stack pointer
            TXS
            lda    #$42             ; Desactiva el COP
            sta    SOPT1
            lda    #$00             ; Se configura el módulo RTC
            sta    RTCMOD
            lda    #$18
            sta    RTCSC            ; Se habilita la interrupción en el RTC
            CLI                     ; Se habilitan las interrupciones globales
mainLoop:                            ;función principal
            
            BRA    mainLoop
RTC:                                ;Función handler de RTC
            "Instrucciones"        
            RTI                     ;Retorno de la interrupción
            
            ORG   $FFCE             ;Vector de interrupción 
            DC.W  RTC

Implementación de interrupciones en C

Es importante incluir la librería hidef.h, esta incluye el macro para habilitar las interrupciones.
Inicialmente, habilitar las interrupciones con el macro "EnableInterrupts.
Configurar el módulo y habilitar la interrupción deseada.
Configurar la función handler de la interrupción siguiendo este formato:

void interrupt NúmeroDeVector NombreDelHandler(void) { }

A continuación, un ejemplo de código en C:

include <hidef.h> /* EnableInterrupts macro */
include "derivative.h" /* include peripheral declarations */

/*Aqui se colocan las variables globales*/



byte buff;

byte flag=1;

/*Aqui se colocan los vectores de interrupcion*/

/*ISR para la transmision*/
void interrupt VectorNumber_Vsci1tx SCI_ISR_TXC(void) {

SCI1S1_TDRE=0;  //limpio la bandera de la interrupcion de enviado//
flag=1;


}

/*ISR para la recepcion*/
void interrupt VectorNumber_Vsci1rx SCI_ISR_RX(void) {

SCI1S1_RDRF=0;  //limpio la bandera de la interrupcion de recibido//

buff=SCI1D;   //obtengo el byte recibido
flag=0;
}

void main(void) {

 /*Condiciones iniciales*/
 
SOPT1_COPE =0; /*Deshabilito COP*/

EnableInterrupts; /* Activo Interrupciones */

/*Configuro el puerto serial*/

SCI1BD=0x1A; 		/*Baudrate*/
SCI1C1_PE=0; 		/*Sin paridad*/
SCI1C2_RIE=1;		/*y Recepcion Completada*/
SCI1C2_RE=1;		/*Activamos la recepcion*/
SCI1C2_TE=1;		/*y la emision*/

/*Funcion principal*/

{

int i;

for(;;)

{

while(flag==1);	//espera a recibir
SCI1C2_TCIE=1;	//Activamos los interrupts de Transmision Completada
SCI1D=buff;	//Coloca en cola de transmision el byte recibido
while(flag==0);	//espera a transmitir lo recibido

}
}

Generacion de interrupciones en la simulacion

El programa Codewarrior 6.3 presenta la opción “debug” que permite simular el programa sin necesidad de la conexión de un micro. En dicha aplicación también se puede simular las interrupciones como se presentan con el uso del micro.

Para crear las interrupciones en la simulación, se deben seguir los siguientes pasos:

1. Correr el programa y detenerlo con la opción Halt

2. Seleccionar la opción HCS08FCS que se encuentra en la parte superior del programa de simulación

3. Seleccionar IRQ Module

4. Seleccionar Set IRQ Inputs Levels (INPUTS)


     Opciones para generar interrupciones.PNG


Despues de realizar los anteriores pasos se desplegara una ventana que mostrara los diferentes puertos que realizan interrupciones, configurados por defecto con el valor FF, con excepción del IRQ que esta configurado con 1.

                                 Configuracion de Puertos de entradas para generar interrupciones.PNG


Para realizar una interrupción se debe colocar en 0 el puerto que la debe generar, como ejemplo, se generara una interrupción por el puerto PTA2, por lo cual se le asignara a InputA el valor FB.


Configuracion de PTA2 como interrupcion.PNG


Y se puede observar que el programa entro en la instrucción Izquierda, dado que es la rutina que se llama al presionar el botón Pta2.

Para generar otras interrupciones, primero se debe colocar todos los registros con sus valores originales, es decir FF, presionar la opción Ok, y luego modificarlos para que genere la interrupción deseada.

Las interrupciones por Tpm no necesitan se configuradas con los pasos anteriormente mencionadas, dado que ellas interrumpen en el debugger.

Interrupciones del puerto serial en la simulacion

Para realizar interrupción por puerto serial, se deben seguir los siguientes pasos:

1. Seleccionar la opción HCS08FCS que se encuentra en la parte superior del programa de simulación

2. Seleccionar la opción SCI Module

3. Seleccionar la opción Queue SCI Input Data (SCDI)


Opciones para generar una interrupcion por puerto serial.png


Después se va a desplegar una ventana con el título de SCI In vacía, allí deberá colocar los valores que desea que el programa reciba, lo cual es una simulación de lo que se espera recibir por puerto serial.

                              Ventana donde se colocara los valores transmitidos por el puerto serial.png


Para cargar cada valor debe darle doble click al espacio resaltado en azul, lo cual desplegara una ventana en la cual debe introducir el valor que recibir en el programa.

Ejemplo de como colocar valores que se recibiran por el puerto serial.png


Después de correr el programa si desea visualizar la salida, o el resultado que se va a transmitir por el puerto serial (solo si código recibe y transmite por puerto serial), puede seguir los siguientes pasos:

1. Seleccionar la opción HCS08FCS que se encuentra en la parte superior del programa de simulación

2. Seleccionar la opción SCI Module

3. Seleccionar la opción View SCI Output Data (SCDO)

Lo cual desplegara una ventana donde aparecerán los valores que se están transmitiendo por puerto serial

Opcion para visualizar la recepcion del puerto serial.png

Interrupciones en microcontroladores [Microchip]

En los microcontroladores PIC16F87X existen muchas causas que pueden originar interrupciones; en el caso de los microcontroladores de 28 pines existen 13 posibles fuentes y en los de 40 pines 14. Cuando ocurre una interrupción, se salva el valor del PC en la pila y se carga la dirección en el vector de interrupción 0004h. Los PIC16F84, de gama más baja, poseía 4 causas que generaban interrupción:

  1. Desbordamiento del TMR0
  2. Activación en la pata de interrupción RB0/INT
  3. Cambios en los 4 pines de más peso en el puerto B
  4. Y cuando se terminaba de escribir un byte en la memoria EEPROM (Duraba 2ms!).

Los PIC16F87X, además de las anteriores poseen:

  1. Overflow en Timer1
  2. Overflow en Timer2
  3. Captura o comparación en el módulo CCP1
  4. Captura o comparación en el módulo CCP2
  5. Transferencias en la puerta serie síncrona SSP
  6. Colisión de bus en la puerta serie síncrona BCL
  7. Fin de transmisión USART
  8. Fin de recepción USART
  9. Fin de conversión A/D
  10. Transferencias en la puerta paralela esclava (menos en los de 28 pines)

Para manejar las máscaras de las interrupciones por TMR0, los 4 pines del puerto b y el pin RB0/INT, se usa el registro INTCON (0Bh, 8Bh, 10Bh, 18Bh).
Para las causas de interrupciones A/D, RxUART, TxUART, SSP, CCP1, TMR1 y TMR2 se usa el registro PIE1 (8Ch), sin embargo el bit PEIE en INTCON esté habilitado.
Para las causas escritura en EEPROM, BCL y CCP2 se usa el registro PIE2

En correspondencia con los registros de habilitación de interrupciones PIE1 y PIE2, existen los registro PIR1 (0Ch) y PIR2 (0Dh) que señalan los módulos que originan la causa que provoca la interrupción, estén o no habilitadas dichas interrupciones.

Interrupciones en microcontroladores [Atmel]

Interrupciones Anidadas

Durante el proceso de programación existirán ocasiones en las que se desee, por cualquier motivo, poder atender interrupciones estando ya dentro de una. Una situación típica ocurre cuando dentro de una interrupción se está realizando una rutina de espera o de encuesta durante la cual no se desea desatender el resto del programa, sino más bien, poder atender las interrupciones que vayan apareciendo mientras se espera.


En la DEMOQE128 existen mecanismos que nos permiten emular las interrupciones anidadas, simplemente modificando la bandera I "Global Flag Interrupt Enable" localizada en el CCR para permitir o no nuevas interrupciones. Antes de lanzarnos a programar debemos tener claro, según lo que queremos lograr, que interrupciones deben permitir interrupciones anidadas, en que parte del código y cuales no, así mismo debemos saber que interrupción no puede estar anidada dentro de alguna otra para asegurarnos de que no tengamos errores de lógica. Por ejemplo, en líneas generales, una interrupción de transmisión serial no debería poder ser interrumpida por otra igual, ya que podría perderse el orden de la información enviada.


Una vez tomadas en cuenta estas consideraciones, los pasos para realizar una interrupcion anidada son:


  1. Localizar la interrupción y el lugar de la interrupción donde podemos permitir interrupciones anidadas.
  2. Justo antes de ese lugar, deshabilitamos todas las interrupciones que no queremos anidar. Por ejemplo, a si misma.
  3. Una vez deshabilitadas, bajamos la "Global Interrupt Flag" I con la instrucción CLI.
  4. Al final de la interrupción principal volvemos a habilitar todo lo deshabilitado para que el programa pueda seguir su curso.
  5. Retornamos con RTI.


Veamos esta situación con más detalle mediante un ejemplo:

Transmicion_Serial:

	LDHX #$0000
	STHX TPM1CNT	      
	LDHX #$8888
	STHX TPM1MOD				;Reseteo el contador de TPM moviendo el TPM1MOD	      
	BCLR SCI1C2_TIE,SCI1C2			;Deshabilito la interrupcion de SCI1
						;De este modo me evito que se aniden interrupciones de serial
  
	CLI					;Bajo la bandera global de Interrupciones
						;Para que RTC pueda seguir interrumpiendo y el sonido no se detenga.

wait:   LDHX TPM1CNT

	CPHX #$8840
	BLO  wait		   		;Rutina de espera para dejar que la nota suene antes de cambiarla.
		

	LDX  Counter
	LDA  #$3000,X
        STA SCI1D
        BRCLR SCI1S1_TC ,SCI1S1, *      	;Se transmite el dato por el puerto serial       
	STA RTCMOD				;Meto la nota en RTCMOD para que pueda sonar
        LDA SCI1S1     				;Se baja la bandera de transmisión para poder volverla usar
        INC Counter				;Incremento Contador
        BSET SCI1C2_TIE,SCI1C2			;Vuelvo a habilitar la interrupcion de Serial 
        RTI


En esta rutina de transmision por interrupciones podemos observar que hay que hacer una espera, durante la cual se desea que otros dispositivos puedan seguir operando normalmente por medio de sus mecanismos de interrupcion habituales.

Referencias