miércoles, 1 de febrero de 2012

Interrupciones en SDCC-Parte 1

Breve introducción a las Interrupciones con PIC18


En los PIC tenemos varias fuentes de interrupciones y en los PIC18 tenemos un sistema de dos niveles de prioridad(alta y baja), si el micro se encuentra atendiendo una de baja prioridad y ocurre una de alta,   atiende a esta y luego vuele a atender la primera, de forma contraria no ocurre.
El vector de interrupciones de alta prioridad se encuentra en la dirección 0x0008 y en la 0x0018 se encuentra el de baja prioridad.
Este sistema puede estar habilitado o no, a través del bit IPEN. En caso que no se encuentre habilitado se tiene un único vector que comienza en 0x0008.
Existen 10 registros para manejar las interrupciones:

  • RCON

  • INTCON

  • INTCON2

  • INTCON3

  • PIR1, PIR2

  • PIE1, PIE2

  • IPR1, IPR2
La diferentes fuentes de interrupciones tienen todas 3 bits por los cuales se la controla:
  • Bit enabled: Se lo llama xxxIE(IE=Interrupt Enabled). Básicamente es para habilitar(1) o no(0) el evento como interrupción.

  • Bit de prioridad: De forma genérica se llaman xxxIP(IP=Interrupt Priority). Permite configurar la fuente como de alta(1) o baja(0) prioridad

  • Bit de Flag: Llamados xxxIF(IF=Interrupt Flag). Indica si el evento ocurrió(1) o no(0). Este bit cambia aun si no esta habilitada como interrupción el evento. Este bit se debe poner a 0 manualmente una vez que es atendida la interrupción.
Además de los bits individuales de cada evento, existen ciertos bits globales que son necesarios de configurar. Estos son:

  • GIE/GIEH: si se trabaja con el sistema de prioridades habilita todas las interrupciones de alta prioridad, en caso que no se usen prioridades habilita todas las interrupciones,(todas las que se han activado a través de bit individual).

  • PEIE/GEIL: en el caso de usar el sistema de prioridades habilita las de baja prioridad, en caso contrario habilita las interrupciones de los periféricos del micro.

  • IPEN: Como se menciono antes, para habilitar el sistema de prioridades.
Es recomendable consultar la sección 9 de la hoja de datos, para ampliar sobre el tema.

Ahora veamos como trabajar con las interrupciones en SDCC.
La configuración de los bits se realiza de forma básica accediendo al bit correspondiente y poniendo el valor deseado, como se hizo en el ejemplo “Hola mundo”.
Necesitamos saber como crear los servicios de interrupciones y que el compilador lo entienda.
Podemos trabajar de dos formas diferentes con las interrupciones. Haciendo uso de la directiva del compilador o bien recurriendo a la librería “signal.h” que es parte de SDCC.
Veamos la primer opción, en esta se debe crear un función en la que se hace uso de la palabra clave interrupt. La sintaxis es:

void isr(void) interrupt n {
//Cuerpo del servicio de interrupción.
}

n es el numero de interrupción, que según se detalla para los PIC18 es:


n


Vector de interrupción


Dirección


0


Reset


0x00000


1


Alta Prioridad


0x00008


2


Baja Prioridad


0x00018


En el caso de que no se trabaje con prioridades se deberá adoptar n=1.

Cuando se genera el código en asm el compilador sitúa un GOTO en el vector de interrupciones correspondiente apuntando a la función isr, dicha función es situada normalmente como cualquier otra función en el espacio de código. Podríamos declarar la función como __naked de este modo la función isr se sitúa en el vector de interrupción correspondiente, esto podría ser un problema si se esta trabajando con prioridades y el servicio para las altas prioridades es tan largo que termina pisando el vector correspondiente a las de baja prioridad. Usando esta directiva estaremos obligados a indicar el retorno de la interrupción.

void isr(void) interrupt n __naked{
//Cuerpo del servicio de interrupción.
__asm
retfie
__endasm;
}

Otra directiva que tenemos para las funciones que atienden una interrupción es __shadowregs la cual le indica al compilador que no almacene y recupere los registros WREG, STATUS, BSR, valiéndose de la característica de los PIC18 que mantienen el valor de dichos registros cuando se entra en una interrupción.

Veamos un ejemplo practico en el que se hace uso del TMR0 para hacer parpadear un led, utilizando interrupciones.

El hardware es el mismo que en el ejemplo del “Hola mundo”. Y este es el codigo:


//Definiciones para hacer mas legible el codigo
#define LED_TRIS TRISBbits.TRISB0
#define LED_PIN LATBbits.LATB0

//Agrego la librería de los pic para cargar configuraciones y variables y se agrega la librería delay provista por el compilador.
#include "pic18fregs.h"

static __code char __at __CONFIG1H conf1 = _OSC_INTOSC__INTOSC_CLK0_RA6___USB_EC_1H; // Activo oscilador interno
static __code char __at __CONFIG4L conf2 = _LVP_OFF_4L; // Deshabilito LVP
static __code char __at __CONFIG2H conf3 = _WDT_DISABLED_CONTROLLED_2H; // Deshabilito WDT

//Servicio de rutina
void TMR0_isr(void) __naked __interrupt 1
{
INTCONbits.TMR0IF = 0; //Limpio el Flag de TMR0
LED_PIN ^= 1;
__asm
retfie
__endasm;
}

//Programa principal
void main(){
//Inicialización
OSCCON = 0b11110011; //Configuro oscilador int en 8MHZ
LED_TRIS = 0; //Configuro como salida
INTCONbits.TMR0IE = 1; //Habilito interrupción de TMR0 por overflow
INTCONbits.TMR0IF = 0; //Limpio flag de interrupción
INTCONbits.GIE = 1; //Habilito interrupciones globales
T0CONbits.T08BIT = 0; //Timer configurado como contador de 16bits
T0CONbits.T0CS = 0; //Selecciono como reloj el ciclo de introducción
T0CONbits.PSA = 0; //Prescaler Activado
T0CONbits.T0PS2 = 1; //Configuro Prescaler en 256
T0CONbits.T0PS1 =0;
T0CONbits.T0PS0 =0;
TMR0L = 0; //Pongo en 0 la cuenta
T0CONbits.TMR0ON = 1; //Habilito el Timer0
//Fin de inicialización

while(1){
}
}

En este ejemplo, al ser el servicio tan simple, se decidió situar el código directamente en el vector de interrupciones. Tampoco se verifico si realmente la interrupción correspondía al timer0, se dio por sentado ya que en el programa principal fue la única interrupción que se habilito, lo que disminuyo enormemente el código generado, esto se puede ver en el archivo *.lst que se genera al momento de la compilación.

Todo ese proceso de inicialización se podría reducir con mascaras, lo que mejora el código final, sin embargo se dispuso así para que sea mas legible.
Comparte este articulo
  • Comparte con Facebook
  • Comparte con Twitter
  • Comparte con Google+
  • Comparte con Stumble Upon
  • Comparte con Evernote
  • Comparte con Blogger
  • Comparte con Email
  • Comparte con Yahoo Messenger
  • More...

0 comentarios:

Publicar un comentario