martes, 22 de enero de 2013

Evitar alteraciones de registros por interrupción

Durante una interrupción el único registro que se salvaguarda en la pila, es el contador de programa. La subrutina de atención a la interrupción puede alterar el contenido de nuestros registros del microcontrolador. Por esta razón al iniciar la rutina de atención a la interrupción es conveniente guardar el valor de nuestros registros y restaurarlos antes de la instrucción retfie.
A simple vista, guardar los datos y restaurarlos sin modificar los contenidos parece fácil, el contenido de los registros W y STATUS deben guardarse primero y después los demás datos que puedan variar su valores durante la interrupción.
Para dejar mas claro esto, a continuación se expondrá la manera en que no esta correcto el guardado de datos y la correcta.


            ORG    0          ;Inicio del programa
            goto     Inicio
            ORG    4          ; Vector de interrupción
            goto     Serviciodeinterrupcion

Inicio
---------
Subrutina “Serviciodeinterrupcion”
; Esta subrutina puede alterar los registros, asi que debemos preservar su valor previo

            CBLOCK
            Guarda_W
            Guarda_STATUS
            Guarda_RegistroA
            Guarda_ RegistroB
            ….
            ENDC
;Ya se preservaron los valores de W y STATUS
Serviciodeinterrupcion
            movwf              Guarda_W      ;Guarda W y STATUS
            movf                STATUS,W       ;Esta instrucción altera el registro STATUS
            movwf              Guarda_STATUS        
            movf                RegistroA,W
            movwf              Guarda_RegistroA       ;Guarda RegistroA alterado
            movf                RegistroB,W                 ;Guarda RegistroB
            movwf              Guarda_RegistroB      
            …
; Aquí va el resto de la rutina de atención
            …
;Ahora se deben restaurar los valores de los registros
            movf                Guarda_RegistroB,W   ;Restaura el contenido de B
            movwf              RegistroB        
            movf                Guarda_RegistroA,W
            movwf              RegistroA                     ; Restaura el contenido de A
            movf                Guarda_STATUS,W     ;Esta instrucción ha alterado el contenido de
            movwf              STATUS                                   ;STATUS
            movf                Guarda_W,W             ;Esta instrucción vuelve a alterar STATUS
            bcf                   INTCON,INTF               ;Limpia la Flag para la interrupción
            retfie                                                   ;Retorna a antes de la interrupción



La parte del programa anterior esta errónea ya que al mover un registro cualquiera al registro de trabajo W corrompe el flag Z y modifica el registro STATUS, lo que se recomiendo para evitar este tipo de problemas es lo siguiente:


;No se puede usar la instrucción “movf STATUS,W” porque corrompe el contenido de STATUS
Serviciodeinterrupcion
            movwf              Guarda_W      ;Guarda W y STATUS
            swapf               STATUS,W       ;Asi no se altera el registro STATUS
            movwf              Guarda_STATUS        
            movf                RegistroA,W
            movwf              Guarda_RegistroA       ;Guarda RegistroA
            movf                RegistroB,W                 ;Guarda RegistroB
            movwf              Guarda_RegistroB      
            …
            bcf                   STATUS,RP0                 ;Asegurar que trabajamos en el banco 0
; Aquí va el resto de la rutina de atención
            …
;Ahora se deben restaurar los valores de los registros
            movf                Guarda_RegistroB,W   ;Restaura el contenido de B
            movwf              RegistroB        
            movf                Guarda_RegistroA,W
            movwf              RegistroA                     ; Restaura el contenido de A
            swapf               Guarda_STATUS,W     ;Restaura STATUS con su valor original
            movwf              STATUS                                  
            swapf               Guarda_W,F               ;Restaura W como estaba antes
            swapf               Guarda_W,W
            bcf                   INTCON,INTF               ;Limpia la Flag para la interrupción
            retfie                                                   ;Retorna a antes de la interrupción



La función de la instrucción “swapf STATUS, W” mueve los datos sin afectar el registro STATUS, aunque antes del proceso los nibles se intercambian, posteriormente son restaurados y esto sin afectar ninguna de las banderas como la Z, evitando hacer “movf STATUS,W” y no se altera la bandera Z.


No hay comentarios:

Publicar un comentario