Autor Tema: Problema con interrupciones y EEPROM  (Leído 2137 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado qrppablo

  • PIC10
  • *
  • Mensajes: 2
Problema con interrupciones y EEPROM
« en: 17 de Diciembre de 2014, 22:14:57 »
YA SOLUCIONÉ EL PROBLEMA, HABIA COMETIDO UN ERROR CON LAS FLAGS. POR FAVOR NO CONTESTAR, GRACIAS!


Buenas, soy nuevo en el foro y tengo un problema que paso a detallar:

Estoy tratando de modificar un programa en asm para el PIC 16F877A que tiene interrupciones con contador, funciona de esta manera: Cada veinte interrupciones se guardan en EEPROM una serie de bytes, cuando termina, se reinicia el contador y asi sucesivamente. Es una radio, la frecuencia del display se graba mas o menos cada 3 segundos en EEPROM para que cuando se apague y se vuelva a encender aparezca en el display la frecuencia que se había usado antes del apagado.

El codigo es el siguiente:

T1CON_INIT        EQU     0x31    ; Timer1 - Prescale of 8 and enable the timer
INTCON_INIT       EQU     0xC0    ; Interrupt Control- Enable Global and Peripheral
COUNT_OF_INTS  EQU         20        ; Interrupts before saving

int_counter ;  Used to count number of interrupts

;
;

   ORG   0x0000             
reset_entry
        goto    Start             ; Jump around the band table to main program

   ORG   0x0004
interrupt_entry
        goto    interrupt         ; Go to interrupt routine

;
;

Start

        movlw   count_of_ints     ; Get number of interrupts before saving
        movwf   int_counter       ; Initialize the counter

        bcf     PIR1,TMR1IF       ; Reset the Timer 1 interrupt flag
        clrf    TMR1L             ; Set Timer 1 Low and
        clrf    TMR1H             ;     Timer 1 High to maximum count
   Bank1
        bsf     PIE1,TMR1IE       ; Enable Timer 1 overflow interrupt
   Bank0
        movlw   INTCON_INIT       ; Get GIE and PEIE bits and enable
        movwf   INTCON            ;    Global and Peripheral interrupts
        movlw   T1CON_INIT        ; Get T1CKPS1, T1CKPS0 and TMR1ON bits
        movwf   T1CON             ;    and enable Timer 1 with prescale of 8

;
;

interrupt
        movwf    save_w           ; Store W in save_w
       swapf   STATUS,w       ; Move STATUS to W
        clrf           STATUS           ; Force to Bank 0      
        movwf       save_s           ; Store STATUS in save_s
        movf         FSR,w            ; Move FSR into W
        movwf       save_fsr         ; Save FSR

        clrf     T1CON                ; Stop the timer by clearing T1CON
        bsf     int_flags,T1_INT  ; Set the flag for poll_encoder
        bcf     PIR1,TMR1IF       ; Reset the interrupt flag
        clrf    TMR1L                ; Reload Timer 1 Low
        clrf    TMR1H               ;   and Timer 1 High
        movlw   T1CON_INIT     ; Restart Timer 1 with prescale = 8
        movwf   T1CON            ; Timer 1 control

        movf         save_fsr,w       ; Get saved FSR
        movwf       FSR              ; Restore the FSR
       swapf   save_s,w         ; Get saved status
       movwf   STATUS           ; Restore STATUS register (now in pre-interrupt Bank)
       swapf   save_w,f         ;
       swapf   save_w,w         ; Restore W register

       retfie                  

;
;

process_int
        decfsz  int_counter,f     ; Decrement the interrupt counter
        goto    int_exit          ; Not zero, exit

; Guarda freq actual en EEPROM
   
   call   VFOA_save

        movlw   count_of_ints     ; Initialize the counter
        movwf   int_counter       ;   to start over
int_exit
        bcf     int_flags,T1_INT  ; Reset the interrupt flag bit
        goto    proc_int_rtn      ; Back to poll_encoder

Se carga el numero de veces que tienen que realizarse las interrupciones (20) en la variable int_counter, cada vez que se realiza una interrupción, en la rutina process_int se le resta un bit a int_counter, 20 veces hasta llegar a 0, cuando se llega a 0 se llama a la rutina de guardado de los bytes que equivalen a la frecuencia que muestra el display (no puse esta rutina aqui porque creo que no viene al caso). Al terminar de guardar se vuelve a cargar el 20 en int_counter y se reinicia el conteo y asi sucesivamente. En otra rutina en loop va esta otra parte del codigo:

btfsc   int_flags,T1_INT  ; Has a Timer 1 interrupt occurred
          goto    process_int       ; Yes, go process it
proc_int_rtn                      ; Return from interrupt processing

Que es el que va a process_int cada vez que se produce una interrupción.

El problema es que cuando quiero grabar en EEPROM otros datos no puedo, no en la rutina de interrupción, si no por medio de una rutina que se acciona al presionar un botón, supongo que no se puede porque las interrupciones estan activadas? y además de eso cada vez que el conteo llega a 0 se llama a una rutina para grabar en EEPROM?
Ya probé tratando de desactivar las interrupciones pero no se si lo hago mal, ya que cada vez que quiero guardar algún dato en EEPROM no se guarda nada ni tampoco lee nada.

La manera en que intenté desactivar las interrupciones fueron las siguientes:
        
bcf     PIE1,TMR1IE <- Primero probé con poner a 0 TMR1IE justo antes de llamar a guardar en EEPROM, desactiva las interrupciones pero no guarda ni lee.

clrf     T1CON  <- Despues probé con detener el timer justo antes de llamar a guardar en EEPROM, desactiva las interrupciones pero tampoco guarda ni lee.

Los direccionamientos en EEPROM son correctos pero no logro entender por que no guarda ni lee nada...  :5]  :5]  :5]

Resumiendo: necesito frenar las interrupciones para poder grabar manualmente en EEPROM ya que con las interrupciones habilitadas no logro hacerlo.

Agradezco su ayuda.


YA SOLUCIONÉ EL PROBLEMA, HABIA COMETIDO UN ERROR CON LAS FLAGS. POR FAVOR NO CONTESTAR, GRACIAS!
« Última modificación: 18 de Diciembre de 2014, 13:07:18 por qrppablo »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Problema con interrupciones y EEPROM
« Respuesta #1 en: 17 de Diciembre de 2014, 23:07:46 »
Primero voy a expresar mi opinion pero obviamente esto depende de vos.

Comenzamos con que estas haciendo algo mal de concepto que es escribir seguido en una EEPROM, recorda que tiene una cantidad limitada de escrituras, la forma en que queres hacerlo se puede hacer de otra forma, puede ser sensando la tension de entrada y determinando cuando falte asi se ejecuta un codigo que guarde en EEPROM, pero mientras este "encendida" o conectada solo use la RAM. Tambien si no queres ir o no queres preocuparte por el hardware podes hacer lo mismo pero preguntar si la frecuencia cambio (el valor a guardar con una referencia que tengas en RAM), asi reducirias la cantidad de grabaciones a la EEPROM. De todas formas si ocurre que en esos 3 segundos, cambias de frencuencia y se corta la alimentacion, puede que no llegues a grabar la frecuencia nueva por que no llego a tu interrupcion numero 30. Tambien podes hacer que solo grabe a la EEPROM cuando se dejo mas de 3 segundos en una frecuencia, y obviamente grabas 1 sola ves. Eso depende totalmente de vos es solo mi opinion.

Por otra parte. Tenes el codigo incompleto o solo pusiste una parte?

Al fin de la bandera Start no veo que dirija a otra seccion, sino que el micro seguiria ejecutando lo de la bandera interrupt, es decir faltaria un goto ... Pero no se si es que esta incompleto el codigo.

Y creo que lo interesante seria ver como es que estas guardando los datos a la EEPROM, en especial como seteas la direccion/datos etc. Ademas para desactivar las interrupciones simplemente deshabilita la interrupciones globales (GIE,INTCON).

En el datasheet hay un codigo para la EEPROM, es ese el que estas usando (Pag 43) ? ( En ese desactiva las interrupciones cuando debe )

Escribir:
Código: [Seleccionar]
BSF STATUS, RP1 ;
BSF STATUS, RP0 ;Bank 3
BTFSC EECON1, WR ;Wait for
GOTO $-1 ;write to finish
BCF STATUS, RP0 ;Bank 2
MOVF ADDR, W ;Address to
MOVWF EEADR ;write to
MOVF VALUE, W ;Data to
MOVWF EEDATA ;write
BSF STATUS, RP0 ;Bank 3
BCF EECON1, EEPGD ;Point to Data memory
BSF EECON1, WREN ;Enable writes
;Only disable interrupts
BCF INTCON, GIE ;if already enabled,
;otherwise discard
MOVLW 0x55 ;Write 55h to
MOVWF EECON2 ;EECON2
MOVLW 0xAA ;Write AAh to
MOVWF EECON2 ;EECON2
BSF EECON1, WR ;Start write operation
;Only enable interrupts
BSF INTCON, GIE ;if using interrupts,
;otherwise discard
BCF EECON1, WREN ;Disable writes

Leer:
Código: [Seleccionar]
BSF STATUS, RP1 ;
BCF STATUS, RP0 ;Bank 2
MOVF ADDR, W ;Write address
MOVWF EEADR ;to read from
BSF STATUS, RP0 ;Bank 3
BCF EECON1, EEPGD ;Point to Data memory
BSF EECON1, RD ;Start read operation
BCF STATUS, RP0 ;Bank 2
MOVF EEDATA, W ;W = EEDATA
« Última modificación: 17 de Diciembre de 2014, 23:15:05 por KILLERJC »

Desconectado qrppablo

  • PIC10
  • *
  • Mensajes: 2
Re: Problema con interrupciones y EEPROM
« Respuesta #2 en: 18 de Diciembre de 2014, 00:05:03 »
Que tal KILLERJC, gracias por tu respuesta.
Al codigo lo tengo entero, solamente que es bastante extenso y puse solamente las partes que creo que incumben al problema. Entiendo que escribir seguido en una EEPROM sea un error porque tiene un número limitado de escrituras y también repito que estoy tratando de modificar un código que descargue de internet y todo eso ya estaba escrito y funciona de esa manera, estoy tratando de entender como funcionan las interrupciones y como escribir y leer en/desde EEPROM. Pasar todo a RAM es el doble de trabajo ya que tendría que modificar mucho el programa (que llegado el momento seguramente lo haré ya que me interesa).

He probado también desabilitar las interrupciones globales INTCON y GIE antes de escribir en EEPROM pero tampoco guarda ni lee.

De esta manera graba lo descrito en el mensaje anterior (pongo el codigo en segmentos):

        ORG     0x2100
        DATA    ref_osc_0
        DATA    ref_osc_1
        DATA    ref_osc_2
        DATA    ref_osc_3

; Freq de inicio VFO-A        | EEADR 0x04

   DATA         0x20          ; 17 meters
   DATA         0xB2
   DATA         0x13
   DATA         0x01

; Freq de inicio VFO-B        | EEADR 0x08

        DATA      0xC0        ; 40 meters
        DATA      0xCF         
        DATA      0x6A         
        DATA      0x00       

; Freq guardado temp de RIT | EEADR 0x0C

   DATA   0x40
   DATA   0x77
   DATA   0x1B
   DATA   0x00

; Freq guardado de RIT TX   | EEADR 0x10

   DATA   0x00
   DATA   0x3F
   DATA   0xAB
   DATA   0x01

; VFO X start up bit        | EEADR 0x14

   DATA    0x00

; La frecuencia se guarda en cuatro bytes, por ejemplo en EEADR 0x04, 0x05, 0x06, 0x07
; y lo hace de esta manera

VFOA_save

        movlw   0x04              
        movwf   ee_addr       ; ee_addr = 0x04

    movf        ee_addr,w     ; Carga dirección a guardar
   Bank2
    movwf    EEADR        ; En EEADR   

   Bank0
        movf    freq_0,w           ; Record the first
   Bank2
        movwf   EEDATA            ;   osc
        call       write_EEPROM      ;   byte
        movf     freq_1,w           ; Record the second
   Bank2
        movwf   EEDATA            ;   osc
        call       write_EEPROM      ;   byte
        movf     freq_2,w           ; Record the third
   Bank2
        movwf   EEDATA            ;   osc
        call       write_EEPROM      ;   byte
        movf     freq_3,w           ; Record the fourth
   Bank2
        movwf   EEDATA            ;   osc
   call       write_EEPROM

;
;
write_EEPROM
   Bank3
   btfsc      EECON1,WR     ; Wait for write to finish
   goto      $-1        ; Jump back one
   bcf      EECON1,EEPGD     ; Point to Data Memory
   bsf      EECON1,WREN     ; Enable Write
        movlw   0x55              ; Write 0x55 and 0xAA to EEPROM
        movwf   EECON2            ; control register2, as required
        movlw   0xAA              ; for the write
        movwf   EECON2            ;
        bsf       EECON1,WR         ; Set WR to initiate write
bit_check
        btfsc   EECON1,WR         ; Has the write completed?
        goto    bit_check         ; No, keep checking
        bcf     EECON1,WREN       ; Clear the EEPROM write enable bit
   Bank2
        incf    EEADR,f           ; Increment the EE write address
   Bank0
        return                    ; Return to the caller

; con incf EEADR,f se asegura de guardar los 4 bytes que conforman la frecuencia en las direcciones de EEPROM 0x04, 0x05, 0x06, 0x07

Hasta ahi funciona perfecto.
El problema es cuando desactivo las interrupciones o el timer e intento guardar cuando presiono un botón, el codigo para eso es este:

RIT   
   btfss   PORTC,RIT_State     ; Is RIT Line low? (RIT_State corresponde al PORTC,6 donde está conectado el botón y está declarado al inicio)
   goto   RIT_on        ; Yes, select RIT Mode
   return           ; No, continue

; Yes, restore pre RIT base frequency

   movlw       0x0C              
        movwf       ee_addr       ; ee_addr = 0x0C

    movf            ee_addr,w     ; Carga dirección a leer
   Bank2
    movwf    EEADR        ; En EEADR   

   Bank0   
   call          read_OSC
   movf          EEDATA,w
   Bank0
   movwf      freq_0        ; Primer byte - LSB

   call          read_OSC
   movf          EEDATA,w
   Bank0
   movwf      freq_1        ; Proximo byte

   call          read_OSC
   movf          EEDATA,w
   Bank0
   movwf      freq_2        ; Proximo byte

   call         read_OSC
   movf         EEDATA,w
   Bank0
   movwf   freq_3        ; Ultimo byte - MSB

   return
RIT_on

; Save current base frequency

   bcf     INTCON,GIE    ; Desactivo interrupciones
        bcf     INTCON,PEIE   ;

   movlw   0x0C             
        movwf   ee_addr       ; ee_addr = 0x0C

    movf    ee_addr,w     ; Carga dirección a guardar
   Bank2
    movwf    EEADR        ; En EEADR   

   Bank0
        movf    freq_0,w           ; Record the first
   Bank2
        movwf   EEDATA            ;   osc
        call    write_EEPROM      ;   byte
        movf    freq_1,w           ; Record the second
   Bank2
        movwf   EEDATA            ;   osc
        call    write_EEPROM      ;   byte
        movf    freq_2,w           ; Record the third
   Bank2
        movwf   EEDATA            ;   osc
        call    write_EEPROM      ;   byte
        movf    freq_3,w           ; Record the fourth
   Bank2
        movwf   EEDATA            ;   osc
   call   write_EEPROM

        return

En este caso, cuando se presiona el boton se pone el PORTC,6 en LOW, se debería guardar la frecuencia en las direcciones 0x0C, 0x0D, 0x0E, 0x0F.
Esto permite hacer una sintonía fina en la radio y cambiar la frecuencia. Cuando el botón se suelte, se devuelve la frecuencia guardada en las direcciones anteriores a freq_0, freq_1, freq_2 y freq_3 que conforman la frecuencia que se ve en el display, para volver a la frecuencia anterior a la sintonía fina, la cuestión es que el grabado no se produce. Como lo se? porque para probarlo desactivo las interrupciones pero no las vuelvo a activar cuando suelto el botón. Esto permite que cuando suelto el boton y vuelvo a cambiar de frecuencia, al volver a presionar el botón la frecuencia vuelve a ser la misma de antes. Para graficarlo, por ejemplo sería asi:

Frecuencia con el PORTC,6 en low y con interrupciones activas:
14.010.000 khz

Frecuencia con el PORTC,6 en high y sin interrupciones:
14.010.000 khz

Si cambio de frecuencia por ejemplo con el PORTC,6 en high a 14.015.000 khz y suelto el botón, la frecuencia vuelve a ser 14.010.000 khz (Perfecto, pareciera que se había guardado)

Vuelvo a cambiar de frecuencia, por ejemplo a 14.020.000 khz.

Al presionar el botón la frecuencia debería ser 14.020.000 khz pero NO, sigue siendo 14.010.000 porque los bytes no se guardan y cada vez que cambio de frecuencia y presiono el botón, la misma vuelve a ser 14.010.000 khz.

Perdon si se hace muy extenso esto pero no tengo otra manera mas simple de explicarlo.

La rutina para leer de EEPROM es la misma que uso para leer la frecuencia que se guarda con las interrupciones al prender la radio:

read_OSC

   Bank3
   bcf   EECON1,EEPGD     ; Point to Data Memory
        bsf     EECON1,RD         ; Request the read
   Bank2
        incf    EEADR,f           ; Increment the read address
        return                    ; Return to the caller






 

anything