Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
1.1 Introducción
Con este documento se pretende introducir al lector en el manejo de las interrupciones y
los temporizadores en la plataforma ENT2004CF. Este documento esta estructurado en 3
grandes partes:
En primer lugar se aborda el estudio de los temporizadores y su gestión para generar
interrupciones periódicas en tiempo real, que son las utilizadas para llevar un control del
tiempo en los sistemas.
En segundo lugar realizaremos un ejemplo en el que se captura una interrupción
externa producida por un flanco de subida en uno de los terminales de entrada de
interrupción.
En tercer lugar programaremos que se produzca una interrupción interna cuando se
cumpla un tiempo establecido (fin de temporización) posterior a la detección de un
flanco de subida en una entrada de captura de entrada.
En los tres casos abordaremos el desarrollo del tutorial centrándonos en un programa
desarrollado en ensamblador al que le faltan ciertas partes de algunas instrucciones, que
debemos ir completando a medida que avancemos por el tutorial.
1.2 Tutorial para el manejo de temporizadores e interrupciones en tiempo
real
En esta parte vamos a desarrollar un programa que, tras escribir una frase de comienzo
(“COMIENZA EL PROGRAMA”), va escribiendo letra a letra el mensaje “CADA SEGUNDO
ESCRIBO UNA LETRA”. Entre escritura de letras consecutivas, se realiza una pausa de 1
segundo aproximadamente. Este tiempo de espera se configura mediante un temporizador
y una interrupción asociada a dicho temporizador. En la Figura 1 vemos un ejemplo de la
ejecución del programa.
Comenzará el tutorial realizando una copia del código fuente del ejemplo (InterrTimer.asm),
en su directorio de trabajo. Esta copia será la que utilice a lo largo del tutorial, para ir
modificando las instrucciones incompletas. A continuación, abra dicho fichero con el editor
de textos.
1.2.1 Estructura del programa InterrTimer.asm
ICR1: registro de control de interrupciones. Para el caso del temporizador 0, los bits de
control son 12, 13 y 14 para fijar el nivel de prioridad, y 15 es el bit que indica si hay
interrupción pendiente. Para cambiar el nivel de prioridad, además de escribir en los
bits 12, 13 y 14, hay que escribir un 1 en el bit 15.
31 30 28 27 26 24 23 22 20 19 18 16 15 14 12 11 10 8 7 6 4 3 2 0
INT1 INT1 INT2 INT2 INT3 INT3 INT4 INT4 TMR0 TMR0 TMR1 TMR1 TMR2 TMR2 TMR3 TMR3 xPI: interrupción pendiente (1) o no (0)
ICR1 xIPL: nivel de prioridad de interrupción
PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL
TRR0: registro que contiene el valor final del contador que indica el final de la cuenta, y
por tanto, el vencimiento del tiempo programado.
TCN0: registro que actúa sobre el contador permitiendo inicializarlo a 0.
15 0
TCNn Contador
TCAPn Captura
TRRn Referencia
SR: registro de estado del microcontrolador donde se habilitan las interrupciones del
sistema.
C: acarreo (C=1)
V: desbordamiento (V=1)
CCR Z: cero (Z=1)
N: negativo (N=1)
X: extensión (X=1)
15 13 12 10 9 8 4 3 2 1 0 I2-I0: máscara interrup.
M: maestro (M=1)
SR T - S M - I2I1I0 - - X N Z V C S: supervisor (S=1)
T: traza (T=1)
Al igual que en la primera parte debemos comenzar realizando una copia del código fuente
del ejemplo (InterrExterna.asm), en el directorio de trabajo. Esta copia será la que utilice a
lo largo del tutorial, para ir modificando las instrucciones incompletas. A continuación, abra
dicho fichero con el editor de texto.
1.3.1 Estructura del programa InterrExterna.asm
De igual forma al caso anterior, el programa contenido en este fichero está estructurado en
4 zonas principales:
Una primera zona en la que se definen las constantes que vamos a utilizar a lo largo
del programa (DEFINICIÓN DE CONSTANTES). Entre las constantes definidas se
encuentran las direcciones de memoria donde están los registros que nos van a
permitir configurar la interrupción externa INT1. Además de estas direcciones de
memoria, aparecen las constantes SISTEMA y OUT que contienen respectivamente
los valores del número de la TRAP del sistema (15 en nuestro caso), y el código
asociado con la salida de un carácter en la pantalla del ordenador. A continuación,
tenemos las constantes asociadas a la dirección de comienzo del programa y de las
variables, y las asociadas a los vectores de interrupción.
La segunda zona (DEFINICIÓN DE VARIABLES) contiene las posiciones de memoria
donde vamos a guardar cierta información a lo largo del programa y que actúan como
variables. Esta zona está establecida a partir de la posición DIR_VARIABLES ($30000)
en memoria.
La tercera parte lo constituye el propio programa en sí (COMIENZO DEL
PROGRAMA). Esta zona comienza a partir de la posición DIR_PROGRAMA ($20000)
en memoria. Como se puede observar este programa siempre comienza en la etiqueta
PPAL y debe terminar en un bucle infinito que se queda esperando a que se produzca
alguna interrupción externa. En nuestro caso, el bucle está comprendido entre la
etiqueta BUCLE y la instrucción BRA BUCLE. Todos los programas que
desarrollaremos deben terminar en un bucle infinito o bien ser ellos mismo un bucle
infinito. De no ser así el contador de programa PC seguiría avanzando hasta salirse de
la zona de memoria donde está alojado el programa produciendo un error de ejecución.
La primera acción que realizamos al comienzo del programa es situar el puntero de la
pila en la posición DIR_PILA ($30000). Esta dirección es la posición de comienzo de la
zona de variables pero no habrá ningún problema puesto que el acceso a la pila se
hace siempre con PREDECREMENTO (se decrementa el puntero antes de guardar el
dato en la pila) con lo que se comenzará a almacenar a partir de la posición $2FFFF
hacia abajo.
A continuación del programa se encuentran todas las subrutinas que serán llamadas
desde el programa principal (DEFINICIÓN DE SUBRUTINAS) y que veremos en los
apartados siguientes.
1.3.2 Funcionamiento general del programa InterrExterna.asm
ICR1: registro de control de interrupciones. Para el caso de INT1, los bits de control
son: 28, 29 y 30 para fijar el nivel de prioridad y el 31 es el bit que indica si hay
interrupción pendiente.
31 30 28 27 26 24 23 22 20 19 18 16 15 14 12 11 10 8 7 6 4 3 2 0
INT1 INT1 INT2 INT2 INT3 INT3 INT4 INT4 TMR0 TMR0 TMR1 TMR1 TMR2 TMR2 TMR3 TMR3 xPI: interrupción pendiente (1) o no (0)
ICR1 xIPL: nivel de prioridad de interrupción
PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL
SR: registro de estado del microcontrolador donde se habilitan las interrupciones del
sistema.
C: acarreo (C=1)
V: desbordamiento (V=1)
CCR Z: cero (Z=1)
N: negativo (N=1)
X: extensión (X=1)
15 13 12 10 9 8 4 3 2 1 0 I2-I0: máscara interrup.
M: maestro (M=1)
SR T - S M - I2I1I0 - - X N Z V C S: supervisor (S=1)
T: traza (T=1)
De igual forma al caso anterior, el programa contenido en este fichero está estructurado en
4 zonas principales:
Una primera zona en la que se definen las constantes que vamos a utilizar a lo largo
del programa (DEFINICIÓN DE CONSTANTES). Entre las constantes definidas se
encuentran las direcciones de memoria donde están los registros que nos van a
permitir configurar tanto los dos temporizadores como la interrupción interna generada
(MCFSIM_*). Además de estas direcciones de memoria, aparecen las constantes
SISTEMA y OUT que contienen respectivamente el valor del número de la TRAP del
sistema (15 en nuestro caso) y el código asociado con la salida de un carácter en la
pantalla del ordenador. A continuación, tenemos las constantes asociadas a la
dirección de comienzo del programa y de las variables, y las asociadas a los vectores
de interrupción.
La segunda zona (DEFINICIÓN DE VARIABLES) contiene las posiciones de memoria
donde vamos a guardar cierta información a lo largo del programa y que actúan como
variables. Esta zona está definida a partir de la posición DIR_VARIABLES ($30000) en
memoria.
La tercera parte lo constituye el propio programa en sí (COMIENZO DEL
PROGRAMA). Esta zona comienza a partir de la posición DIR_PROGRAMA ($20000)
en memoria. Como se puede observar este programa siempre comienza en la etiqueta
PPAL y debe terminar en un bucle infinito que se queda esperando a que se produzca
alguna interrupción externa. En nuestro caso, el bucle está comprendido entre la
etiqueta BUCLE y la instrucción BRA BUCLE. Todos los programas que
desarrollaremos deben terminar en un bucle infinito o bien ser ellos mismo un bucle
infinito. De no ser así, el contador de programa PC seguiría avanzando hasta salirse de
la zona de memoria donde está alojado el programa produciendo un error de ejecución.
La primera acción que realizamos al comienzo del programa es situar el puntero de la
pila en la posición DIR_PILA ($30000). Esta dirección es la posición de comienzo de la
zona de variables pero no habrá ningún problema puesto que el acceso a la pila se
hace siempre con PREDECREMENTO (se decrementa el puntero antes de guardar el
dato en la pila) con lo que se comenzará a almacenar a partir de la posición $2FFFF
hacia abajo.
A continuación del programa se encuentran todas las subrutinas que serán llamadas
desde el programa principal (DEFINICIÓN DE SUBRUTINAS) y que veremos en los
apartados siguientes.
1.4.2 Funcionamiento general del programa FinTemp.asm
ICR1: registro de control de interrupciones. Para el caso del temporizador 0, los bits de
control son 12, 13 y 14 para fijar el nivel de prioridad, y 15 es el bit que indica si hay
interrupción pendiente. Para el temporizador 1, los bits de control son 8, 9 y 10 para fijar
el nivel de prioridad, y 11 es el bit que indica si hay interrupción pendiente.
31 30 28 27 26 24 23 22 20 19 18 16 15 14 12 11 10 8 7 6 4 3 2 0
INT1 INT1 INT2 INT2 INT3 INT3 INT4 INT4 TMR0 TMR0 TMR1 TMR1 TMR2 TMR2 TMR3 TMR3 xPI: interrupción pendiente (1) o no (0)
ICR1 xIPL: nivel de prioridad de interrupción
PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL PI IPL
TRR0/TRR1: registros que contienen el valor final del contador que indica el final de la
cuenta, y por tanto, el vencimiento del tiempo programado.
TCN0/TCN1: registros de los contadores, que permiten leerlos (sin detener su cuenta) y
permiten su inicialización a 0.
15 0
TCNn Contador
TCAPn Captura
TRRn Referencia
SR: registro de estado del microcontrolador donde se habilitan las interrupciones del
sistema.
C: acarreo (C=1)
V: desbordamiento (V=1)
CCR Z: cero (Z=1)
N: negativo (N=1)
X : extensión (X=1)
15 13 12 10 9 8 4 3 2 1 0 I2-I0: máscara interrup.
M: maestro (M=1)
SR T - S M - I2I1I0 - - X N Z V C S: supervisor (S=1)
T: traza (T=1)
1.5.1.1 InterrTimer.asm
****************************************************************************
* INTERRTIMER.ASM: EJEMPLO PARA APRENDER EL MANEJO DE INTERRUPCIONES
* TEMPORIZADAS MEDIANTE UN TEMPORIZADOR CON EL SISTEMA COLDFIRE 5272
*
* AUTORES: RUBÉN SAN SEGUNDO, JUAN MANUEL MONTERO Y RICARDO DE CÓRDOBA
***************************************************************************
LEA DIR_TIMER0,A0
MOVE.L #BBB_BBBBBB?,(A0) * ESCRIBIMOS LA DIRECCIÓN DE LA
SUBRUTINA.
1.5.1.2 InterrTimer.c
//------------------------------------------------------------------------------
// InterrTimer.c
// Ejemplo para aprender el manejo de interrupciones temporizadas
// y fines de temporización mediante un temporizador con el sistema
// ENT2004CF.
//
// Autores: Juan Manuel Montero, Rubén San Segundo y Ricardo de Córdoba
// Adaptado a C por: Javier Guillén Álvarez
//------------------------------------------------------------------------------
#include "m5272.h"
#include "m5272lib.c"
1.5.2.1 InterrExterna.asm
****************************************************************************
* INTERREXTERNA.ASM: EJEMPLO PARA APRENDER EL MANEJO DE INTERRUPCIONES
* EXTERNAS EL SISTEMA COLDFIRE 5272
*
* AUTORES: JUAN MANUEL MONTERO, RUBÉN SAN SEGUNDO Y RICARDO DE CÓRDOBA
***************************************************************************
*********** DEFINICIÓN DE CONSTANTES **********************
MCF_MBAR EQU $10000000 * DIRECCIÓN BASE
MOVE.L #MCFSIM_ICR1,A0
MOVE.L #EEEEEEEEE?,(A0) * MARCAMOS LA INTERRUPCIÓN INT1
* COMO NO PENDIENTE Y DE NIVEL 3.
* HABILITAMOS INTERRUPCIONES
MOVE.W SR, D0
ANDI.L
MOVE.W #$F8FF,D0
D0,SR
RTS
***********************************************************
* RUTINA PARA SACAR UNA CADENA POR PANTALLA
PRINTCAD ADDA.L #-60, A7
MOVEM.L D0-D7/A0-A6,(A7)
CLR.L D1
SIG_CAR MOVE.B (A0)+,D1
MOVE.L #OUT,D0
TRAP #SISTEMA
CMPA.L A0,A1
BNE SIG_CAR
MOVEM.L (A7),D0-D7/A0-A6
ADDA.L #60,A7
RTS
***********************************************************
* RUTINA DE INTERRUPCIÓN PARA INT1
SUB_INT1 ADDA.L #-60, A7
MOVEM.L D0-D7/A0-A6,(A7)
1.5.2.2 InterrExterna.c
//------------------------------------------------------------------------------
// InterrExterna.c
// Ejemplo para aprender el manejo de interrupciones externas con la
// plataforma ENT2004CF.
//
// Autores: Ricardo de Córdoba, Juan Manuel Montero y Rubén San Segundo
// Adaptado a C por: Javier Guillén Álvarez
//------------------------------------------------------------------------------
#include "m5272.h"
#include "m5272lib.c"
#define V_BASE 0x40 // Dirección de inicio de los vectores de
interrupción
#define DIR_VINT1 4 * (V_BASE + 1) // Dirección del vector de INT1
//------------------------------------------------------
// void rutina_int1(void)
// Descripción:
// Función de atención a la interrupción para la
// interrupción externa.
//------------------------------------------------------
void rutina_int1(void)
{
// Imprime el mensaje de la interrupción
output("HE DETECTADO UN FLANCO DE SUBIDA\r\n");
// Al ser interrupción externa debemos volverla a activar
mbar_writeLong(MCFSIM_ICR1, 0xB8888888);
}
//------------------------------------------------------
// void __init(void)
//
// Descripción:
Función por defecto de inicialización del sistema
//------------------------------------------------------
void __init(void)
{
// Fijamos el comienzo de vectores de interrupción en V_BASE
mbar_writeByte(MCFSIM_PIVR,V_BASE);
// Escribimos la dirección de la función de atención a la interrupción
ACCESO_A_MEMORIA_LONG(DIR_VINT1) = (ULONG) _prep_INT1;
// Imprimimos el mensaje de comienzo
output("COMIENZA EL PROGRAMA\r\n");
// Configuramos INT1 para que se active con flanco de subida
mbar_writeLong(MCFSIM_PITR, mbar_readLong(MCFSIM_PITR) | 0x80000000);
// Marcamos la interrupción INT1 como no pendiente y de nivel 3
mbar_writeLong(MCFSIM_ICR1, 0xB8888888);
// Habilitamos interrupciones
sti();
}
//------------------------------------------------------
// void bucleMain(void)
// Descripción:
// Función del programa principal
//------------------------------------------------------
void bucleMain(void){}
//---------------------------------------------------------
// Definición de rutinas de atención a la interrupción
// Es necesario definirlas aunque estén vacías
void rutina_int2(void){}
void rutina_int3(void){}
void rutina_int4(void){}
void rutina_tout0(void){}
void rutina_tout1(void){}
void rutina_tout2(void){}
void rutina_tout3(void){}
1.5.3.1 FinTemp.asm
****************************************************************************
* FINTEMP.ASM: EJEMPLO PARA APRENDER EL MANEJO DE INTERRUPCIONES
* TEMPORIZADAS Y FINES DE TEMPORIZACIÓN MEDIANTE UN TEMPORIZADOR CON EL
* SISTEMA COLDFIRE 5272
*
* AUTORES: RICARDO DE CÓRDOBA, JUAN MANUEL MONTERO Y RUBÉN SAN SEGUNDO
***************************************************************************
*********** DEFINICIÓN DE CONSTANTES ****************
MCF_MBAR EQU $10000000 * DIRECCIÓN BASE
BSR REINIT
BUCLE2 TST.B CAP_RECIBIDA
BNE BUCLE2
MOVE.L MCFSIM_TMR1,D0
BCLR.L #16,D0
MOVE.L D0,MCFSIM_TMR1 * Y SE PARA
BRA BUCLE
* TODOS LOS PROGRAMAS DEBEN TERMINAR CON UN BUCLE INFINITO AL FINAL
LEA DIR_TIMER0,A0
MOVE.L #FFF_FFFFFF?,(A0) * DIRECCIÓN DE LA SUBRUTINA.
LEA DIR_TIMER1,A0
MOVE.L #GGG_GGGGGG?,(A0) * DIRECCIÓN DE LA SUBRUTINA.
MOVE.W #$4F45,(A0)
MOVE.L #MCFSIM_TMR1,A0 * TIMER1: COMPARACIÓN SALIDA
MOVE.W #HHHHH?,(A0)
MOVE.L #MCFSIM_ICR1,A0
MOVE.L #IIIIIIIII?,(A0) * MARCA LA INTERRUPCIÓN DE TIMER0
* Y TIMER1
* COMO NO PENDIENTE Y DE
* PRIORIDADES 2 y 4
* HABILITAMOS INTERRUPCIONES
MOVE.W SR, D0
ANDI.L #$F8FF,D0
MOVE.W D0,SR
RTS
***********************************************************
* RUTINA DE REINICIALIZACIÓN
REINIT MOVE.L #MCFSIM_TCN1,A0 * PONEMOS A 0 EL CONTADOR DEL TIMER0.
MOVE.W #$0000,(A0)
MOVE.L MCFSIM_TMR1,D0
BSET.L #16,D0
MOVE.L D0,MCFSIM_TMR1 * COMIENZA TIMER1
RTS
***********************************************************
* RUTINA PARA SACAR UNA CADENA POR PANTALLA
PRINTCAD ADDA.L #-60, A7
MOVEM.L D0-D7/A0-A6,(A7)
CLR.L D1
SIG_CAR MOVE.B (A0)+,D1
MOVE.L #OUT,D0
TRAP #SISTEMA
CMPA.L A0,A1
BNE SIG_CAR
MOVEM.L (A7),D0-D7/A0-A6
ADDA.L #60,A7
RTS
***********************************************************
* RUTINA DE INTERRUPCIÓN PARA TIMER0
* Configurado como captura de entrada
SUB_TIMER0 ADDA.L #-60, A7
MOVEM.L D0-D7/A0-A6,(A7)
1.5.3.2 FinTemp.c
//------------------------------------------------------------------------------
// FinTemp.c
// Ejemplo para aprender el manejo de interrupciones temporizadas
// y fines de temporización mediante un temporizador con el sistema
//
// ENT2004CF.
// Autores: Ricardo de Córdoba, Juan Manuel Montero y Rubén San Segundo
// Adaptado a C por: Javier Guillén Álvarez
//------------------------------------------------------------------------------
#include "m5272.h"
#include "m5272lib.c"
#define V_BASE 0x40 // Dirección de inicio de los vectores
de interrupción
#define DIR_VTMR0 4*(V_BASE+5) // Dirección del vector de TMR0
#define DIR_VTMR1 4*(V_BASE+6) // Dirección del vector de TMR1
#define PERIODO_INTERR 2 // Periodo de interrupción de TMR1
#define CNT_INT1 MCF_CLK*PERIODO_INTERR/(0x84*16) // Valor de precarga del
temporizador de interrupciones TRR1
#define BORRA_CAP 0x0001 // Valor de borrado de interr.
pendientes de tout1 para TER1
#define BORRA_REF 0x0002 // Valor de borrado de interr.
pendientes de tout1 para TER1
//---------------------------------------------------------
// Definición de rutinas de atención a la interrupción
// Es necesario definirlas aunque estén vacías
void rutina_int1(void){}
void rutina_int2(void){}
void rutina_int3(void){}
void rutina_int4(void){}
void rutina_tout2(void){}
void rutina_tout3(void){}
2 Anexo I: Soluciones a los tutoriales
Tabla 3. Soluciones del tutorial para la gestión de una interrupción producida por finalización de un temporizador
25