Práctica
5.a Interrupciones externas
El
objetivo de esta práctica es que el estudiante experimente
con el uso de las
interrupciones. El CPU,
en todo momento está ejecutando un programa, y las interrupciones
son un mecanismo para que se detenga y atienda a
algún dispositivo. Por ejemplo
en la PC existen interrupciones (IRQ),
que
atienden a dispositivos como el teclado con la IRQ=1, el disco duros
con IRQ=5, etc. En el caso de
los microcontroladores, las interrupciones se pueden encontrar en el
UART, temporizadores, PWM, etc. También puede disponer de
interrupciones externas generadas cuando cambia el nivel de voltaje
que recibe una patita asociada a una interrupción.
El
controlador de interrupciones es responsable de procesar las
solicitudes de interrupción (IRQ) y presentarlas en el orden
apropiado al CPU. El controlador de interrupción está diseñado
para recibir hasta 96 IRQ desde periféricos en el chip capaces de
generar Interrupciones, y cinco entradas externas. Todas las IRQ se
muestrean en el flanco ascendente de SYSCLK y se pone a uno la
bandera correspondiente en los registros IFSx. Solo las
interrupciones externas se pueden configurar para que se activen en
el flanco ascendente o en en el descendente de la señal de la
interrupción. Una IRQ pendiente se indica cuando el bit que le
corresponde en un registro IFSx es igual a “1”. El IRQ pendiente
no causará más procesamiento si el bit correspondiente en el
registro de habilitación de interrupción (IECx) está en cero
(cleared). En otras palabras, los bits IECx actúan para habilitar
las interrupciones. Todas las IRQ se codifican en un de vector con
una longitud igual a 64. Dado que hay más IRQ que los números de
vectores disponibles, algunos IRQ comparten números de vectores
comunes. A cada entrada del vector se le asigna un número de
prioridad de interrupción y número de conjunto registros sombra
(SRS=Shadow Registers Set).
Registros
Sombra(SRS)
Cuando
el CPU atiende una interrupción, abandona la tarea que estaba
realizando y ejecuta la rutina asociada a la interrupción. Cuando
termina de ejecutar la rutina de la interrupción regresa a continuar
la ejecución anterior. Para que el CPU pueda regresar a continuar
con la ejecución de la tarea que estaba realizando antes de ser
interrumpido, se guarda información como variables locales y
registros del CPU, este proceso de guardar y restaurar el estado de
ejecución se le conoce como cambio de contexto y puede consumir
bastantes ciclos de CPU. En el caso de los PIC32, se tienen los SRS
para reducir la cantidad de ciclos de CPU necesarios para realizar
los cambios de contexto. Los SRS son registros adicionales a los que
posee el CPU y que no requieren ser salvados. Por lo tanto cuando el
CPU abandona la tarea que estaba realizando no se requiere que se
salven los registros del CPU, pues al ejecutar el código asociado a
la interrupción se usa otro juego de registros, los registros
sombra, cuando regresa a la tarea anterior solo continua usando los
registros originales del CPU y los SRS usados ya no son necesarios.
Nivel
de prioridad
El
nivel de prioridad está determinado por la configuración del
registro IPCx del vector asociado. En el modo Multi-Vector, el
usuario puede seleccionar un nivel de prioridad para recibir un
conjunto de registro sombra dedicado. En el modo de un solo vector,
todas las interrupciones pueden recibir un conjunto de sombras
dedicado. El controlador de interrupción selecciona la IRQ de mayor
prioridad entre todas las IRQs pendientes y presenta el número de
vector asociado, el nivel de prioridad y el número de conjunto de
registros sombras al CPU. La sub-prioridad es para que el
controlador de interrupciones pueda elegir que interrupción
presentar al CPU en caso de que se generaran interrupciones con el
mismo nivel de prioridad.
El
modulo de interrupciones dispone de los siguientes registros
SFR(Special Function Registers):
• INTCON
Registro de control de interrupciones
• INTSTAT
Registro de estatus
• TPTMR
Registro de proximidad temporal del timer (ver DS61108E-p24)
• IFSx
Registro de la bandera de estatus
• IECx
Registro del control de habilitación
• IPCx
Registro del control de prioridad
Modo
mono-vector y multi-vector
Después
de un “reset” el controlador de interrupciones está configurado
para funcionar como mono-vector. En este modo todas las fuentes de
interrupción tienen un número único de vector y para identificar
la fuente se usa la ecuación: “Single Vector Address = EBase +
0x200”, para mas detalles ver capítulo 8.6.2 del documento
DS61108E. Cuando se usa el modo multi-vector cada fuente de
interrupción posee su propio número de vector, este modo aunque
consume mas RAM, es mucho más rápido y fácil de usar. En esta
práctica es el que se usará.
Interrupciones
externas
En
esta familia de microcontroladores se pueden tener hasta 5
interrupciones externas, sin embargo cada microcontrolador en
particular dispone de un número igual o menor debido
a la cantidad de patitas disponibles. En el caso del PIC32MX220F032B
solo se dispone de una interrupción externa, la INT0.
Figura
5.1 Segmento de la Tabla 7.1 de la hoja de datos de la familia PIC32
(DS61168D-p88)
Pasos
para configurar las interrupciones
- Elegir modo, ya sea mono ó multi-vector, si es multi-vector se pone a uno el bit MVEC(12) del registro INTCON
- Se establecen las propiedades de la interrupción. En la figura 5.1, se puede ver que la interrupción cero (INT0) Tiene el vector 3, su bandera se encuentra en el bit 3 de IFS0, el bit de habilitación se encuentra en el bit 3 de IEC0 y su prioridad se fija en los bits 28, 27 y 26 del registro IPC0 y la sub-prioridad en los bits 25 y 24 del mismo registro IPC0.
- Se define la función que se ejecutará cuando se active la interrupción (DS51686E-p133). Esta función ya se encuentra predefinida y esta definición es la misma para todas las interrupciones, tanto internas como externas. Esta función es: void __ISR(3, IPL7AUTO) invierte_led(void){
void No
regresa parámetros
__ISR Nombre
función (Interrupt Service Routine)
3 Número
de vector de INT0
IPL7 IPL7 Interrup Priority Level 7,
AUTO Se
elige de forma automática el uso de los SRS, si el microcontrolador
dispone de ellos
apaga_led(void) Nombre
de función definida por el usuario, no recibe parámetros
Para
establecer la fuente de interrupción se puede usar una macro ya
definida, que para el caso de INT0 es “_EXTERNAL_0_VECTOR”.
En este manual se prefiere usar el número del vector de
interrupción.
Equipo
-
Computadora personal
-
Fuente de poder de laboratorio
-
Osciloscopio digital
-
Programador ICD3, PICkit3 o equivalente
Material:
Cantidad Descripción
1 PIC32MX220F032B
1 Resistencia
de 10kΩ
2 Resistencia
de 1 kΩ
2 Diodo
Emisor de luz (Led)
1 Tablilla
para prototipo (Protoboard)
Figura
5.1 Este “push button” está conectado a la patita 16.
Para
construir el circuito para la práctica, se agrega el circuito de la
figura 5.1 al circuito del sistema mínimo.
El
programa
/*
*
x32_05a.c
*
Autor: Jesus Acosta
*
11 Abril 2019
*
Ejemplo de interrupci'on externa
*
Usa oscilador FRCPLL
*
Micro = PIC32MX220F032B
*
No requiere el uso de plib.h
*/
#include
<p32xxxx.h>
#include
<sys/attribs.h> //Para las macros de Interrupciones
#pragma
config ICESEL = ICS_PGx2 //PGEC = pin 22
//PGED
= pin 21
#pragma
config JTAGEN = OFF // Deshabilita JTAG
#pragma
config FSOSCEN = OFF // Deshabilita oscilador secundario
#pragma
config FWDTEN = OFF // Deshabilita watchdog timer
#pragma
config FNOSC=FRCPLL // Usa oscilador FRC con PLL [8MHz]]
//#pragma
config FPLLIDIV=DIV_4 // Pero con PLL FPLLIDIV no lo divide
//
Entonces entran 4MHZ
#pragma
config FPLLMUL=MUL_16 // Multiplica por 16 [Ahora 64MHz]
#pragma
config FPLLODIV=DIV_8 // Divide entre 8 [Ahora 8MHz]
#pragma
config FPBDIV = DIV_1 // Divide entre 1 el reloj a los
perif'ericos
#pragma
config DEBUG = OFF // Se pone a On para depuraci'on usando
ICD3
void
__ISR(3, IPL7AUTO) invierte_led(void); //Prototipo funci'on
int
main(void); //Prototipo funcion main
//**************
Programa principal **********************
int
main(void){
TRISACLR
= 0x0010; //Se pone a cero bit 4 de TRISA (Output)
LATASET
= 0x0010; //Se pone a uno bit LATA4
__builtin_disable_interrupts();
//Deshabilita todas las interrupciones
IEC0bits.INT0IE
= 0; // Inhabilita interrupci'on externa INT0
INTCONbits.MVEC
= 1; // Multivector habilitado
INTCONbits.INT0EP
= 0; // Se activa en flanco negativo
IPC0bits.INT0IP
= 7; // Prioridad, 7 la mas alta
IPC0bits.INT0IS
= 3; // Sub-prioridad
IFS0bits.INT0IF
= 0; // Se baja bandera
IEC0bits.INT0IE
= 1; // Habilita interrupci'on INT0
__builtin_enable_interrupts();
//Habilita todas las interrupciones
//Ciclo
infinito haciendo nada
while(1){
asm("nop");
//Un periodo Tcy Haciendo nada
}
}
//Funci'on
que se ejecuta cuando se activa INT0
//void
__ISR(_EXTERNAL_0_VECTOR, IPL7AUTO) invierte_led(void){
void
__ISR(3, IPL7AUTO) invierte_led(void){
LATAINV
= 0x0010; //Invierte estado bit 4 (0000 0000 0001 0000)
IFS0bits.INT0IF
= 0; //Se baja bandera de INT0
}
Descripción
del programa:
Esta
práctica consiste en un programa donde el CPU está ejecutando un
ciclo infinito en cuyo interior solo se encuentra la instrucción
“nop” que es un periodo Tcy inactivo del CPU. Cuando se presiona
el “push-button” que se encuentra conectado a la patita 16, se
dispara la INT0 y esto fuerza a que el CPU abandone el ciclo infinito
y ejecute la rutina(función) asociada a la INT0. Esta función solo
cambia el estado del bit RA4. Si tenía un uno, cambia a cero, y
si tenía un cero cambia a uno. Después regresa al ciclo infinito


No hay comentarios.:
Publicar un comentario