Diferencia entre revisiones de «IRQ (External Interrupt Request) - MC9S08QE128»

De Wikitronica
Saltar a: navegación, buscar
(Ejemplo de interrupcion de IRQ)
 
(No se muestran 25 ediciones intermedias de 4 usuarios)
Línea 1: Línea 1:
 
[[Categoría:MC9S08QE128]]
 
[[Categoría:MC9S08QE128]]
[[Archivo:IRQpin.jpg|400px|thumb|right|]]  
+
[[Archivo:IRQpin.jpg|400px|thumb|right|Ubicación del botón de IRQ en el micro MC9S08QE128]]  
  
 
<div style="top:+0.3em; text-align: center;font-size:100%; border:1px solid #C7D0F8; background:#F2F5FD;width:80%">
 
<div style="top:+0.3em; text-align: center;font-size:100%; border:1px solid #C7D0F8; background:#F2F5FD;width:80%">
Línea 14: Línea 14:
 
==Funcionamiento==
 
==Funcionamiento==
  
[[Image:IRQ Diagrama de Bloques.jpeg|thumb|450px|right]]
+
[[Image:IRQ Diagrama de Bloques.jpeg|thumb|450px|Diagrama de bloques IRQ]]
  
Dependiendo de la configuración de la MCU, una interrupción por IRQ se genera por un nivel bajo o por una transición de nivel alto a un nivel bajo en el pin IRQ.  Al detectarse una interrupción la bandera IRQF se coloca en 1 y se produce una petición de interrupción.
+
Dependiendo de la configuración de la MCU, un evento externo dispara la interrupción del IRQ por un nivel bajo o por una transición de nivel alto a un nivel bajo en el pin IRQ.  Al detectarse una interrupción la bandera IRQF se coloca en 1 y se comienza la rutina de servicio de la interrupción, tan pronto como cuando termine la última instrucción ejecutándose.
  
Para volver a realizar una petición de interrupción,  se puede limpiar la bandera escribiendo un 1 lógico en el bit ACK del registro IRQSC. Si se limpia la bandera IRQF y se genera una nueva interrupción antes de que el pin regrese a un nivel alto, la petición de interrupción queda pendiente.  
+
El funcionamiento del IRQ por un flanco descendente, el más usual por convención, se ilustra en la siguiente imagen:
 +
 
 +
[[Image:IRQ edge and level.jpeg|thumb|500px|left]]
 +
 
 +
 
 +
Para volver a realizar una petición de interrupción,  se puede limpiar la bandera escribiendo un 1 lógico en el bit ACK del registro IRQSC. Si se limpia la bandera IRQF y se genera una nueva interrupción antes de que el pin regrese a un nivel alto, la petición de interrupción queda pendiente.
  
 
==Registro IRQSC==
 
==Registro IRQSC==
  
::::::[[Archivo:IRQSC.jpg]]
+
::::::[[Archivo:IRQSC.jpg]] '''Registros del IRQ'''
 +
 
  
 
* '''IRQPDD. Interrupt Request (IRQ) Pull Device Disable:''' Si el bit IRQPE=1, entonces este bit permite deshabilitar o habilitar los dispositivos de pull-up, dependiendo de la polaridad escogida (IRQPDD). Por default habilita los dispositivos.
 
* '''IRQPDD. Interrupt Request (IRQ) Pull Device Disable:''' Si el bit IRQPE=1, entonces este bit permite deshabilitar o habilitar los dispositivos de pull-up, dependiendo de la polaridad escogida (IRQPDD). Por default habilita los dispositivos.
Línea 30: Línea 36:
  
 
*'''IRQEDG. Interrupt Request (IRQ) Edge Select:''' Este bit permite escoger los la polaridad de los flancos o niveles detectados en el pin IRQ, que causa el levantamiento de la bandera IRQF. Cuando IRQEDG=1 y se habilita el dispositivo de pull-up, este es reconfigurado como un dispositivo opcional pull-down.
 
*'''IRQEDG. Interrupt Request (IRQ) Edge Select:''' Este bit permite escoger los la polaridad de los flancos o niveles detectados en el pin IRQ, que causa el levantamiento de la bandera IRQF. Cuando IRQEDG=1 y se habilita el dispositivo de pull-up, este es reconfigurado como un dispositivo opcional pull-down.
 
  
 
:  0 el pin IRQ es sensible a un flanco descendente o un flanco descendente y nivel bajo
 
:  0 el pin IRQ es sensible a un flanco descendente o un flanco descendente y nivel bajo
Línea 62: Línea 67:
 
   
 
   
 
* Enmascarar las interrupciones, limpiando el bit IRQIE del registro IRQSC
 
* Enmascarar las interrupciones, limpiando el bit IRQIE del registro IRQSC
* Seleccionar a conveniencia la polaridad del pin, forzando el bit IRQEDG del registro IRQSC. Si este bit esta en "0", IRQF se activa al reconocer un flanco de bajada en la señal de reloj. Si esta en "1", IRQF se activa al reconocer un flanco de subida.  
+
* Seleccionar a conveniencia la polaridad del pin, forzando el bit IRQEDG del registro IRQSC. Si este bit está en "0", IRQF se activa al reconocer un flanco de bajada en la señal de reloj. Si está en "1", IRQF se activa al reconocer un flanco de subida.  
 
* Si se va a utilizar un dispositivo de pull-up/pull-down, limpiar el bit IRQPDD en el IRQSC
 
* Si se va a utilizar un dispositivo de pull-up/pull-down, limpiar el bit IRQPDD en el IRQSC
 
* Habilitar el pin IRQ forzando a "1" el bit IRQPE del IRQSC
 
* Habilitar el pin IRQ forzando a "1" el bit IRQPE del IRQSC
Línea 68: Línea 73:
 
* Colocar un 1 en el IRQIE del IRQSC para habilitar las interrupciones.
 
* Colocar un 1 en el IRQIE del IRQSC para habilitar las interrupciones.
  
A continuación se vera como configurar el IRQ, siguiendo los pasos descritos anteriormente  
+
A continuación se verá cómo configurar el IRQ, siguiendo los pasos descritos anteriormente
  
 
==Configuración del IRQ==
 
==Configuración del IRQ==
Línea 108: Línea 113:
 
===Configuración del puerto de reloj del IRQ===
 
===Configuración del puerto de reloj del IRQ===
  
El ultimo paso para configurar IRQ se refiere al manejo del registro SCGC2 (Sistema de control de puertos de reloj 2) para controlar el puerto de reloj del IRQ.
+
El último paso para configurar IRQ se refiere al manejo del registro SCGC2 (Sistema de control de puertos de reloj 2) para controlar el puerto de reloj del IRQ.
  
El IRQ corresponde al bit 5 del registro SCGC2 y se debe colocar "1" para permitir que la señal de reloj de la interrupción de de IRQ se habilite. La manera de hacerlo es la siguiente:
+
El IRQ corresponde al bit 5 del registro SCGC2 y se debe colocar "1" para permitir que la señal de reloj de la interrupción de IRQ se habilite. La manera de hacerlo es la siguiente:
  
 
<syntaxhighlight lang="asm">
 
<syntaxhighlight lang="asm">
Línea 129: Línea 134:
 
==Rutina de Interrupción==
 
==Rutina de Interrupción==
  
Primero que nada se debe buscar el vector de interrupción que contiene la dirección de la rutina que debe llamar para atender una petición de interrupción del IRQ, en el caso del MC9S08QE128 corresponde a la dirección $0000FFFA.
+
En primer lugar, se debe buscar el vector de interrupción que contiene la dirección de la rutina que debe llamar para atender una petición de interrupción del IRQ, en el caso del MC9S08QE128 corresponde a la dirección $0000FFFA.
 +
 
 +
El vector de interrupción se define con la instruccion DC.W seguido del nombre que se le haya dado a la rutina de interrupción del IRQ. En assembler hay que definir el vector de interrupción de la siguiente manera:
 +
 
 +
 
 +
<syntaxhighlight lang="asm">
 +
 
 +
;**************************************************************
 +
;*                Interrupt Vectors                          *
 +
;**************************************************************
 +
            ORG  $FFFA            ; Posición en memoria donde se encuentra el vector de interrupción
 +
            DC.W  Rutina_IRQ      ; Rutina de interrupcion de IRQ
 +
</syntaxhighlight>
  
El vector de interrupción se define con la instruccion DC.W seguido del nombre que se le haya dado a la rutina de interrupción del IRQ (Como se puede ver al final del ejemplo de interrupcion de IRQ).
 
  
 
La interrupción del IRQ ocurre si se cumple que:
 
La interrupción del IRQ ocurre si se cumple que:
Línea 145: Línea 161:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
+
==Ejemplo de interrupción de IRQ==
==Ejemplo de interrupcion de IRQ==
+
 
El siguiente código realiza una interrupción por IRQ sobre un programa, para encender y apagar los leds del DEMOQE:
 
El siguiente código realiza una interrupción por IRQ sobre un programa, para encender y apagar los leds del DEMOQE:
  
Línea 153: Línea 168:
 
;                    Codigo para realizar una interrupcion por IRQ  
 
;                    Codigo para realizar una interrupcion por IRQ  
 
;****************************************************************************************************
 
;****************************************************************************************************
 
+
 
; Include derivative-specific definitions
 
; Include derivative-specific definitions
 
             INCLUDE 'derivative.inc'
 
             INCLUDE 'derivative.inc'
Línea 165: Línea 180:
 
;
 
;
 
             ORG    ROMStart
 
             ORG    ROMStart
 
+
 
_Startup:   
 
_Startup:   
 
             LDHX  #RAMEnd+1        ; initialize the stack pointer
 
             LDHX  #RAMEnd+1        ; initialize the stack pointer
 
             TXS
 
             TXS
 +
 +
 
Main:      SEI
 
Main:      SEI
             LDA  #$42             ;se carga 2 al acumulador
+
             LDA  #$42             ;se carga 2 al acumulador
             STA  SOPT1             ;se guarda en SOPT1
+
             STA  SOPT1           ;se guarda en SOPT1
 
             ; COPE  = 0, COPT  = 1, STOPE = 0, 0, 0, RSTOPE= 0,  
 
             ; COPE  = 0, COPT  = 1, STOPE = 0, 0, 0, RSTOPE= 0,  
             ;BKGDPE= 1 ;; se habilita el backroung debug mode
+
             ; BKGDPE= 1 ;; se habilita el background debug mode
 
             ; RSTPE = 0 ;; se deshabilita el RESET
 
             ; RSTPE = 0 ;; se deshabilita el RESET
             BSR Configurar_GPIO          
+
 
+
             BSR Configurar_GPIO
;; Configuracion del IRQSC
+
             BSR Configurar_IRQ
             lda #%00010110          ; se carga el numero 16 hexadecimal al acumulador
+
   
            sta IRQSC              ; se guarda en el registro IRQSC
+
             CLI                   ; habilitar interrupciones
                                    ;        0
+
                                    ; IRQPDD= 0
+
Loop:       BRA    Loop            ; un BRA * tendria este mismo efecto de loop
                                    ; IRQEDG= 0
+
                                    ; IRQPE = 1 ;; se habilita el IRQ pin enable
+
                                    ; IRQF = 0
+
                                    ; IRQACK= 1 ;; se habilita el ACKNOWLEDGE
+
                                    ; IRQIE = 1 ;; se habilita el IRQ interrupt enable
+
                                    ; IRQMOD= 0
+
             CLI                     ; habilitar interrupciones
+
Fin:       BRA    Fin              ; un BRA * tendria este mismo efecto de loop
+
 
+
 
;**************************************************************
 
;**************************************************************
 
;            Subrutina de configuracion                      *
 
;            Subrutina de configuracion                      *
 
;**************************************************************
 
;**************************************************************
 
+
 
Configurar_GPIO:   
 
Configurar_GPIO:   
                LDA #$3F              ; Se escogen los 6 leds de PTCD
+
            LDA #$3F              ; Se escogen los 6 leds de PTCD
                STA PTCDD              ;...       
+
            STA PTCDD              ;...       
                STA PTCD
+
            STA PTCD
                LDA #$C0              ; Se escogen los 2 leds de PTED
+
            LDA #$C0              ; Se escogen los 2 leds de PTED
                STA PTEDD              ;...
+
            STA PTEDD              ;...
                STA PTED              ;logica negada (Inicializamos los leds apagados)  
+
            STA PTED              ;logica negada (Inicializamos los leds apagados)  
                RTS
+
            RTS
 
+
 +
Configurar_IRQ:
 +
            LDA #$20    ; 0010 0000
 +
            STA SCGC2
 +
            LDA #%00010110        ; se carga el numero 16 hexadecimal al acumulador
 +
            STA IRQSC              ; se guarda en el registro IRQSC
 +
            RTS                    ; IRQPDD= 0
 +
                                  ; IRQEDG= 0
 +
                                  ; IRQPE = 1 ;; se habilita el IRQ pin enable
 +
                                  ; IRQF  = 0
 +
                                  ; IRQACK= 1 ;; se habilita el ACKNOWLEDGE
 +
                                  ; IRQIE = 1 ;; se habilita el IRQ interrupt enable
 +
                                  ; IRQMOD= 0
 +
 
;**************************************************************
 
;**************************************************************
;*                RUTINAS DE INTERRUPCION                   *
+
;*                Rutinas de Interrupción                   *
;*                                                            *
+
 
;**************************************************************
 
;**************************************************************
 
+
rutinaIRQ:
+
Rutina_IRQ:  
         LDA PTCD
+
            BSET    IRQSC_IRQACK, IRQSC         ; Se limpia la bandera IRQF
        CMP #$FF
+
            LDA PTCD
        BEQ Encender_Leds
+
            CMP #$3F
 +
            BEQ Encender_Leds
 
Apagar_Leds:     
 
Apagar_Leds:     
        MOV #$FF, PTCD
+
            MOV #$FF, PTCD
        MOV #$FF, PTED
+
            MOV #$FF, PTED
        RTI
+
            RTI
 
Encender_Leds:
 
Encender_Leds:
        MOV #00, PTCD
+
            MOV #00, PTCD
        MOV #00, PTED
+
            MOV #00, PTED
        RTI
+
            RTI
 
+
 
;**************************************************************
 
;**************************************************************
 
;* spurious - Spurious Interrupt Service Routine.            *
 
;* spurious - Spurious Interrupt Service Routine.            *
 
;*            (unwanted interrupt)                          *
 
;*            (unwanted interrupt)                          *
 
;**************************************************************
 
;**************************************************************
spurious:                           ; placed here so that security value
+
spurious:                         ; placed here so that security value
             NOP                     ; does not change all the time.
+
             NOP                   ; does not change all the time.
 
             RTI
 
             RTI
 +
 
;**************************************************************
 
;**************************************************************
 
;*                Interrupt Vectors                          *
 
;*                Interrupt Vectors                          *
 
;**************************************************************
 
;**************************************************************
             ORG  $FFFA           ; <--- IMPORTANTE COLOCAR EL VECTOR EN EL ORIGEN CORRECTO
+
             ORG  $FFFA           ; <--- IMPORTANTE COLOCAR EL VECTOR EN EL ORIGEN CORRECTO
             DC.W  rutinaIRQ       ; ...con el nombre que se le haya dado a la rutina de interrupcion de IRQ
+
             DC.W  Rutina_IRQ       ; ...con el nombre que se le haya dado a la rutina de interrupcion de IRQ
             DC.W  spurious       ; SWI
+
             DC.W  spurious         ; SWI
             DC.W  _Startup       ; Reset
+
             DC.W  _Startup         ; Reset
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 243: Línea 268:
 
Para realizar una pausa a un programa se puede utilizar la interrupción por IRQ, los pasos a seguir son:
 
Para realizar una pausa a un programa se puede utilizar la interrupción por IRQ, los pasos a seguir son:
  
* Configurar IRQ como se explico anteriormente
+
* Configurar IRQ como se explicó anteriormente
 
* Configurar el SOPT1 para habilitar PTA5 con IRQ colocando RSTPE=0, en el registro SOPT1.  
 
* Configurar el SOPT1 para habilitar PTA5 con IRQ colocando RSTPE=0, en el registro SOPT1.  
* Una vez en la rutina de interrupción de IRQ, verificar que el puerto de reloj de RTC este activo.
+
* Una vez en la rutina de interrupción de IRQ, verificar que el puerto de reloj de RTC esté activo.
* Si esta activo habrá que deshabilitarlo para detener el programa al presionar PTA5.
+
* Si está activo habrá que deshabilitarlo para detener el programa al presionar PTA5.
* Si no esta activo habrá que habilitarlo para permitir que el programa vuelva a correr al volver a presionar PTA5.
+
* Si no está activo habrá que habilitarlo para permitir que el programa vuelva a correr al volver a presionar PTA5.
  
El puerto de reloj de RTC se encuentra en el registro SCGC2, al igual que el del IRQ. Al momento de deshabilitar el puerto de reloj del RTC es importante recordar '''no deshabilitar''' el de IRQ, pues de lo contrario el programa solo hará la rutina de interrupción una vez y el programa no volvera a correr.
+
El puerto de reloj de RTC se encuentra en el registro SCGC2, al igual que el del IRQ. Al momento de deshabilitar el puerto de reloj del RTC es importante recordar '''no deshabilitar''' el de IRQ, pues de lo contrario el programa solo hará la rutina de interrupción una vez y el programa no volverá a correr.
  
 
<syntaxhighlight lang="asm">
 
<syntaxhighlight lang="asm">
Línea 255: Línea 280:
 
           LDA #$20            ; 0010 0000   
 
           LDA #$20            ; 0010 0000   
 
                                 ; El bit 5 es el puerto de reloj del IRQ, debe estar siempre en "1".
 
                                 ; El bit 5 es el puerto de reloj del IRQ, debe estar siempre en "1".
           CMP SCGC2            ; Se verifica qe el puerto de reloj de RTC este activo
+
           CMP SCGC2            ; Se verifica qe el puerto de reloj de RTC esté activo
           BEQ Habilitar_RTC    ; Si no lo esta se habilita
+
           BEQ Habilitar_RTC    ; Si no lo está se habilita
  
 
;; Si ya esta activo no hara en branch, por lo que se deshabilita el puerto de reloj del RTC
 
;; Si ya esta activo no hara en branch, por lo que se deshabilita el puerto de reloj del RTC
Línea 267: Línea 292:
  
  
;; Si no esta activo hara el branch y se pasa a habilitar el puerto de reloj del RTC
+
;; Si no está activo hará el branch y se pasa a habilitar el puerto de reloj del RTC
 
Habilitar_RTC:
 
Habilitar_RTC:
 
           LDA #$24          ; 0010 0100
 
           LDA #$24          ; 0010 0100
Línea 273: Línea 298:
 
           STA SCGC2
 
           STA SCGC2
 
           RTI                ; retorna de la interrupción
 
           RTI                ; retorna de la interrupción
 +
</syntaxhighlight>
 +
 +
 +
Otra forma de realizar una pausa en un programa que funciona mediante interrupciones del RTC, sin tocar el reloj de éste en el registro SCGC2, es habilitar o deshabilitar según sea el caso las interrupciones del RTC, colocando el bit correspondiente en el RTIE del registro RTCSC. El procedimiento sería:
 +
 +
<syntaxhighlight lang="asm">
 +
IRQISR:
 +
          LDA RTCSC
 +
          AND #%00010000      ; Se hace una mascara al bit 4 (RTIE)
 +
          CMP #$00            ; Se verifica que las interrupciones del RTC estén habilitadas
 +
          BEQ Habilitar_RTIE  ; Si no lo está, se habilita
 +
 +
 +
;; Si ya está activo no hará el branch, por lo que se deshabilitan las interrupciones del RTC
 +
Deshabilitar_RTIE:
 +
          BCLR RTCSC_RTIE, RTCSC
 +
          RTI                    ; retorna de la interrupción
 +
 +
 +
;; Si no está activo se hará el branch y se pasa a habilitar las interrupciones del RTC
 +
Habilitar_RTIE:
 +
          BSET RTCSC_RTIE, RTCSC
 +
          RTI                    ; retorna de la interrupción
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 278: Línea 326:
 
El Instruction Set de los Microcontroladores HCS08 contiene instrucciones directamente vinculadas con el uso del pin IRQ, como:
 
El Instruction Set de los Microcontroladores HCS08 contiene instrucciones directamente vinculadas con el uso del pin IRQ, como:
  
*BIH: Branch if IRQ Pin High. Comprueba el estado del pin de interrupción externo y realiza un salto si el pin esta en un nivel alto.
+
*BIH: Branch if IRQ Pin High. Comprueba el estado del pin de interrupción externo y realiza un salto si el pin está en un nivel alto.
 
:If IRQ pin = 1, PC ← (PC) + $0002 + rel
 
:If IRQ pin = 1, PC ← (PC) + $0002 + rel
 
[[Image:BIH.jpeg|thumb|400px|center]]
 
[[Image:BIH.jpeg|thumb|400px|center]]
  
*BIL: Branch if IRQ Pin Low. Comprueba el estado del pin de interrupción externo y realiza un salto si el pin esta en un nivel bajo.
+
*BIL: Branch if IRQ Pin Low. Comprueba el estado del pin de interrupción externo y realiza un salto si el pin está en un nivel bajo.
 
:If IRQ pin = 0, PC ← (PC) + $0002 + rel
 
:If IRQ pin = 0, PC ← (PC) + $0002 + rel
  
 
[[Image:BIL.jpeg|thumb|400px|center]]
 
[[Image:BIL.jpeg|thumb|400px|center]]
 
El registro CCR no se ve afectado por estas instrucciones.
 
El registro CCR no se ve afectado por estas instrucciones.
 
  
 
==Referencias==
 
==Referencias==
  
 
*[http://www.freescale.com/files/microcontrollers/doc/ref_manual/MC9S08QE128RM.pdf''MC9S08QE128RM Reference Manual'']
 
*[http://www.freescale.com/files/microcontrollers/doc/ref_manual/MC9S08QE128RM.pdf''MC9S08QE128RM Reference Manual'']

Revisión actual del 11:35 1 abr 2013

Ubicación del botón de IRQ en el micro MC9S08QE128
Este artículo está incompleto. Necesita trabajo adicional. Revisar la discusión.

Introducción

El pin de IRQ se puede usar para activar interrupciones de hardware externas. Dependiendo de la configuración de la MCU, una interrupción por IRQ se genera por nivel bajo o por una transición de nivel alto a nivel bajo en el pin IRQ. Este tipo de interrupción se puede usar para supervisar sistemas externos o eventos.

Las interrupciones externas son manejadas por el registro de control y status del IRQ (IRQSC). Cuando la función del IRQ está habilitada, lógica síncrona supervisa el pin para detectar un flanco descendente o un flanco descendente y nivel bajo. Cuando el MCU está en modo stop o los relojes del sistema estén detenidos, un método asíncrono separado es usado para que el pin IRQ (si este está habilitado) pueda despertar el MCU.

Cada tipo de interrupción tiene una prioridad predefinida asociada. La interrupción del módulo IRQ externa tiene la prioridad más alta, después del evento de Reset y SWI. Cuando ocurren múltiples interrupciones, la CPU primero mira la prioridad de los eventos y servicios del evento con la prioridad más alta, con los otros pendientes.

Funcionamiento

Diagrama de bloques IRQ

Dependiendo de la configuración de la MCU, un evento externo dispara la interrupción del IRQ por un nivel bajo o por una transición de nivel alto a un nivel bajo en el pin IRQ. Al detectarse una interrupción la bandera IRQF se coloca en 1 y se comienza la rutina de servicio de la interrupción, tan pronto como cuando termine la última instrucción ejecutándose.

El funcionamiento del IRQ por un flanco descendente, el más usual por convención, se ilustra en la siguiente imagen:

IRQ edge and level.jpeg


Para volver a realizar una petición de interrupción, se puede limpiar la bandera escribiendo un 1 lógico en el bit ACK del registro IRQSC. Si se limpia la bandera IRQF y se genera una nueva interrupción antes de que el pin regrese a un nivel alto, la petición de interrupción queda pendiente.

Registro IRQSC

IRQSC.jpg Registros del IRQ


  • IRQPDD. Interrupt Request (IRQ) Pull Device Disable: Si el bit IRQPE=1, entonces este bit permite deshabilitar o habilitar los dispositivos de pull-up, dependiendo de la polaridad escogida (IRQPDD). Por default habilita los dispositivos.
0 Habilita los dispositivos de pull-up IRQPE=1
1 Deshabilita los dispositivos de pull-up IRQPE=1
  • IRQEDG. Interrupt Request (IRQ) Edge Select: Este bit permite escoger los la polaridad de los flancos o niveles detectados en el pin IRQ, que causa el levantamiento de la bandera IRQF. Cuando IRQEDG=1 y se habilita el dispositivo de pull-up, este es reconfigurado como un dispositivo opcional pull-down.
0 el pin IRQ es sensible a un flanco descendente o un flanco descendente y nivel bajo
1 el pin IRQ es sensible a un flanco ascendente o un flanco ascendente y nivel alto
  • IRQPE. IRQ Pin Enable: Este bit habilita la función del pin IRQ. IRQPE debe ser 1 para que el pin IRQ pueda actuar como una entrada por petición de interrupción.
0 Función del pin IRQ deshabilitada
1 Función del pin IRQ habilitada
  • IRQF. IRQ Flag: Este bit indica si ha ocurrido una petición de interrupción.
0 No se detecto una petición por IRQ
1 Se detecto un evento del IRQ
  • IRQACK. IRQ Acknowledge: Este bit permite limpiar la bandera IRQF si se fuerza IRQACK=1. Forzarla a 0 no tiene ningún significado o efecto. La lectura de este bit siempre retorna 0.
  • IRQIE. IRQ Interrupt Enable: Este bit de control determina si los eventos del IRQ generan una petición de interrupción
0 Deshabilitadas las peticiones de interrupción cuando IRQF=1
1 Habilitadas las peticiones de interrupción cuando IRQF=1
  • IRQMOD. IRQ Detection Mode: Este bit de control determina si el pin de IRQ es sensible a un único flanco o a un flanco y nivel.
0 sensible sólo a flancos descendentes o flacos ascendentes
1 sensible a flanco descendente y nivel bajo o flanco ascendente y nivel alto

Inicialización

Cuando se habilita por vez primera el pin de IRQ, es posible obtener una falsa bandera de interrupción. Para evitar esta falsa petición de interrupción, se debe inicializar el IRQ de la siguiente manera:

  • Enmascarar las interrupciones, limpiando el bit IRQIE del registro IRQSC
  • Seleccionar a conveniencia la polaridad del pin, forzando el bit IRQEDG del registro IRQSC. Si este bit está en "0", IRQF se activa al reconocer un flanco de bajada en la señal de reloj. Si está en "1", IRQF se activa al reconocer un flanco de subida.
  • Si se va a utilizar un dispositivo de pull-up/pull-down, limpiar el bit IRQPDD en el IRQSC
  • Habilitar el pin IRQ forzando a "1" el bit IRQPE del IRQSC
  • Colocar un 1 en el IRQACK del IRQSC para limpiar cualquier falsa interrupción. Esto generalmente se hace dentro de la rutina de interrupción del IRQ, para que cada vez que se entre se limpie la bandera IRQF.
  • Colocar un 1 en el IRQIE del IRQSC para habilitar las interrupciones.

A continuación se verá cómo configurar el IRQ, siguiendo los pasos descritos anteriormente

Configuración del IRQ

La configuración del IRQ se hace mediante el manejo de tres registros: SOPT1, IRQSC y SCGC2.

El IRQ tiene la limitación de que posee un solo botón, el cual además comparte con RESET. Es debido a esto que el primer paso para configurar IRQ es deshabilitar el pin de RESET. El RESET pin enable (RSTPE) esta contenido en el registro SOPT1 y se configura modificando el bit 0. "1" indica que el pin esta habilitado, "0" que esta deshabilitado.

El SOPT1 es un registro de 8 bits, entre los cuales se encuentra tambien el COP (Computer Operating Properly) o watchdog, que fuerza al programa a reiniciarse si este se pierde o no se comporta como era esperado. Para evitar que el programa se reinicie el COP puede deshabilitarse colocando en "1" el bit 6 (COPT) y el bit 1 (BKGDPE) del registro SOPT1. Estos bits corresponden al COP Timeout y al Backroung Debug Mode Pin Enable respectivamente. De esta manera si se coloca:


LDA  #$42         ; bits 1 y 6 en "1", bit 0 en "0"
STA  SOPT1        ; $1802

Se deshabilita tanto el COP como el pin de RESET.

Configuración del pin IRQ

El siguiente paso es habilitar las interrupciones y el pin del IRQ, para esto se utiliza el registro IRQSC. El IRQPE en el registro IRQSC debe estar habilitado para que el pin IRQ pueda actuar como una entrada por petición de interrupción.


En este caso nos interesa habilitar los bits 1, 2 y 4. El bit 1 es el IRQIE (Interrupt Enable) con el cual se habilitan las interrupciones del IRQ, el bit 2 es el IRQACK (Acknowledge)que reconoce que se dio una interrupcion y el bit 4 es el IRQPE (Pin Enable) con el cual se habilita el pin del IRQ. Una forma de habilitar los bits es la siguiente:

LDA  #$16         ; 0001 0110
STA  IRQSC        
; IRQPDD=0, IRQEDG=0, IRQPE= 1, IRQF=  0, IRQACK=1, IRQIE= 1, IRQMOD=0

Siendo el IRQ una entrada, el usuario puede escoger la polaridad de los flancos o niveles detectados (IRQEDG) y si el pin detecta un flanco o un flanco y nivel (IRQMOD). En general se puede colocar el IRQEDG=0 y el IRQMOD=0, para que la bandera IRQF se active solo con flancos de bajada de la señal de reloj, como se hizo en este caso.

Cuando el pin de IRQ es habilitado utiliza por defecto un dispositivo de pull-up o pull-down dependiendo de la polaridad escogida (IRQPDD=0).

La bandera IRQF se levanta cuando se detecta el cambio en el flanco del pin IRQ esperado, y no se puede limpiar la bandera mientras el pin IRQ permanezca en este nivel. La bandera IRQF se limpia forzando IRQACK=1.


Configuración del puerto de reloj del IRQ

El último paso para configurar IRQ se refiere al manejo del registro SCGC2 (Sistema de control de puertos de reloj 2) para controlar el puerto de reloj del IRQ.

El IRQ corresponde al bit 5 del registro SCGC2 y se debe colocar "1" para permitir que la señal de reloj de la interrupción de IRQ se habilite. La manera de hacerlo es la siguiente:

LDA #$20    ; 0010 0000
STA SCGC2

Una vez realizados estos pasos se podrán realizar interrupciones por IRQ presionando el boton correspondiente a PTA5.

Jumper J18

Antes de empezar a codificar y trabajar con el pin IRQ se debe verificar que los Jumpers del DEMOQE128 posea la configuración adecuada para su funcionamiento. El pin IRQ depende de que el RESET_EN del jumper J18 este colocado de la siguiente manera:

Jumper18.jpeg

Para más información acerca de los jumpers, revisar el artículo JUMPER SETTINGS.

Rutina de Interrupción

En primer lugar, se debe buscar el vector de interrupción que contiene la dirección de la rutina que debe llamar para atender una petición de interrupción del IRQ, en el caso del MC9S08QE128 corresponde a la dirección $0000FFFA.

El vector de interrupción se define con la instruccion DC.W seguido del nombre que se le haya dado a la rutina de interrupción del IRQ. En assembler hay que definir el vector de interrupción de la siguiente manera:


;**************************************************************
;*                 Interrupt Vectors                          *
;**************************************************************
            ORG   $FFFA            ; Posición en memoria donde se encuentra el vector de interrupción 
            DC.W  Rutina_IRQ       ; Rutina de interrupcion de IRQ


La interrupción del IRQ ocurre si se cumple que:

  • La máscara de interrupción global está activa.
  • Están habilitadas las interrupciones del IRQ
  • La interrupción tiene actualmente la prioridad más alta de petición de interrupción.

Dentro de la rutina de interrupción hay que asegurarse de escribir un 1 lógico en el bit IRQACK del IRQSC para limpiar la bandera IRQF, y de esta forma permitir volver a realizar una petición de interrupción.

BSET    IRQSC_IRQACK, IRQSC         ; Se limpia la bandera IRQF

Ejemplo de interrupción de IRQ

El siguiente código realiza una interrupción por IRQ sobre un programa, para encender y apagar los leds del DEMOQE:

;***************************************************************************************************
;                     Codigo para realizar una interrupcion por IRQ 
;****************************************************************************************************
 
; Include derivative-specific definitions
            INCLUDE 'derivative.inc'
;
; export symbols
;
            XDEF _Startup
            ABSENTRY _Startup
;
; code section
;
            ORG    ROMStart
 
_Startup:  
            LDHX   #RAMEnd+1        ; initialize the stack pointer
            TXS
 
 
Main:       SEI
            LDA   #$42             ;se carga 2 al acumulador
            STA   SOPT1            ;se guarda en SOPT1
            ; COPE  = 0, COPT  = 1, STOPE = 0, 0, 0, RSTOPE= 0, 
            ; BKGDPE= 1 ;; se habilita el background debug mode
            ; RSTPE = 0 ;; se deshabilita el RESET
 
            BSR Configurar_GPIO
            BSR Configurar_IRQ
 
            CLI                    ; habilitar interrupciones
 
Loop:       BRA    Loop            ; un BRA * tendria este mismo efecto de loop
 
 
 
;**************************************************************
;             Subrutina de configuracion                      *
;**************************************************************
 
Configurar_GPIO:  
            LDA #$3F               ; Se escogen los 6 leds de PTCD
            STA PTCDD              ;...      
            STA PTCD
            LDA #$C0               ; Se escogen los 2 leds de PTED
            STA PTEDD              ;...
            STA PTED               ;logica negada (Inicializamos los leds apagados) 
            RTS
 
Configurar_IRQ:
            LDA #$20    ; 0010 0000
            STA SCGC2 
            LDA #%00010110         ; se carga el numero 16 hexadecimal al acumulador
            STA IRQSC              ; se guarda en el registro IRQSC
            RTS                    ; IRQPDD= 0
                                   ; IRQEDG= 0
                                   ; IRQPE = 1 ;; se habilita el IRQ pin enable
                                   ; IRQF  = 0
                                   ; IRQACK= 1 ;; se habilita el ACKNOWLEDGE
                                   ; IRQIE = 1 ;; se habilita el IRQ interrupt enable
                                   ; IRQMOD= 0
 
;**************************************************************
;*                 Rutinas de Interrupción                    *
;**************************************************************
 
Rutina_IRQ: 
            BSET    IRQSC_IRQACK, IRQSC         ; Se limpia la bandera IRQF 
            LDA PTCD
            CMP #$3F
            BEQ Encender_Leds
Apagar_Leds:     
            MOV #$FF, PTCD
            MOV #$FF, PTED
            RTI
Encender_Leds:
            MOV #00, PTCD
            MOV #00, PTED
            RTI
 
;**************************************************************
;* spurious - Spurious Interrupt Service Routine.             *
;*             (unwanted interrupt)                           *
;**************************************************************
spurious:                          ; placed here so that security value
            NOP                    ; does not change all the time.
            RTI
 
;**************************************************************
;*                 Interrupt Vectors                          *
;**************************************************************
            ORG   $FFFA            ; <--- IMPORTANTE COLOCAR EL VECTOR EN EL ORIGEN CORRECTO
            DC.W  Rutina_IRQ       ; ...con el nombre que se le haya dado a la rutina de interrupcion de IRQ
            DC.W  spurious         ; SWI
            DC.W  _Startup         ; Reset

Utilidades de interrupción por IRQ

Realizar una pausa a un programa presionando PTA5

Para realizar una pausa a un programa se puede utilizar la interrupción por IRQ, los pasos a seguir son:

  • Configurar IRQ como se explicó anteriormente
  • Configurar el SOPT1 para habilitar PTA5 con IRQ colocando RSTPE=0, en el registro SOPT1.
  • Una vez en la rutina de interrupción de IRQ, verificar que el puerto de reloj de RTC esté activo.
  • Si está activo habrá que deshabilitarlo para detener el programa al presionar PTA5.
  • Si no está activo habrá que habilitarlo para permitir que el programa vuelva a correr al volver a presionar PTA5.

El puerto de reloj de RTC se encuentra en el registro SCGC2, al igual que el del IRQ. Al momento de deshabilitar el puerto de reloj del RTC es importante recordar no deshabilitar el de IRQ, pues de lo contrario el programa solo hará la rutina de interrupción una vez y el programa no volverá a correr.

IRQISR:
           LDA #$20             ; 0010 0000   
                                ; El bit 5 es el puerto de reloj del IRQ, debe estar siempre en "1".
           CMP SCGC2            ; Se verifica qe el puerto de reloj de RTC esté activo
           BEQ Habilitar_RTC    ; Si no lo está se habilita

;; Si ya esta activo no hara en branch, por lo que se deshabilita el puerto de reloj del RTC
Deshabilitar_RTC: 
           LDA #$20             ; 0010 0000 
                                ; El bit 2 es el puerto de reloj del RTC
                                ;... se deshabilita para detener el programa
           STA SCGC2
           RTI                  ; retorna de la interrupción


;; Si no está activo hará el branch y se pasa a habilitar el puerto de reloj del RTC
Habilitar_RTC:
           LDA #$24           ; 0010 0100
                              ; El bit 2 se habilita para que el programa vuelva a correr
           STA SCGC2
           RTI                ; retorna de la interrupción


Otra forma de realizar una pausa en un programa que funciona mediante interrupciones del RTC, sin tocar el reloj de éste en el registro SCGC2, es habilitar o deshabilitar según sea el caso las interrupciones del RTC, colocando el bit correspondiente en el RTIE del registro RTCSC. El procedimiento sería:

IRQISR:
           LDA RTCSC
           AND #%00010000       ; Se hace una mascara al bit 4 (RTIE)
           CMP #$00             ; Se verifica que las interrupciones del RTC estén habilitadas
           BEQ Habilitar_RTIE   ; Si no lo está, se habilita


;; Si ya está activo no hará el branch, por lo que se deshabilitan las interrupciones del RTC
Deshabilitar_RTIE: 
           BCLR RTCSC_RTIE, RTCSC 
           RTI                    ; retorna de la interrupción


;; Si no está activo se hará el branch y se pasa a habilitar las interrupciones del RTC
Habilitar_RTIE:
           BSET RTCSC_RTIE, RTCSC 
           RTI                    ; retorna de la interrupción

Instrucciones Relacionadas

El Instruction Set de los Microcontroladores HCS08 contiene instrucciones directamente vinculadas con el uso del pin IRQ, como:

  • BIH: Branch if IRQ Pin High. Comprueba el estado del pin de interrupción externo y realiza un salto si el pin está en un nivel alto.
If IRQ pin = 1, PC ← (PC) + $0002 + rel
BIH.jpeg
  • BIL: Branch if IRQ Pin Low. Comprueba el estado del pin de interrupción externo y realiza un salto si el pin está en un nivel bajo.
If IRQ pin = 0, PC ← (PC) + $0002 + rel
BIL.jpeg

El registro CCR no se ve afectado por estas instrucciones.

Referencias