TODOPIC

Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: lpossamay en 10 de Febrero de 2016, 21:36:30

Título: Ayuda con tablas en assembler 16f628A
Publicado por: lpossamay en 10 de Febrero de 2016, 21:36:30
Estoy terminando el diseño de un programa en assembler, con un 16F628A, que requiere el uso de 4 tablas de 200 datos cada una.
Dado que es un programa para trabajar en 50/60 Hz, ya lo he probado para cada caso en particular con tablas de 100 datos cada una y una funciona correctamente, sin embargo quisiera poner todo junto y con 200 valores por tabla.
Cuando intento usarlo con tablas de 200 datos cada una, no he logrado hacerlo funcionar.
Cuando accedo a la segunda tabla, el programa no regresa a la rutina que llama a esa tabla, en lugar de eso se reinicia.
He leído del tema y no he encontrado nada acerca del uso de tablas grandes donde solo requiero recuperar un valor a la vez.
¿Alguien que pueda indicarme alguna rutina que funcione, o que tenga algún link para leer con detalle, como funciona la instrucción RETLW para regresar al lugar correcto?
Título: Re:Ayuda con tablas en assembler 16f628A
Publicado por: KILLERJC en 10 de Febrero de 2016, 23:34:59
El problema es que no sabes como funcionan las instrucciones y el micro sobre el direccionamiento.

Es el caso del GOTO/CALL. Que puede que te sirva, pero te lo digo igual.

La direccion de memoria flash del PIC16 es de 13bits.. Ocurre en cambio que para un GOTO/CALL la direccion va en el OPCODE

Código: [Seleccionar]
GOTO - 10 1kkk kkkk kkkk
CALL -  10 0kkk kkkk kkkk

Es decir puede direccionar hasta 11bits. Como ejemplo si quisieras hacer un GOTO/CALL a las direcciones FLASH 0x0 y 0x800 el OPCODE quedaria:

Código: [Seleccionar]
GOTO 0x0 - 10 1000 0000 0000
CALL  0x0 -  10 0000 0000 0000

GOTO 0x800 - 10 1000 0000 0000
CALL  0x800 -  10 0000 0000 0000

Como podras ver no hay ninguna diferencia entre uno u otro y estarias saltando a 0x0. Entonces tenes que asegurar que si la direccion a la que estas apuntando con tu tabla SUPERA los 11bits 0x3FF, vas a tener que modificar el registro PCLATH antes! del salto. Que para el caso del GOTO/CALL los bits que afectan a los mismos son el 4 y 3 del registro PCLATH.
Volviendo al ejemplo anterior si veo que mi funcion debe saltar a 0x800 tendria hacer:

Código: ASM
  1. MOVLW 0x8
  2. MOVWF PCLATH
  3. CALL     0x800

Entonces ahora el CALL y el PCLATH esta formado de la siguiente forma:
CALL  0x800 -  10 0000 0000 0000
PCLATH - 0000 1000

Lo cual forma la direccion:

0 1000 0000 0000 = 0x800

Esto es rescpecto a los CALL/GOTO. Lo mismo ocurre cuando usas cualquier otra instruccion para modificar el PCL. Ejemplo

Código: ASM
  1. ADDWF PCL,F
  2. RETLW ----
  3. ..
  4. ..
  5. ..
  6. RETLW ..

El problema aca es que PCL es un registro de solo 8 bits, y por lo tanto puede direccionar 256, Pero de donde saca los 5 bits restantes? Del PCLATH
Esta ves el PCLATH aporta su 5 bits.. Un ejemplo muy simple.

Código: ASM
  1. ;PCLATH = 0
  2. ORG 0x0FC
  3. MOVLW 0x3         ; 0xFD
  4. ADDWF PCL,F      ; 0xFE
  5. RETLW 0             ; 0xFF
  6. RETLW 1             ; 0x100
  7. RETLW 2             ; 0x101
  8. RETLW 3             ; 0x102

Si usas eso en ves de saltar a 0x102 y que use el RETLW, vas a saltar a la posicion 0x02. Como lo solucionas? Es simple

Código: ASM
  1. Llamar_Tabla1:
  2.         pageselw        Tabla1          ; Esto genera un MOVLW y MOVWF a PCLATH con el valor Tabla1, PCLATH = 0x01
  3.         MOVLW Tabla1    ; Cargo el comienzo de la tabla ( 0xFE ) solo 8 bits permite el OPCODE
  4.         ADDWF Indice,W  ; Se lo sumo al indice del elemento a acceder
  5.         BTFSC STATUS, C ; Esta en 1 el Carry?, es decir supero los 255 ?
  6.         INCF  PCLATH, F ; Si es 1 el carry, quiere decir que tengo que incrementar el PCLATH
  7.         MOVWF PCL       ; El resultado de la suma lo pongo el PCL, esta instruccion carga el PCLATH al PCH
  8.  
  9.  
  10.         ORG 0x1FE
  11. Tabla1:
  12.         RETLW 0             ; 0x1FE
  13.         RETLW 1             ; 0x1FF
  14.         RETLW 2             ; 0x200
  15.         RETLW 3             ; 0x201

En este caso vamos a ir por parte, vamos a suponer que el indice es 0x3, el pageselw van a generar un MOVLW y un MOVWF al PCLATH con el valor 0x01, ya que ese valor es el que posee Tabla1.
Luego se suma el Indice al comienzo de la tabla, 0xFE + 0x3 = 0x01, y queda en W. Luego observamos el valor del carry y vemos que ocurrio un carry entonces incrementamos PCLATH dejandolo en 0x2. Y luego procedemos a mover el valor de W ( 0x01 ) a PCL, al hacer esto la direccion queda:

PCH    |     PCL
0 0010 0000 0001  = 0x201

La direccion de retorno no influye el PCLATH; ya que cuando se ejecuta el CALL se guardan los 13 bits en el stack

Y ahora por mas que cruce el borde de 256 bytes podes usar la tabla. Por lo del comienzo solo debes asegurarte que lo que llama a esta tabla este dentro de los 11 bits de direccionamiento. Asi no tenes que cambiar el PCLATH
Título: Re:Ayuda con tablas en assembler 16f628A
Publicado por: lpossamay en 11 de Febrero de 2016, 00:50:43
Gracias por tu respuesta y por tomarte el trabajo de hacer una descripción completa  ((:-)) ((:-)), finalmente he logrado que el programa acceda a las tablas, de siguiente manera  :):

; VALOR indica la posición en la tabla a leer.
; puedo usar una, dos o más tablas.

; Solo debí usar dos instrucciónes más, cada vez que llamaba a la tabla correspondiente.
Tabla página 1
      MOVLW   D'1'                     ; Página 1.
      MOVWF   PCLATH                  ; Carga el número de página en PCLATH
      MOVF   VALOR,         W         ; VALOR indica el desplazamiento en la tabla
      CALL   Tabla_página_1         ;
      MOVWF   donde sea necesario            ; W retorna con el valor almacenado en la posición que quiero leer en la tabla.

Tabla página 2
      MOVLW   D'2'                     ; Página 2.
      MOVWF   PCLATH                  ;
      MOVF   VALOR,         W         ;
      CALL   Tabla_página_2         ;
      MOVWF   donde sea necesario            ; W retorna con el valor almacenado en la posición que quiero leer en la tabla.

Tabla página 3
      MOVLW   D'3'                     ; Página 3.
      MOVWF   PCLATH                  ;
      MOVF   VALOR,         W         ;
      CALL   Tabla_página_3         ;
      MOVWF   donde sea necesario            ; W retorna con el valor almacenado en la posición que quiero leer en la tabla.

Tabla página 4
      MOVLW   D'4'                     ; Página 4.
      MOVWF   PCLATH                  ;
      MOVF   VALOR,         W         ;
      CALL   Tabla_página_4         ;
      MOVWF   donde sea necesario            ; W retorna con el valor almacenado en la posición que quiero leer en la tabla.


ORG 100H
Tabla_página_1
      ADDWF   PCL,         F         ;
      RETLW   0x
      .
      .
      RETLW   0x                  ; (200 valores de la tabla 1)
; ----------------------
ORG 200H
Tabla_página_2
      ADDWF   PCL,         F         ;
      ADDWF   PCL,         F         ;
      RETLW   0x
      .
      .
      RETLW   0x                  ; (200 valores de la tabla 2)
; ----------------------
ORG 300H
Tabla_página_3
      ADDWF   PCL,         F         ;
      ADDWF   PCL,         F         ;
      RETLW   0x
      .
      .
      RETLW   0x                     ; (200 valores de la tabla 3)
; ----------------------
ORG 400H
Tabla_página_4
      ADDWF   PCL,         F         ;
      ADDWF   PCL,         F         ;
      RETLW   0x
      .
      .
      RETLW   0x                  ; (200 valores de la tabla 4)
; ----------------------