t-edson / PicPas

Compilador en Pascal para microcontroladores PIC / Pascal compiler for PIC microcontrollers
GNU General Public License v2.0
88 stars 27 forks source link

Varios fallos al crear procedimientos escritura de EEPROM interna #6

Closed AguHDz closed 7 years ago

AguHDz commented 7 years ago

En esta prueba realizado con la versión 0.6.8 he conseguido escribir la EEPROM interna del microcontrolador PIC16F84A. En el siguiente código podemos ver los procedimientos empleados, ambos son equivalentes, pero uno está escrito en código ensamblador y el otro en Pascal.

// Prueba de esctritura en la EEPROM interna del PIC16F84A

{$FREQUENCY 8 MHZ }
{$PROCESSOR PIC16F84A}
program EEPROMInterna;

uses
  PIC16F84A;  

var
    EECON1   :byte absolute $08;  // FALLA ENSAMBLADOR SI SE DEJA $88.
    EECON2   :byte absolute $09;  // FALLA ENSAMBLADOR SI SE DEJA $89.

  Contador :byte;

procedure WriteEEPROMASM(direccion , valor: byte);
begin
ASM
ESCRITURA:                   ; Establecer EEADR y EEDATA
        MOVF    direccion,w      ; Direccion de esctritura
        MOVWF   EEADR                ; Escribe la dirección en EEADR
        MOVF    valor,w          ; Dato a escribir en EEPROM
        MOVWF   EEDATA             ; Se escribe el dato en EEDATA 
        BSF STATUS,STATUS_RP0  ; (RP0) Selecciona el banco 1
        BSF EECON1,EECON1_WREN ; (WREN) Permiso de escritura activado
;Comienzo de la secuencia de escritura
        MOVLW   $55
        MOVWF   EECON2             ; Se escribe el dato 55 h en EECON2
        MOVLW   $AA
        MOVWF   EECON2             ; Se escribe AA h en EECON2
        BSF EECON1,EECON1_WR     ; (WR)Comienza la escritura
        BCF EECON1,EECON1_WREN ; (WREN) Permiso de escritura desactivado
ESPERA:
        BTFSC   EECON1,EECON1_WR ; (WR) Espera a que termine la escritura
        GOTO    ESPERA
        BCF STATUS,STATUS_RP0  ; (RP0) Selecciona el banco 0
END
end;

procedure WriteEEPROM(direccion , valor: byte);
//var
//  WREN    : bit absolute EECON1.EECON1_WREN; // FALLA. No reconoce constantes.
//  WR     : bit absolute EECON1.EECON1_WR;   // FALLA. No reconoce constantes.
begin
  EEADR  := direccion;
  EEDATA := valor;
  ASM
    BSF STATUS,5
  END
  EECON1.2 := 1;        // EECON1,EECON1_WREN := 1 // FALLA. No reconoce constantes.
  EECON2   := $55;
  EECON2   := $AA;
  EECON1.1 := 1;      // EECON1.EECON1_WR :=1 // FALLA. No reconoce constantes.
  EECON1.2 := 0;
  repeat until (EECON1.1 = 0);
  ASM
    BCF STATUS,5
  END
end;

begin
  repeat
  for contador:=$00 to $10 do  
    WriteEEPROMASM(contador,$00);
  end;

  for contador:=$00 to $10 do  
    WriteEEPROM(contador,$FF);
  end;
  until false;
end.

Aunque ambos procedimiento graban la EEPROM perfectamente, ha sido necesario hacer ciertas correcciones para que funcione que no deberían haber sido necesarias. Estas correcciones evitar fallos del compilador y permiten generar un código que funciona correctamente.

Los fallos detectados son:

AguHDz commented 7 years ago

Por cierto, he actualizado la librería PIC16F84A.pas (https://pastebin.com/i3PMcNGs) con los nombres de bits de SFR que aparecen en el DataSheet de Microchip. Había alguna discrepancia, al igual que ocurre en distintos manuales en internet sobre PICs. Por eso, creo que lo mejor es tomar siempre los nombres facilitados por el fabricante.

t-edson commented 7 years ago

Hola Agustín. Con respecto al problema de tener que definir EECON1 y EECON2 en el banco 0, y el porqué el compilador no hace los cambios de banco, no veo el problema. Déjame revisarlo.

Con respecto al error al usar la notación: EECON1,EECON1_WREN := 1;
No es una falla, sino un tema de sintaxis o semántico. PicPas identifica a EECON1_WREN, como constantes, y no es permitido, usar: <byte>.<constante>

, para identificar a un campo de un byte. Por definición, PicPas, soporta solo: <byte>.<identificador de campo de byte>

Y los únicos identificadores válidos para el tipo byte son: bit0, bit1, ... bit7. Si clao, también se puede usar 0, 1, .. 7, pero esto se mantiene solo por compatibilidad. Legalmente no se podrían usar números. La verdadera sintaxis para hacer eso, sería tener que definir algo como:

VAR
  STATUS: byte ABSOLUTE $03  RECORD C , DC, Z, PD, _TO : Bit; RP : 0..3; END;

Y es lo que te comenté, con respecto a la sintaxis legal, de PicPas, para acceder a campos de un SFR. No está implementado por ahora, pero espero tenerlo pronto disponible, o al menos un acercamiento.

AguHDz commented 7 years ago

Hola t-edson, el resultado de compilar este procedimiento:

procedure WriteEEPROM(direccion , valor: byte);
begin
  EEADR  := direccion;
  EEDATA := valor;
  EECON1.2 := 1;
  EECON2   := $55;
  EECON2   := $AA;
  EECON1.1 := 1;
  EECON1.2 := 0;
  repeat until (EECON1.1 = 0);
end;

Es este:

__WriteEEPROM:
    ;EEADR  := direccion;
    $0011 movf direccion,w 
    $0012 movwf EEADR 
    ;EEDATA := valor;
    $0013 movf valor,w 
    $0014 movwf EEDATA 
    ;EECON1.2 := 1;
    $0015 bsf EEDATA, 2 
    ;EECON2   := $55;
    $0016 movlw 0x55 
    $0017 bsf STATUS, 5 ;Bank set.
    $0018 movwf EEADR 
    ;EECON2   := $AA;
    $0019 movlw 0xAA 
    $001A movwf EEADR 
    ;EECON1.1 := 1;
    $001B bcf STATUS, 5 ;Bank set.
    $001C bsf EEDATA, 1 
    ;EECON1.2 := 0;
    $001D bcf EEDATA, 2 
    ;repeat until (EECON1.1 = 0);
    $001E btfsc EEDATA, 1 
    $001F goto 0x01E 
    ;end;
    $0020 return  

Ves que antes de la dirección $0015 debería de haber cambiado al banco 1 y sin embargo lo hace en la dirección $0017, y no se por qué vuelve a cambiar al banco 0 en la dirección $001B, lo cual es incorrecto ya que a partir de ahí existen tres instrucciones que que trabajan con registros del banco 1.

Como digo, las instrucciones que cambiar los registros TRIS, también en el banco 1 funcionan perfectamente, probado incluso compilando código para 16F877A con los puertos C, D y E.

AguHDz commented 7 years ago

Otra solución, mientras implantas el modo de definir bits en RECORD, puede ser esta:

procedure WriteEEPROM(direccion , valor: byte);
var
  bitSFR_WREN   : bit absolute EECON1.2; // No reconoce constantes.
  bitSFR_WR     : bit absolute EECON1.1; // No reconoce constantes.
begin
  EEADR  := direccion;
  EEDATA := valor;
  ASM
    BSF STATUS,5
  END
  bitSFR_WREN := 1;    // EECON1,EECON1_WREN := 1 // FALLA. No reconoce constantes.
  EECON2      := $55;
  EECON2      := $AA;
  bitSFR_WR   := 1;   // EECON1.EECON1_WR :=1 // FALLA. No reconoce constantes.
  bitSFR_WREN := 0;
  repeat until (bitSFR_WR = 0);
  ASM
    BCF STATUS,5
  END
end;

Pero sería mucho mejor que se siguiera un solo criterio para llamar a los bits de los registros SFR. Ahora mismo, en las partes de programa escritas en ASM se definen como constantes (reciente implantado, lo que es muy de agradecer), y en las partes de código escritas en Pascal se definen como variables, y por lo tanto, es necesario darles otros nombres. Se puede dejar así, y funciona sin ningún problema, pero dobla es trabajo de crear librerías de registros para los distintos microcontroladores. De todos modos, la ventaja que le veo ahora mismo a PicPas es que ofrece distintos recursos para que si alguien sabe programar y entiende el código ensamblador casi siempre puede encontrar soluciones, pero entiendo que estas soluciones particulares para problemas concretos en cada programa pueden ser una barrera para quien tenga intención de empezar a usarlo o quiera simplemente aprender a programar microcontroladores PIC en lenguaje Pascal. Pero bueno, supongo que paso a paso se irán solucionando estos problemas normales cuando se afronta una labor tan compleja como programarse uno mismo su propio compilador. :)

t-edson commented 7 years ago

Efectivamente he comprobado que hay un "bug", en el manejo de bancos en PicPas. Hay una ligera corrección, que he hecho en esta misma versión 0.6.8 (tienes que actualziar de nuevo) y puede ayudar, pero el problema de fondo persiste y es un fallo en la asignación de bancos cuando se manejan procedimientos. Este tema es algo que estaré viendo en la siguiente versión, junto a otros pendientes. Mientras tanto te recomiendo que tengas cuidado cuando un procedimiento accede a variables de otros bancos. Puedes ayudarte de la función de sistema SetBank(), para fijar el banco de trabajo.

t-edson commented 7 years ago

Con respecto al problema que mencionas:

" Ha sido necesario redefinir las variables EECON1 y EECON2 en direcciones del banco 0. Si se dejan las originales del banco 1 el código escrito en ensamblador falla."

Quisiera que indiques, en qué sentido falla. ¿No compila? ¿No hace lo que debe hacer? En mis pruebas, no detecto el error.

AguHDz commented 7 years ago

Hola t-edson.

Si compilo el siguiente código:

{$FREQUENCY 8 MHZ }
{$PROCESSOR PIC16F84A}
program EEPROMInterna;

uses
  PIC16F84A;  

var
  Contador :byte;

procedure WriteEEPROMASM(direccion , valor: byte);
begin
ASM
ESCRITURA:                   ; Establecer EEADR y EEDATA
  MOVF  direccion,w      ; Direccion de esctritura
  MOVWF EEADR                ; Escribe la dirección en EEADR
  MOVF  valor,w          ; Dato a escribir en EEPROM
  MOVWF EEDATA             ; Se escribe el dato en EEDATA 
  BSF   STATUS,STATUS_RP0  ; (RP0) Selecciona el banco 1
  BSF   EECON1,EECON1_WREN ; (WREN) Permiso de escritura activado
;Comienzo de la secuencia de escritura
  MOVLW $55
  MOVWF EECON2             ; Se escribe el dato 55 h en EECON2
  MOVLW $AA
  MOVWF EECON2             ; Se escribe AA h en EECON2
  BSF   EECON1,EECON1_WR     ; (WR)Comienza la escritura
  BCF   EECON1,EECON1_WREN ; (WREN) Permiso de escritura desactivado
ESPERA:
  BTFSC EECON1,EECON1_WR ; (WR) Espera a que termine la escritura
  GOTO  ESPERA
  BCF   STATUS,STATUS_RP0  ; (RP0) Selecciona el banco 0
END
end;

begin
  repeat
  for contador:=$00 to $10 do  
    WriteEEPROMASM(contador,$00);
  end;

  for contador:=$00 to $10 do  
    WriteEEPROMASM(contador,$FF);
  end;
  until false;
end.

En el emulador Proteus no funciona la escritura en la memoria interna EEPROM. https://es.pinterest.com/pin/585468020279303851/

Pero si añado las dos siguientes línea para redefinir la posición de las variables EECON1 y EECON2.

var
  EECON1   :byte absolute $08;  // FALLA ENSAMBLADOR SI SE DEJA $88.
  EECON2   :byte absolute $09;  // FALLA ENSAMBLADOR SI SE DEJA $89.

  Contador :byte;

procedure WriteEEPROMASM(direccion , valor: byte);
begin ...

En la simulación de Proteus funciona y escribe la memoria EEPROM interna del uC sin problemas. https://es.pinterest.com/pin/585468020279303851/

Existen compiladores en los que esto es normal, por lo que las librerías de SFR se definen todas en el banco 0, pero me parece que no es sería muy complicado poder utilizar las posiciones reales y que el compilador elimine los bits altos a partir de la dirección límite del banco 0. Por supuesto, en ensamblador el cambio de bancos es siempre labor del código ASM.

t-edson commented 7 years ago

Hola Agustín. Los fallos que mencionas deben estar ya corregidos en la nueva versión de PicPas, la 0.6.9, excepto el problema de acceso a los bits de un registro, usando constates, que como ya te indiqué, es un tema de sintaxis y no una falla. Ten cuidado con los bancos de RAM cuando uses ASM. El compilador no sabe cuando se realizan cambios de banco, dentro de los bloques ASM.

AguHDz commented 7 years ago

Perfecto! Ahora funciona sin ningún problema.

Para el temas de las constantes, he actualizado la UNIT de los nombres de registro 16F84A.pas ( disponible en https://pastebin.com/4eRdCPzA ). Con ella, se evitan los problemas comentados, y por la forma de escribir el código en lenguaje Pascal y en Ensamblador, me parece incluso más coherente este uso de nombres de registros especiales y sus bits.

Ahora compila y funciona a la perfección el código escrito de esta manera (usando la UNIT 16F84A.pas actualizada):

{
*  (C) AguHDz 05-JUN-2017
*  Ultima Actualizacion: 14-JUN-2017
*
*  Compilador PicPas v.0.6.9 (https://github.com/t-edson/PicPas)
*
*  ESCRITURA DE DATOS EN EEPROM INTERNA DEL MICROCONTROLADOR
*  Ejemplo de uso de nombrea de variables y constantes definindas en nueva
*  UNIT 16F84A.pas, ahora mas coherente en el uso de los nombre de bytes y 
*  bits de la zona SFR de memoria y sus registros.
}

{$FREQUENCY 8 MHZ }
{$PROCESSOR PIC16F84A}
program EEPROMInterna;

uses
  PIC16F84A;  

var
  Contador :byte;

procedure WriteEEPROMASM(direccion , valor: byte);
begin
ASM
ESCRITURA:               ; Establecer EEADR y EEDATA
  MOVF  direccion,w      ; Direccion de esctritura
  MOVWF EEADR                ; Escribe la dirección en EEADR
  MOVF  valor,w          ; Dato a escribir en EEPROM
  MOVWF EEDATA             ; Se escribe el dato en EEDATA 
  BSF   STATUS,bit_RP0     ; Selecciona el banco 1
  BSF   EECON1,bit_WREN    ; Permiso de escritura activado
;Comienzo de la secuencia de escritura
  MOVLW $55
  MOVWF EECON2             ; Se escribe el dato 55 h en EECON2
  MOVLW $AA
  MOVWF EECON2             ; Se escribe AA h en EECON2
  BSF   EECON1,bit_WR        ; Comienza la escritura
  BCF   EECON1,bit_WREN    ; Permiso de escritura desactivado
ESPERA:
  BTFSC EECON1,bit_WR    ; Espera a que termine la escritura
  GOTO  ESPERA
  BCF   STATUS,bit_RP0     ; Selecciona el banco 0
END
end;

procedure WriteEEPROM(direccion , valor: byte);
begin
  EEADR       := direccion;
  EEDATA      := valor;
  EECON1_WREN := 1;
  EECON2      := $55;
  EECON2      := $AA;
  EECON1_WR   := 1;
  EECON1_WREN := 0;
  repeat until (EECON1_WR = 0);
end;

begin
  repeat
  for contador:=$00 to $10 do  
    WriteEEPROMASM(contador,$00);
  end;

  for contador:=$00 to $10 do  
    WriteEEPROM(contador,$FF);
  end;
  until false;
end.

(Código disponible en https://pastebin.com/RzfpdyXU)

A ver que te parece la UNIT actualizada con definiciones de bytes y bits del SFR válidos para su uso tanto en Pascal como en ASM y lo pudieras actualizar ya en la versión actual de PicPas.

En cuanto a lo que comentas de selección de bancos en ASM, por supuesto, debe ser así. El programador debe decidir en que banco trabaja, y el compilador debe eliminar los bits altos de los registros SFR que están fuera del banco 0.

Por las pruebas realizadas hasta ahora, todos los problemas comentado quedan solucionados o aclarados perfectamente, y Picpas sigue mejorando en cada actualización. Gracias.

t-edson commented 7 years ago

Me parece muy bien la forma como has actualizado las unidades, hasta mientras no se tenga una mejor sintaxis. Voy a actualizar las nuevas unidades, y a incluir tu ejemplo en la carpeta "/samples". Una aclaración, si ya tienes definidas las variables bit, como STATUS_Z, puedes usar esa misma variable para acceder directamente desde el ensamblador:

uses PIC16F84A;
begin
  asm
      BCF STATUS_Z
          BTFSC STATUS_Z
  end
end.

El ensamblador soporta ya desde la versión 0.6.7 referencias a variables bit y boolean. No sé si sea necesario definir adicionalmente la constante "bit_Z".

AguHDz commented 7 years ago

En ese caso, mejor. Son temas que si en una ocasión no funcionan y encuentras un modo de solucionarlas ya sigues metódicamente haciéndolas de la forma en que te funcionó. Acabo de probarlo con el siguiente procedimiento dejando en forma de comentarios las lineas de código actualizada. Supongo que me dio problemas en alguna versión previa a la 0.6.7, pero ahora reconoce perfectamente las variables tipo bit en el código ASM.

procedure WriteEEPROMASM(direccion , valor: byte);
begin
ASM
ESCRITURA:               ; Establecer EEADR y EEDATA
  MOVF  direccion,w      ; Direccion de esctritura
  MOVWF EEADR                ; Escribe la dirección en EEADR
  MOVF  valor,w          ; Dato a escribir en EEPROM
  MOVWF EEDATA             ; Se escribe el dato en EEDATA 
;  BSF  STATUS,bit_RP0     ; Selecciona el banco 1
;  BSF  EECON1,bit_WREN    ; Permiso de escritura activado
  BSF   STATUS_RP0     ; Selecciona el banco 1
  BSF   EECON1_WREN    ; Permiso de escritura activado
;Comienzo de la secuencia de escritura
  MOVLW $55
  MOVWF EECON2             ; Se escribe el dato 55 h en EECON2
  MOVLW $AA
  MOVWF EECON2             ; Se escribe AA h en EECON2
;  BSF  EECON1,bit_WR        ; Comienza la escritura
  BSF   EECON1_WR        ; Comienza la escritura
;  BCF  EECON1,bit_WREN    ; Permiso de escritura desactivado
  BCF   EECON1_WREN    ; Permiso de escritura desactivado
ESPERA:
  BTFSC EECON1,bit_WR    ; Espera a que termine la escritura
  GOTO  ESPERA
;  BCF  STATUS,bit_RP0     ; Selecciona el banco 0
  BCF   STATUS_RP0     ; Selecciona el banco 0
END
end;

Estoy de acuerdo en que se pueden eliminar las constantes tipo bit_XXX y llamar a los bits del SFR del mismo modo en el código Pascal y ASM.