Capítulo 3. PRINCIPALES REGISTROS DE CONTROL Y MANEJO DE LAS ME-
3.5. Lectura y escritura de las memorias EEPROM y FLASH
En el PIC16F84 se podía leer y escribir la memoria de datos EEPROM. En los PIC16F87x también se pue- de leer y escribir la memoria de código FLASH. Esto significa que un programa dinámicamente puede ge- nerar información que se puede grabar en la FLASH directamente, sin necesidad del grabador externo.
La propia aplicación se puede reprogramar según las condiciones externas. Es posible ampliar el área de la memoria de datos no volátil EEPROM con posiciones libres de la memoria de código FLASH.
PSPIE Permiso de interrupción para la puerta paralela esclava al realizar una operación de lectura/
escritura. En modelos de 40 patitas.
ADIE Permiso de interrupción para el conversor A/D al finalizar la conversión.
RCIE Permiso de interrupción para el receptor del USART cuando el buffer se llena.
TXIE Permiso de interrupción para el transmisor del USART cuando el buffer se vacía.
SSPIE Permiso de interrupción para la puerta serie síncrona.
CCP1IE Permiso de interrupción para el módulo CCP1 cuando se produce una captura o comparación.
TMR2IE Permiso de interrupción para el TMR2 con su desbordamiento.
TMR1IE Permiso de interrupción para el TMR1 con su desbordamiento.
REGISTRO PIE1
PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE
7 0
Figura 3.4. Designación y funciones de permiso y prohibición de los bits del registro PIE1.
La memoria EEPROM de los PIC16F87x tiene una capacidad de 128 o 256 bytes, con un rango de direcciones de 00h a 7Fh o 00h a FFh, respectivamente.
En los PIC16F87x se puede leer y escribir la memoria FLASH y ộsta puede alcanzar un tamaủo de 8 K palabras de 14 bits cada una. No es suficiente con un solo registro para especificar la direc- ción, que alcanza los 13 bits, y lo mismo sucede para el contenido, que tiene una longitud de 14 bits.
Para cubrir esta necesidad, el registro EEADR se concatena con el EEADRH, que contiene los 5 bits de más peso de la dirección. Por otra parte, el registro EEDATAH se concatena con el EEDATA y contiene los 6 bits de más peso de la palabra leída o a escribir en la FLASH. Estos dos nuevos re- gistros no se usan en las operaciones que afectan a la EEPROM. (Figura 3.7.)
Para controlar la operación de lectura/escritura de las memorias EEPROM y FLASH hay dos re- gistros denominados EECON1 y EECON2. El EECON1 (Figura 3.8) ocupa la dirección 18Ch, mientras que el EECON2, como sucedía con el PIC16F84, no está implementado físicamente y só- lo se utiliza como registro de seguridad en la delicada operación de escritura, que tiene la elevada duración de 2 milisegundos, aproximadamente. Antes de iniciar la escritura de una palabra se es- cribe en EECON2 primero el dato 55h y luego el AAh.
CMIE Permiso de interrupción para el comparador.
EEIE Permiso de interrupción por fin de escritura en la EEPROM de datos.
BCLIE Permiso de interrupción por colisión de bus en el SSP cuando dos o más maestros tratan de transferir al mismo tiempo.
CCP2IE Permiso de interrupción en el módulo CCP2.
REGISTRO PIE2
7 0
Figura 3.5. Designación y funciones de los bits del registro PIE2.
REGISTRO PIR1
PSPIF ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF
7 0
REGISTRO PIR2
— CMIF — EEIF BCLIF — — CCP2IF
7 0
Figura 3.6. Los bits de los registros PIR1 y PIR2 contienen los seủalizadores de las causas que producen las interrupciones, en correspondencia con los registros PIE1 y PIE2.
— CMIE — EEIE BCLIE — — CCP2IE
Se proponen algunos programas fundamentales para manejar las operaciones de lectura y escri- tura en las memorias EEPROM y FLASH. En la parte dedicada a programación se incluye un ejer- cicio completo sobre este tema. Un resumen de la operación de escritura de una posición de la EE- PROM consta de los siguientes pasos:
Figura 3.7. Para contener la dirección y el dato de la memoria FLASH se necesitan dos registros para cada valor.
EADRH (10Fh) EEADR (10Dh)
0 0 0 x x x x x x x x x x x x x
DIRECCIÓN DE 13 BITS (8 K) EEDATAH (10Eh) EEDATA (10Ch)
0 0 x x x x x x x x x x x x x x
DATO DE 14 BITS (FLASH)
PROGRAMA DE ESCRITURA DE LA MEMORIA EEPROM DE DATOS bsf STATUS,RP1 ; Con estas dos instrucciones se
bcf STATUS,RP0 ; selecciona el banco 2
movf ADDR_L,W ; Se mete en EEADR la dirección a la
movwf EEADR ; que se va a acceder
movf DATA_L,W ; Se mete en EEDATA el dato a escribir
movwf EEDATA
bsf STATUS,RP0 ; Se pasa al banco 3
bcf EECON1,EEPGD ; Se selecciona el acceso a la EEPROM bsf EECON1,WREN ; Se habilita la escritura en la EEPROM bcf INTCON,GIE ; Se prohiben las interrupciones
movlw 55h ; Se mete el valor 55h y el AAh en el
movwf EECON2 ; registro de seguridad EECON2 tal y
movlw AAh ; como recomienda el fabricante
movwf EECON2
bsf EECON1,WR ; Se da la orden de escritura bsf INTCON,GIE ; Se habilitan las interrupciones
sleep ; Se espera a que se produzca interrupción
; por fin de escritura
bcf EECON1,WREN ; Se prohibe la escritura de nuevos datos
bcf STATUS,RP1 ; Se pasa al banco 0
bcf STATUS,RP0 ;
bcf PIR2,EEIF ; Se borra el flag de fin de escritura 1.aSe introduce el dato a escribir en EEDATA y la dirección en EEADR.
2.a Se pone WREN=1 en EECON1. Permiso de escritura.
3.a Se escribe la secuencia de seguridad que carga el registro EECON2 con el dato 55h y luego con AAh.
4.a Para iniciar la escritura se pone WR=1 en EECON1.
5.a Al finalizar la escritura se activa el seủalizador EEIF de forma automỏtica.
6.a Se debe borrar el seủalizador EEIF y prohibir la escritura (WREN=0).
EEPGD Selecciona el acceso a la FLASH (1) o a la EEPROM (0).
WRERR Seủalizador de error en escritura.
WREN Permiso de escritura.
WR Hay que ponerlo a 1 para iniciar la escritura y pasa a 0 automáticamente cuando finaliza.
RD Hay que ponerlo a 1 para iniciar la lectura.
REGISTRO EECON1
EEPGD — — — WRERR WREN WR RD
7 0
Figura 3.8. Denominación y misión de los bits del registro EECON1.
PROGRAMA DE LECTURA DE LA MEMORIA FLASH DE CÓDIGO
bsf STATUS,RP1 ; Con estas dos instrucciones se
bcf STATUS,RP0 ; selecciona el banco 2
movf ADDR_H,W ; Se mete en EEADRH la parte alta de la
movwf EEADRH ; dirección a leer
movf ADDR_L,W ; Se mete en EEADR la parte baja de la
movwf EEADR ; dirección a leer
bsf STATUS,RP0 ; Se pasa al banco 3
bsf EECON1,EEPGD ; Se selecciona el acceso a la FLASH bsf EECON1,RD ; Se da la orden de lectura de la FLASH
nop ; Tarda 3 ciclos en tener el dato, por lo que
nop ; cualquier instrucción es ignorada
bcf STATUS,RP0 ; Se pasa al banco 2
movf EEDATA,W ; Se coge la parte baja del dato leído
movwf DATA_L
movf EEDATAH,W ; Se coge la parte alta del dato leído
movwf DATA_H
PROGRAMA DE ESCRITURA EN LA MEMORIA FLASH DE CÓDIGO bsf STATUS,RP1 ; Con estas dos instrucciones se
bcf STATUS,RP0 ; selecciona el banco 2
movf ADDR_H,W ; Se mete en EEADRH la parte alta de la
movwf EEADRH ; dirección a escribir
movf ADDR_L,W ; Se mete en EEADR la parte baja de la
movwf EEADR ; dirección a escribir
movf DATA_H,W ; Se mete en EEDATH la parte alta
movwf EEDATH ; del dato a escribir
movf DATA_L,W ; Se mete en EEDATA la parte baja
CONFIGURACIÓN DE BITS POSICIONES LECTURA ESCRITURA LECTURA ESCRITURA
CP1 CP0 WRT DE FLASH INTERNA INTERNA ICSP ICSP
0 0 x Toda la memoria de programa Sí No No No
0 1 0 Áreas no protegidas Sí No Sí No
0 1 0 Áreas protegidas Sí No No No
0 1 1 Áreas no protegidas Sí Sí Sí No
0 1 1 Áreas protegidas Sí No No No
1 0 0 Áreas no protegidas Sí No Sí No
1 0 0 Áreas protegidas Sí No No No
1 0 1 Áreas no protegidas Sí Sí Sí No
1 0 1 Áreas protegidas Sí No No No
1 1 0 Toda la memoria de programa Sí No Sí Sí
1 1 1 Toda la memoria de programa Sí Sí Sí Sí
Figura 3.9. Diversas posibilidades de protección de la memoria FLASH ante operaciones de lectura y es- critura, de acuerdo con los valores de los bits WRT, CP1 y CP0 de la Palabra de Configuración.
PROGRAMA DE ESCRITURA EN LA MEMORIA FLASH DE CÓDIGO (continuación)
movwf EEDATA ; del dato a escribir
bsf STATUS,RP0 ; Se pasa al banco 3
bsf EECON1,EEPGD ; Se selecciona el acceso a la FLASH bsf EECON1,WREN ; Se habilita la escritura en la FLASH bcf INTCON,GIE ; Se prohiben las interrupciones
movlw 55h ; Se mete el valor 55h y el AAh en el
movwf EECON2 ; registro de seguridad EECON2 tal y
movlw AAh ; como recomienda el fabricante
movwf EECON2
bsf EECON1,WR ; Se da la orden de escritura
nop ; El microcontrolador ignora estas dos
nop ; instrucciones y no sigue con la siguiente
; hasta que no termine la escritura bsf INTCON,GIE ; Se habilitan las interrupciones bcf EECON1,WREN ; Se prohibe la escritura de nuevos datos
Es una buena práctica de programación verificar que todos los valores escritos en las memorias EEPROM y FLASH son correctos. Para evitar escrituras indeseadas en la EEPROM motivadas por espúreos en la inicialización del microcontrolador, se controla el bit WREN, prohibiendo cualquier operación de escritura mientras duran los 72 milisegundos que temporiza el Timer de Power-up. Pa- ra realizar la misma protección en la memoria FLASH se debe poner a 0 el bit WRT de la Palabra de Configuración, que sólo puede escribirse desde un grabador externo.
Dependiendo del valor del bit WRT y de los bits de Protección de Código CP1 y CP0, ubicados en la Palabra de Configuración, se consiguen diversas alternativas de protección contra lectura y es- critura de la FLASH. (Figura 3.9.)
UN PROGRAMA QUE MANEJA LAS MEMORIAS FLASH DE CÓDIGO Y EEPROM DE DATOS
En este mismo capítulo se han visto trozos de código para leer y escribir la memoria FLASH de ins- trucciones y para escribir la memoria EEPROM de datos. Vamos a realizar ahora un ejercicio que reúna la utilización de estas dos memorias. Para ello, consideraremos que los códigos ya vistos, con una pequeủa modificaciún, son subrutinas a las cuales se llamarỏ para realizar procesos de lectu- ra/escritura sobre las citadas memorias. Así, tendremos las siguientes subrutinas:
Falta por realizar el código correspondiente a la lectura de la EEPROM, que una vez convertida a subrutina quedaría como sigue.
* LEER-EEPROM bsf STATUS,RP1 ; Con estas dos
; instrucciones se bcf STATUS,RP0 ; selecciona el banco 2
movf ADDR_L,W ; Se mete en EEADR
movwf EEADR ; la dirección a leer
bsf STATUS,RP0 ; Se pasa al banco 3 bcf EECON1,EEPGD ; Se selecciona el
; acceso a EEPROM bsf EECON1,RD ; Se da la orden de
; lectura
bcf STATUS,RP0 ; Se pasa al banco 2 movf EEDATA,W ; Se coge el dato leído
movwf DATA_L ; y se deja en
; DATA_L
return ; Retorno de
; subrutina LEER-FLASH
ESCRIBIR-FLASH LEER-EEPROM ESCRIBIR-EEPROM
Programar PIC es fácil
67
En las líneas que empiezan con * se pretende resaltar las modificaciones que habría que llevar a cabo en los códigos anteriores para convertirlos a subrutinas: poner como etiqueta el nombre co- rrespondiente de cada subrutina y como última instrucción la returnpara volver al programa prin- cipal.
Enunciado
La posibilidad de escribir la memoria de código mientras se está ejecutando un programa puede re- sultar interesante para ciertas aplicaciones. Imaginemos que en un programa se necesita saber si es la primera vez que se utiliza, para pedir cierta información de configuración por ejemplo, o si ya se ha utilizado más veces y dicha información ya se tiene. Hay muchos modos de hacer esto: se podría preguntar al usuario, mirar cierta variable para determinarlo y ejecutar una subrutina u otra o, como haremos aquí, modificar el programa la primera vez que se entra para en posteriores ocasiones eje- cutar un código diferente.
En nuestro programa, la primera vez que se ejecute se leerá la primera posición de la EE- PROM (aunque no es estrictamente necesario lo haremos así para probar las funciones vistas en este capítulo). Si en dicha posición se encuentra el valor 27h (que anteriormente deberemos gra- bar) significa que el programa no se ha ejecutado anteriormente, en cuyo caso se inicializarán una serie de contadores y se modificará el programa para que la próxima vez que se ejecute los con- tadores no sean inicializados. Puede parecer que sería más sencillo e igual de óptimo no modifi- car el programa, sino el valor de la EEPROM, y simplemente leer cada vez que se ejecuta el pro- grama la primera posición de ésta, de modo que se salte a un punto u otro. La ventaja de nuestro método es que, aunque un astuto usuario quisiera hacer trampa a nuestro programa variando el va- lor de la EEPROM para que creyera que era la primera vez que se entraba en él, al haberse mo- dificado el programa y, a no ser que tenga el original, le será imposible saber cuál era la secuen- cia que seguía esta primera vez. ¿Se imagina que el cuentakilómetros de los coches tuviera un método tan sofisticado?
En esta ocasión, para resolver el ejercicio sólo necesitamos como base el organigrama ya que, al no utilizar periféricos de E/S, el esquema eléctrico no aporta ningún dato significativo.
Organigrama
El organigrama de la Figura 3.10 representa el funcionamiento más completo del programa, la pri- mera vez que se ejecuta. En siguientes ocasiones, ya desde la primera instrucción se saltará a otras instrucciones.
Programa comentado
Antes de realizar el programa principal se debe hacer un primer programa con el cual se escriba en la primera posición de la EEPROM (dirección 00) el valor 27. Este primer programa se gra- bará en el PIC de la forma habitual y su cuerpo consistirá en una llamada a la subrutina ESCRI- BIR-EEPROM, habiendo antes metido en el registro ADDR_L el valor 00 y en DATA_L el va- lor 27.
Antes de grabar un nuevo programa, como ya se expuso en el primer capítulo, es necesario bo- rrar el PIC, pero este borrado no afecta a la EEPROM, por lo que al grabar el programa que real- mente nos interesa el valor 27 de la primera posición permanecerá ahí.
Ahora, intente seguir el desarrollo del programa e imaginar cuál ha sido el resultado final.
Figura 3.10. Organigrama del programa en su primera ejecución.
LIST P=16F873 ; Se indica el tipo de
; procesador
RADIX HEX ; Sistema de numeración
; hexadecimal
INCLUDE ôP16F873.INCằ ; Se incluye la definiciún de
; los registros internos en
; una librería
LOCAL_VAR EQU 0x20 ; Dirección de comienzo
cblock LOCAL_VAR ; de var. locales
CONT ; Para el bucle de borrado
; de Flash
CONT1 ; Contadores a inicializar CONT2
CONT3
ADDR_H ; MSB de dirección FLASH ADDR_L ; LSB de dirección
; FLASH / EEPROM DATA_H ; MSB del dato FLASH DATA_L ; LSB del dato
; FLASH/ EEPROM DEBUG ; Registro de info.
; de debugging endc
ORG 0x00 ; Inicio en el Vector de
; Reset
goto INICIO ; Instrucción a cambiar por
; goto OTRAS
ORG 0x05 ; Salta el Vector de
; Interrupción
; Las instrucciones siguientes serán borradas tras la lectura de la EEPROM,
; realizándose la inicialización de ciertos valores si el valor leído era
; el esperado, y no haciéndola en caso contrario. En cualquiera de los dos
; casos, estas instrucciones se eliminarán.
INICIO clrf DEBUG
bsf DEBUG, 0 ; Punto de control 0
bcf STATUS, RP1 ; Selecciona banco 1
bsf STATUS, RP0
clrf TRISB ; PORTB como salida
bcf STATUS, RP0 ; Vuelta a banco 0
clrf PORTB
bsf STATUS, RP1 ; Selecciona banco 2
clrf ADDR_L ; Dirección 0 EEPROM
call LEER_EEPROM ; Deja dato leído
; en DATA_L
movlw 0x27 ; Valor para comparar
subwf DATA_L, W ; con dato leído EEPROM
btfss STATUS, Z ; ¿Son iguales?
goto NO_INIC ; No. Se indica que
; ha habido error
goto INIC ; Sí. Se realiza
; la inicialización
; Si se entra en INIC es que es la 1.avez que se ejecuta el programa y en la posición
; 00 de la EEPROM se encuentra el valor 27. Teóricamente, si no fuera así no estaría
; pasando por aquí, ya que las instrucciones no existirían.
NO_INIC bsf DEBUG, 1 ; Punto de control 1
goto MODIFICAR ; Se borra TODO el código
; de comparación e inic SIN haber realizado la INIC. Si entra por aquí algo
; va mal
INIC bsf DEBUG, 2 ; Punto de control 2
clrf CONT1 ; Se inicializan contadores
movlw 35
movwf CONT2
movlw 49
movwf CONT3
MODIFICAR bsf DEBUG, 3 ; Punto de control 3
bsf STATUS, RP1
bcf STATUS, RP0 ; Se selecciona banco 2
clrf ADDR_H ; MSB dir FLASH
clrf ADDR_L ; LSB dir FLASH
movlw b’00101000’ ; MSB instrucción goto k
movwf DATA_H
movlw OTRAS ; LSB instrucción goto k
movwf DATA_L ; →goto OTRAS
; (OTRAS ha de ser una etiqueta cuya dir en la Flash sea < = 255 )
call ESCRIBIR_FLASH
bcf STATUS, RP0 ; Banco 2
; (ESCRIBIR_FLASH
; deja en el 3)
movlw d’36’ ; N.oinstrucciones a borrar
movwf CONT ; desde la dir 0x01
BORRAR incf ADDR_L, F ; Siguiente dir a borrar
clrf DATA_H ; MSB instrucción nop
clrf DATA_L ; LSB instrucción nop
call ESCRIBIR_FLASH
bcf STATUS, RP0 ; Banco 2
decfsz CONT, F ; ¿Contador a 0 ?
goto BORRAR ; No. Seguir borrando
bsf DEBUG, 4 ; Punto de control 4
goto OTRAS ; Sí. Ir a la parte que
; siempre se ejecuta
OTRAS bsf DEBUG, 5 ; Punto de control 5
bcf DEBUG,7 ; Será el único punto de
; control que se vea a partir de la 2.aejecución
bcf STATUS, RP1
bsf STATUS, RP0 ; Banco 1
clrf TRISB ; PORTB como salida. Hay
; que volverlo a configurar aquí porque sólo la primera vez se inicilizará al
; principio del programa
¿Se ha dado cuenta de nuestra pequeủa trampa? Hemos introducido puntos de control a lo largo de todo el programa poniendo a 1 los bits de un registro según se iban ejecutando partes, y mos- trando el valor total al final del programa. De esta forma, podemos comprobar de una forma rápida y fiable el cambio de nuestro código. Estos puntos de control no forman parte del programa en sí, por lo que no se muestran en el organigrama ni en el esquema eléctrico. Una vez comprobado el buen funcionamiento pueden ser eliminados.
El programa ha cambiado completamente, tal y como se muestra más abajo. Tras la primera ins- trucción, la mayoría de las instrucciones han sido cambiadas por el código de operación de la ins- trucción NOP. A partir de ese código, aun teniendo acceso a él, sería imposible conocer el progra- ma original. Este mismo método puede utilizarse para aplicaciones de aprendizaje en el campo de la Inteligencia Artificial, donde microbots controlados por microcontrolador pueden ir variando sus programas dinámicamente para adaptarse a situaciones concretas.
bcf STATUS, RP0 ; banco 0
movf DEBUG, W ; Se saca por la puerta B los
movwf PORTB ; puntos de control por los
; que ha pasado el programa
goto OTRAS
INCLUDE <eeprom.asm> ; Ficheros de escritura y INCLUDE <flash.asm> ; lectura de las memorias
END ; Fin de programa
Figura 3.11. PICME-TR mostrando el código del programa una vez modificado.
Prueba del programa
En un programa donde no hay entradas y salidas el resultado no puede comprobarse a simple vista.
Podemos introducir puntos de control, como en nuestro caso, o utilizar herramientas adecuadas pa- ra ello. Los pasos a realizar son los siguientes:
1.o Grabe en el microcontrolador el primer programa para situar en la posición 00 de la EEPROM el valor 27.
2.o Ejecútelo.
3.o Vuelva al programa de grabación PICME-TR y elija la opción Leer PIC, dentro de la ventana MO- DELO ELEGIDO,Editar Datos. La información de la ventana superior izquierda habrá variado pa- ra contener las posiciones de la EEPROM de datos. Compruebe que en la posición 00 efectiva- mente se ha grabado un 27.
4.o Grabe ahora el programa del enunciado y, antes de ejecutarlo la primera vez, elija de nuevo Leer PIC y fíjese en la ventana BUFFER DE MEMORIA DE PROGRAMA. Compruebe además que el valor de la EEPROM sigue ahí.
5.o Ejecute el nuevo programa en el PIC.
6.o Vuelva de nuevo al PICME-TR y lea el PIC para comprobar qué tiene ahora dentro. ¿Ha variado?