Autor Tema: PIC18 y sus misterios  (Leído 11422 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: PIC18 y sus misterios
« Respuesta #15 en: 07 de Octubre de 2015, 05:06:23 »
A pedido de RALF vamos a dar un par de ejemplos. Voy a usar un PIC18F2550, ya que es comun.

Primero que nada vamos a ver el archivo del linker asi vemos como esta separada su memoria. El archivo en cuestion se llama 18f2550_g.lkr, en este tenemos podemos ver 2 secciones y el conflicto al momento de activar el set de instrucciones extendido.


Primero tenemos la Flash, ahi vemos nuestra memoria "page", tenemos los fuses en config, tenemos el ID del PIC en "idlocs" y tenemos la memoria EEPROM como "eedata"

Código: [Seleccionar]
CODEPAGE   NAME=page       START=0x0               END=0x7FFF
CODEPAGE   NAME=idlocs     START=0x200000          END=0x200007       PROTECTED
CODEPAGE   NAME=config     START=0x300000          END=0x30000D       PROTECTED
CODEPAGE   NAME=devid      START=0x3FFFFE          END=0x3FFFFF       PROTECTED
CODEPAGE   NAME=eedata     START=0xF00000          END=0xF000FF       PROTECTED

Luego continua la RAM y esta esta separada en 2 partes


Código: [Seleccionar]
#IFDEF _EXTENDEDMODE
  DATABANK   NAME=gpre       START=0x0               END=0x5F
#ELSE
  ACCESSBANK NAME=accessram  START=0x0               END=0x5F
#FI

La primera dependiendo si esta activo o no el set va a funcionar de una u otra forma, como dijimos si tenemos un ACCESS = 'a'= 0 y una direccion menor a 0x60, va a funcionar de distinta forma. Y en el caso que no este activado el set extendido ese pedazo de memoria se clasifica como ACCESSBANK
Seguido de esto solamente quedan los demas bancos ( ver el DATABANK ) y los SFR (otra ves ACCESBANK):

Código: [Seleccionar]
DATABANK   NAME=gpr0       START=0x60              END=0xFF
DATABANK   NAME=gpr1       START=0x100             END=0x1FF
DATABANK   NAME=gpr2       START=0x200             END=0x2FF
DATABANK   NAME=gpr3       START=0x300             END=0x3FF
DATABANK   NAME=gpr4       START=0x400             END=0x4FF
DATABANK   NAME=gpr5       START=0x500             END=0x5FF
DATABANK   NAME=gpr6       START=0x600             END=0x6FF
DATABANK   NAME=gpr7       START=0x700             END=0x7FF
ACCESSBANK NAME=accesssfr  START=0xF60             END=0xFFF          PROTECTED


OK, visto el linker todavia no vimos ningun ejemplo xD. Lo lamento pero estoy mostrando lo que no normalmente no se ve. Y donde encontrar las respuestas. Asi la gente se familiariza con lo que es el linker, el compilador, etc.

Primero vamos a probar algun codigo con el set de instrucciones estandar, para poder comparar y como todas las instrucciones que tengan esa 'a' en su instruccion van a actuar igual. Lo que vamos a hacer es usar una unica instruccion, en este caso es

Código: ASM
  1. ADDWF f,d,a

Esta nos va a permir cargar un numero en W e intentar repartirlo a donde sea. Para eso creamos este codigo:


CODIGO COMPLETO PARA EL SET ESTANDAR
Código: ASM
  1. ;************************************************    
  2. ;   INCLUDES
  3. ;************************************************
  4.    
  5. #include "p18f2550.inc"
  6.  
  7.    
  8. ;************************************************    
  9. ;   Definicion de variables
  10. ;************************************************    
  11.  
  12.    ; Solo PIC18
  13.    ; Udata - Data no inicializada
  14.    ; Access data
  15.    ; Ubicacion: 0x00 a 0x5F
  16.     udata_acs
  17. Var1:   res     1
  18. Var2:   res     1
  19. Buff:   res     8
  20.    
  21.     ; Udata - Data no inicializada
  22.     ; Comienza en 0x60 el banco 0 ( DAATBANK ) si es que no coloco una direccion
  23.     ; Lo acomoda solo el linker, basta de renegar con CBLOCKS
  24. Bank0:  udata  0x89
  25. V1:     res     1
  26. V2:     res     1
  27. V3:     res     1
  28.  
  29.  
  30.     ; Udata
  31.     ; Variables puestas en el 5to banco
  32. Bank5:  udata  0x500
  33. BVar1:  res     1
  34. BVar2:  res     1
  35. BVar3:  res     1
  36.  
  37.        
  38. ;************************************************    
  39. ;   Vectores de reset e interrupcion
  40. ;************************************************    
  41.    
  42.    
  43.        
  44. Rst:    code    0x00    ;Vector de Reset
  45.         GOTO    Inicio
  46.    
  47. IntB:   code    0x08    ;Vector de Interrupcion Alta Prioridad
  48.         RETURN
  49.    
  50. IntA:   code    0x18    ;Vector de Interrupcion Baja Prioridad
  51.         RETURN
  52.  
  53.    
  54. ;************************************************    
  55. ;   Configuracion de modulos
  56. ;************************************************
  57.    
  58. Inicio:
  59.    
  60.     ; Ponemos el Puerto B como todas salidas
  61.     CLRF    LATB        ; Limpiamos los latch de salida
  62.     MOVLW   0x0E        ; Seteamos Rb4:0 como digitales
  63.     MOVWF   ADCON1      ; Solo por si alguno activo el FUSE PBADEN
  64.     CLRF    TRISB       ; Ponemos todo el puerto como salida
  65.    
  66. ;************************************************    
  67. ;   Programa Principal
  68. ;************************************************    
  69.    
  70. Main:
  71.     MOVLW   0x10                ; Cargo un valor y empiezo a sumar
  72.     MOVLB   0x0                 ; Me aseguro que comienze en el banco 0
  73.    
  74.     ADDWF   Var1, F, ACCESS     ;Var1 ubicado en 0x00
  75.     ADDWF   BVar1, F, ACCESS    ;Bvar1 ubicado en 0x500
  76.     ADDWF   V1, F, ACCESS       ;V1 ubicado en 0x66    
  77.    
  78.     NOP
  79.     GOTO    $                   ;Loop infinito
  80.  
  81. ;----------- Fin de programa ---------------------        
  82.     END


Tengo los bits de los fuses en otro archivo solo para que no moleste en el codigo. Bueno primero que nada vemos un par de diferencias. A lo que estamos acostumbrados y es el no usar CBLOCK !. CBLOCK simplemente asigna constantes y ahi comienzan los problemas. Supongamos esto que es TAN TAN comun:

Archivo1.asm:
Código: ASM
  1. CBLOCK
  2. Var1
  3. Var2
  4. Var3
  5. ENDC
  6.  
  7. ...
  8.  
  9. ;final del archivo
  10. #include(Archivo2.asm) ;delay te suena?

Archivo2.asm (Libreria):
Código: ASM
  1. CBLOCK
  2. LibVar1
  3. LibVar2
  4. LibVar3
  5. ENDC

Eso no es crear una variable. El linker no tiene ni la menor idea que es una variable eso. CBLOCK asigna constantes. Es como tener muchos EQU, pero permite achicarlo mas obviamente

Código: ASM
  1. Var1 EQU 0x00

Y comienza con el valor que se le da, si no se le da un valor comienza por 0x00, ¿se puede usar?, por supuesto!, para un programa con codigo absoluto es genial. pero hacer lo que puse antes va a llevar que LibVar1 se le asigne un 0, y en el primer archivo Var1 igual es 0.

Entonces si luego hacemos: ADDWF Var1,F o ADDWF LibVar1,F

Ambos son iguales que hacer: ADDWF 0x00,F

Para solucionar esta mala usada y problemas de programacion, como cuando cambian de PIC y se encuentran que la RAM comienza en 0x20 y no en 0x0C y terminan escribiendo los registros de los perifericos, solo quedaba de poner todo las variables en un CBLOCK solo, o de contar las variables, y que el otro archivo comienze con ese offset, si seguimos el ejemplo

Archivo1.asm:
Código: ASM
  1. CBLOCK 0x20
  2. Var1
  3. Var2
  4. Var3
  5. ENDC
  6.  
  7. ...
  8.  
  9. ;final del archivo
  10. #include(Archivo2.asm)

Archivo2.asm (Libreria):
Código: ASM
  1. CBLOCK  0x23
  2. LibVar1
  3. LibVar2
  4. LibVar3
  5. ENDC

Ahora imaginate con varios archivos , y agregar una sola "variable" al comienzo, ¿Hermoso trabajo no?
Otro es el de incluir archivos (si otra hermosura es eso de poner el include de los delay al ultimo),
La desicion es de cada uno. de usarlo o no, yo en el codigo hice un codigo que se le llama "Relocatable" el cual permite agregar mas variables sin problemas.

Al comienzo del post elegi mostrar el archivo del linker e hice especial atencion a lo de ACCESSBANK y DATABANK ( o al menos lo intente ).

Yo use las siguientes directivas:

Código: [Seleccionar]
Nombre seccion: udata_acs Direccion
Nombre seccion: udata Direccion

udata_acs usa el ACCESSBANK del linker, como ven los unicos lugares son de las memorias 0x00 a 0x5F
y udata, reserva en cualquier lugar que seas el DATABANK. Si no le das direccion el linker lo acomoda solo

¿Resumen? POR FAVOR

Le dije al linker que tengo 3 variables en el ACCESBANK, entonces el linker decidio de ponerlos en la direccion 0x00, luego a los demas le di direccion de memoria y asi quedaron:

Código: [Seleccionar]
Nombre Direccion

Var1 0x00
Var2 0x01
Buff 0x02-0x09
V1 0x89
V2 0x8A
V3 0x8B
BVar1 0x500
BVar2 0x501
BVar3 0x502


Esto puedo verlo en la memoria de datos cuando lo este simulando. Ahora vamos a ver que pasa con cada instruccion que agregamos, el OPCODE de la instruccion ADDWF f,d,a es

Código: [Seleccionar]
0010 01da ffff ffff
ahi se puede ver que bit es el de la d, el de la a, y que f solo ocupa 8bits que opcodes generarian estas instrucciones?

Código: ASM
  1. ADDWF   Var1, F, ACCESS         ;0010 0110 0000 0000
  2.     ADDWF   BVar1, F, ACCESS            ;0010 0110 0000 0000
  3.     ADDWF   V1, F, ACCESS               ;0010 0110 1000 1001

Primero notar que las 2 primeras instrucciones son iguales en opcde, a pesar que BVar1 esta en 0x500, pero solo toma 8 bits,

Al hacer esas instrucciones paso a paso queda asi:

Código: [Seleccionar]
Var1 = 0x10 - 1era instruccion
Var1 = 0x20 - 2da instruccion
LATA = 0x10 - 3era instruccion

Al ser de 8 bits el lugar para f en el opcode ,solo tomo nomas 0x00 y accedo al banco 0 con direcciones 0x00 a 0x5F ( access bank ). En el caso de la tercera instruccion al ser mayor o igual a 0x60 y seleccionar ACCESS accedio a los SFR, puse a proposito esa direccion para que coincidiera con LATA ( por si las dudas )

Nada que ver lo que quisimos hacer xD. Pero bueno esto demuestra lo errado de esas instrucciones. Como acceder correctamente a esos lugares? Asi que vamos a cambiar un poco las instrucciones. Asi que cambie el codigo por este:


Código: ASM
  1. Main:
  2.     MOVLW   0x10                ; Cargo un valor y empiezo a sumar
  3.  
  4.     MOVLB   0x5                 ; Banco 5
  5.     ADDWF   Var1, F, ACCESS     ; Var1 ubicado en 0x00
  6.     ADDWF   BVar1, F, BANKED    ; Bvar1 ubicado en 0x500
  7.     MOVLB   0x0
  8.     ADDWF   V1, F, BANKED       ;V1 ubicado en 0x89    
  9.    
  10.     GOTO    $                   ;Loop infinito

Al hacer eso tengo los siguientes resultados (paso a paso igual que antes):

Código: [Seleccionar]
Var1(0x000) = 0x10
BVar1(0x500) = 0x10
V1(0x089) = 0x10

Esto es lo que hace el acceso directo. Podriamos haber aprovechado que estabamos en el banco 0 al comienzo y cambiado el orden, asi tener el mismo resultado

Código: ASM
  1. Main:
  2.     MOVLW   0x10                ; Cargo un valor y empiezo a sumar
  3.     MOVLB   0x0                 ; Banco 5
  4.    
  5.     ADDWF   Var1, F, ACCESS     ; Var1 ubicado en 0x00
  6.     ADDWF   V1, F, BANKED       ;V1 ubicado en 0x89    
  7.     BANKSEL BVar1
  8.     ADDWF   BVar1, F, BANKED    ; Bvar1 ubicado en 0x500
  9.    
  10.     GOTO    $                   ;Loop infinito

Ahi se observa que como el banco estaba en cero con banked pude acceder a todo. Y se preguntaran. Que ocurriria si yo utilizo una instruccion con una direccion menor a 0x60 y le pongo el BANKED. Bueno para eso simplemente 2 lineas simples

Código: ASM
  1. ADDWF   Var1, F, ACCESS ; opcode 0x2600
  2.     ADDWF   Var1, F, BANKED     ; opcode 0x2700

Resultado

Código: [Seleccionar]
Var1(0x00) = 0x10
Var1(0x00) = 0x20

Si, el banked le importa nada la direccion. solo le hace caso al banco que esta seleccionado y listo. Y hace uso de sus 8 bits del opcode para la direccion formar la direccion.
Ahh una cosa.. Si observaron puse un BANKSEL , esto es bueno por que si yo coloco en cualquier otro lado mi variable, no debo cambiar el valor del banco ahi, directamente el linker le agregar una linea.
Para el caso del PIC18 es un MOVLB

Que nos queda? El direccionamiento Indirecto. Supongamos que teniamos el mismo caso que recien. En el que tenia una variable en el banco 5 ( 0x500 ) y tenemos que estar cambiando ese y el del banco 0 (0x89).
Primero que nada ver lo irrealista que esto, en el access bank deberias tener lo que siempre usas. ya que podes acceder a el en cualquier lugar sin necesidad de cambiar bancos, luego podrias tener todas tus variables en un banco.Y se evitaria el problema que comento arriba, pero es un ejemplo.

Código: ASM
  1. Main:
  2.     MOVLW   0x10                ; Cargo un valor y empiezo a sumar
  3.     MOVLB   0x0                 ; Banco 5
  4.     LFSR    2,BVar1
  5.    
  6.     ADDWF   Var1, F, ACCESS     ; Var1 ubicado en 0x00
  7.     ADDWF   V1, F, BANKED       ;V1 ubicado en 0x89    
  8.     ADDWF   INDF2, F, ACCESS    ; Bvar1 ubicado en 0x500
  9.     NOP
  10.    
  11.     GOTO    $                   ;Loop infinito

Al termino de la direccion LFSR, el par de registros FSR2 se carga con 0x500 y luego puedo acceder a lo que hay en esa direccion con INDF2, registro que se encuentra en los SFR, se hace notar que no cambio de banco para nada. Paso a paso nuevamente:

Código: [Seleccionar]
Var1 (0x000) = 0x10
V1 (0x089) = 0x10
BVar1 (0x500) = 0x10

El direccionamiento indirecto como ven no depende de elegir el banco, es capaz de direccionar toda la memoria con sus 12bits.

Por ultimo vamos a activar el set extendido y ver si realmente funciona asi o no...
Para eso tengo que activarlo desde la configuracion de proyectos. El primer cambio que encontramos es que ya no existe mas el ACCESSBANK, si recordamos el linker, este no existiria. Asi que si intentamos compilar el otro codigo nos vamos a encontrar con ese error. Es imposible meter una variable ahi.
Asi que este es el esqueleto del programa:

CODIGO COMPLETO PARA EL SET EXTENDIDO
Código: ASM
  1. ;************************************************    
  2. ;   INCLUDES
  3. ;************************************************
  4.    
  5. #include "p18f2550.inc"
  6.  
  7.    
  8. ;************************************************    
  9. ;   Definicion de variables
  10. ;************************************************    
  11.  
  12.     ; Udata - Data no inicializada
  13.     ; Comienza en 0x00 si es que no coloco una direccion, ya no hay mas ACCESSBANK, solo DATABANK
  14.     ; Lo acomoda solo el linker, basta de renegar con CBLOCKS
  15. Bank0:  udata  0x00
  16. Var1:   res     1
  17. Var2:   res     1
  18. Var3:   res     1
  19.        
  20. Bank01: udata  0x89
  21. V1:     res     1
  22. V2:     res     1
  23. V3:     res     1
  24.  
  25.     ; Udata
  26.     ; Variables puestas en el 5to banco
  27. Bank5:  udata  0x500
  28. BVar1:  res     1
  29. BVar2:  res     1
  30. BVar3:  res     1
  31.  
  32.        
  33. ;************************************************    
  34. ;   Vectores de reset e interrupcion
  35. ;************************************************    
  36.    
  37.    
  38.        
  39. Rst:    code    0x00    ;Vector de Reset
  40.         GOTO    Inicio
  41.    
  42. IntB:   code    0x08    ;Vector de Interrupcion Alta Prioridad
  43.         RETURN
  44.    
  45. IntA:   code    0x18    ;Vector de Interrupcion Baja Prioridad
  46.         RETURN
  47.  
  48.    
  49. ;************************************************    
  50. ;   Configuracion de modulos
  51. ;************************************************
  52.    
  53. Inicio:
  54.    
  55.     ; Ponemos el Puerto B como todas salidas
  56.     CLRF    LATB            ; Limpiamos los latch de salida
  57.     MOVLW   0x0E            ; Seteamos Rb4:0 como digitales
  58.     MOVWF   ADCON1, ACCESS  ; Solo por si alguno activo el FUSE PBADEN
  59.     CLRF    TRISB           ; Ponemos todo el puerto como salida
  60.    
  61. ;************************************************    
  62. ;   Programa Principal
  63. ;************************************************    
  64.    
  65. Main:
  66.     MOVLW   0x10                ; Cargo un valor y empiezo a sumar
  67.     MOVLB   0x0                 ; Banco 5
  68.     LFSR    2,0x300             ; Apuntando al banco 3
  69.  
  70.     NOP
  71.    
  72.     GOTO    $                   ;Loop infinito
  73.  
  74. ;----------- Fin de programa ---------------------        
  75.     END


No cambiamos casi nada solo cambie el udata_acs por udata de esa forma teniamos algo "equivalente" a nuestro ejemplo anterior. Vamos a probar lo mismo reemplazando ese NOP por lo siguiente:

Código: ASM
  1. ADDWF   Var1, F, ACCESS
  2.     ADDWF   BVar2, F, ACCESS
  3.     ADDWF   V1, F, ACCESS

Cambie la segunda linea por BVar2 (0x501). Resultado:

Código: [Seleccionar]
Memoria 0x300 = 0x10
Memoria 0x301 = 0x20
LATA = 0x10

Peor xD.
Como se puede ver yo a proposito puse el FSR2 en 0x300 al comienzo del programa. mi idea era justamente esa. Aqui podemos ver que en ACCESS y con el set extendido, tenemos que cuando la direccion es menor a 0x60 ( Reocordar que solo pueden ir 1 byte en el opcode y BVar solo dejaria 0x01 ) lo que se hace es acceder a la direccion del FSR2 + offset dado por el byte del opcode, en la primera es 0x300 + 0x00, en la segunda instruccion es 0x300 + 0x01 y por ultimo al hacer la 3ra instruccion alojado en 0x89, accedemos a los SFR como antes.

Esto es lo unico que cambia con respecto al otro. Y como que no utilizarias nunca el nombre de un registro para eso ya que lo que te interesaria seria poner el valor base con el FSR2 y luego acceder a cada valor con un offset, supongamos que quiero ponerles un 0x10 a los valores de memoria 0x120 ,0x125, 0x150.

Con el set extendido, yo puedo hacer eso con esto:
Código: ASM
  1. LFSR    2,0x120
  2.         ADDWF   [0x0],F
  3.         ADDWF   [0x5],F
  4.         ADDWF   [0x30],F

« Última modificación: 10 de Octubre de 2015, 02:15:23 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: PIC18 y sus misterios
« Respuesta #16 en: 07 de Octubre de 2015, 09:22:14 »
Le dije al linker que tengo 4 variables en el ACCESBANK, entonces el linker decidio de ponerlos en la direccion 0x00, luego a los demas le di direccion de memoria y asi quedaron:

Código: [Seleccionar]
Nombre Direccion

Var1 0x00
Var2 0x01
Buff 0x03-0x08
V1 0x89
V2 0x8A
V3 0x8B
BVar1 0x500
BVar2 0x501
BVar3 0x502


Esto puedo verlo en la memoria de datos cuando lo este simulando. Ahora vamos a ver que pasa con cada instruccion que agregamos, el OPCODE de la instruccion ADDWF f,d,a es

Lo siento no encuentro lo de la memoria de datos para poder visualizar el ejemplo, solo encuentro Program Memory, o tengo que añadir estas lineas al Linker, de ser asi ¿Donde?

Nombre seccion:      udata_acs   Direccion
Nombre seccion:      udata      Direccion

Y GRACIAS por el tutorial que estas haciendo.
« Última modificación: 07 de Octubre de 2015, 09:30:22 por Miquel_S »
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: PIC18 y sus misterios
« Respuesta #17 en: 07 de Octubre de 2015, 09:39:11 »
No al linker no lo tocas, solo lo mostre como es y como esta definida la memoria.


Para ver la memoria de datos:

En el mismo lugar donde ves el Progra Memory abajo hay 2 listas
En la de la izquierda elegi  "File Registers"

Podes elegir luego el formato con las lista de la derecha
"Symbols" esta bueno para ver la memoria y vas a ver que el linker asigna el lugar y le pone el valor de la etiqueta, lo feo es que se necesita hacer un scroll muy largo para recorrer la memoria
"Hex" no te muestra nada de etiquetas, pero podes llegar mas rapido a ver todas las memorias, un simple scroll y estas por el 0x300

Como vos le dijiste al linker que son variables. Tranquilamente cuando lo simulas podes abrir en Window -> Debuging -> Variables
Ahi haces click a la izquierda que hay un diamante con un + y te permite elegir todas las variables, estan como "Global symbols", solo se cargan cuando lo simulas.

¿Tenes que agregar algo?

No, para nada. Tenes 2 archivos "completos", 1 con el set standard que es el primero y el otro con el set extendido, ahi lo voy a resaltar en el post

Lo unico que podes/tenes que cambiar es lo de dentro del Main, lo demas lo dejas como esta hasta probar todo.



A mi lo de Pic me da igual, lo he puesto por solidarizarme con los demás, pero me importa un pimiento  :D :D YO QUIERO ARM, QUE NUNCA HE HECHO NADA DE ASM EN ARM :D :D Y CUANDO MIGRE SERÁ CON TODAS LAS DE LA LEY :D

así que bueno me esperaré  :mrgreen: :mrgreen:

Hoy hice el archivo del linker, con las secciones .data , .text y .bss
Tengo que hacer el archivo startup.s con el codigo de inicializacion de datos en la RAM + stack ( tengo que hacer el codigo y tengo una parte de un ejemplo )
Tengo que hacer el archivo main.s con un loop infinito, el mas corto de todos
Me habia puesto a hacer el Makefile, le falta bastante. especialmente ver todas las opciones del compilador de asm y el linker.
Y finalmente no tengo la menor idea como probarlo xD. Tengo el GDB del gcc, pero NI NI NI idea como funciona, los comandos, etc. Acepto sugerencias aca.
« Última modificación: 07 de Octubre de 2015, 09:53:50 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: PIC18 y sus misterios
« Respuesta #18 en: 07 de Octubre de 2015, 09:57:10 »
Gracias de nuevo ya lo encontré  :-/

Saludos!
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado yair_xiox

  • PIC16
  • ***
  • Mensajes: 210
Re: PIC18 y sus misterios
« Respuesta #19 en: 07 de Octubre de 2015, 12:19:45 »
hola killer, podrías poner algo de un pic18 comunicándose con un sensor bluethoot como el hc-06 y como seria el envió de caracteres asci, para que quede funcionando la comunicación entre el sensor y el micro 

Desconectado RALF2

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2060
Re: PIC18 y sus misterios
« Respuesta #20 en: 07 de Octubre de 2015, 13:59:19 »
Muy buena y nutrida información, lo que me genero muchas dudas  :(
Primero no entiendo como funciona bien lo del linker  :oops:
El cblock, porque no debe utilizarse?, sera porque solo sirve para declarar constantes que luego no pueden ser modificadas en el programa?
No soy experto en asm, de hecho llevo años que no lo toco solo conozco lo basico de la serie pic16xxxx.
Ahora bien ando un poco atareado estos dias, asi que voy a leer bien todo para poder hacer mis preguntas que las tengo jijji.
Otra cocita:
Citar
    ; Udata - Data no inicializada
    ; Comienza en 0x60 si es que no coloco una direccion
    ; Lo acomoda solo el linker, basta de renegar con CBLOCKS
Bank0:   udata  0x66
V1:   res   1
V2:   res   1
V3:   res   1
No deberia comensar en 0x66 en vez de 0x66?

Y como un aporte mio a lo que coloco el amigo KILLERJC (no le podia dejar todo el trabajo a el  :mrgreen:)
Les coloco esto, que aclara algunas cosas hechas por el amigo  ;-)

Saludos
« Última modificación: 07 de Octubre de 2015, 14:02:22 por RALF2 »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: PIC18 y sus misterios
« Respuesta #21 en: 07 de Octubre de 2015, 15:44:19 »
Muy buena y nutrida información, lo que me genero muchas dudas  :(
Primero no entiendo como funciona bien lo del linker  :oops:
El cblock, porque no debe utilizarse?, sera porque solo sirve para declarar constantes que luego no pueden ser modificadas en el programa?
No soy experto en asm, de hecho llevo años que no lo toco solo conozco lo basico de la serie pic16xxxx.
Ahora bien ando un poco atareado estos dias, asi que voy a leer bien todo para poder hacer mis preguntas que las tengo jijji.
Otra cocita:
Citar
    ; Udata - Data no inicializada
    ; Comienza en 0x60 si es que no coloco una direccion
    ; Lo acomoda solo el linker, basta de renegar con CBLOCKS
Bank0:   udata  0x66
V1:   res   1
V2:   res   1
V3:   res   1
No deberia comensar en 0x66 en vez de 0x66?

Y como un aporte mio a lo que coloco el amigo KILLERJC (no le podia dejar todo el trabajo a el  :mrgreen:)
Les coloco esto, que aclara algunas cosas hechas por el amigo  ;-)

Saludos
Hola RALF2 por lo que yo entiendo el Banco 0  empieza en la posición 060h y termina en la 0FFh y el con udata 0x66 le esta diciendo que posicione la variable V1 en la posición 0x66
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: PIC18 y sus misterios
« Respuesta #22 en: 07 de Octubre de 2015, 16:09:21 »
Hay una cosa que no entiendo, o hay un error cuando declaras las variables
Código: ASM
  1. ; Solo PIC18
  2.    ; Udata - Data no inicializada
  3.    ; Access data
  4.    ; Ubicacion: 0x00 a 0x5F
  5.     udata_acs
  6. Var1:   res     1
  7. Var2:   res     1
  8. Buff:   res     8
le estas diciendo que se posiciona Var1 en 0x00, Var2 0x01 y Buff 0x02 pero aquí estas diciendo que Buff empieza en 0x03 ¿No deberia de ser 0x02 y termina en 0x09?
Código: ASM
  1. Nombre  Direccion
  2.  
  3. Var1    0x00
  4. Var2    0x01
  5. Buff    0x03-0x08
  6. V1      0x89
  7. V2      0x8A
  8. V3      0x8B
  9. BVar1   0x500
  10. BVar2   0x501
  11. BVar3   0x502
lo mismo ocurre con V1:
Código: ASM
  1. Bank0:  udata  0x66
  2. V1:     res     1
  3. V2:     res     1
  4. V3:     res     1
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: PIC18 y sus misterios
« Respuesta #23 en: 07 de Octubre de 2015, 19:40:32 »
Les pido perdon es que cambie el programa mientras lo iba haciendo. voy a responderles y luego arreglarlo

Miguel

Citar
le estas diciendo que se posiciona Var1 en 0x00, Var2 0x01 y Buff 0x02 pero aquí estas diciendo que Buff empieza en 0x03 ¿No deberia de ser 0x02 y termina en 0x09?
Este es un error mio, habia puesto 4 variables en cada seccion, y encima solo uso 1. resulto que tenia Var1,Var2,Var3 y Buff, luego borre, pero me olvide cambiarle eso, como todas las demas variables como V4 y BVar4 estaban al ultimo no tuve problemas con los otros. Pero ese se me salto.
Buff deberia comenzar en 0x02 y terminar en 0x09 como bien decis.
Para direccionarlo a lo demas ahces Buff+1, Buff+3,Buff+n

Citar
lo mismo ocurre con V1:
Otro de mis cambios en el medio del programa para ver si realmente ocurria, elegi primero el 0x66 por que vi un SFR en 0xF66 resulto luego que ese registro no se puede escribir, y termine buscando otro. el cual es el LATx que comienzan de 0x89, crei haber cambiado todos los valores. Como es un pedazo de texto un poquito grande.. se me paso realmente.

Ya corrijo esos errores, asi no causan mas confusion.
EDIT: Creo que estan todos corregidos


RALF

Citar
Muy buena y nutrida información, lo que me genero muchas dudas  Sad
Primero no entiendo como funciona bien lo del linker  Embarassed
El cblock, porque no debe utilizarse?, sera porque solo sirve para declarar constantes que luego no pueden ser modificadas en el programa?
No soy experto en asm, de hecho llevo años que no lo toco solo conozco lo basico de la serie pic16xxxx.
Ahora bien ando un poco atareado estos dias, asi que voy a leer bien todo para poder hacer mis preguntas que las tengo jijji.
Otra cocita:
No deberia comensar en 0x60 en vez de 0x66?

Vamos por parte, contesto la ultima pregunta.
Cuando estas con el set de instrucciones standard ( y que seguro NO vas a cambiarlo pero ahi es donde reside la diferencia ) para el linker la memoria de 0x00 a 0xFF se encuentra dividida en 2 partes, una que le llama ACCESSBANK y  otra que le llama DATABANK.
ACCESSBANK utilizaria las posiciones de memoria 0x00 a 0x5F
y el DATABANK ( banco 0 )  comienza en 0x60 y termina en 0xFF

Ya voy a explicar lo del linker.
Primero que nada fue un error mio poner 0x66 como bien le respondi a Miguel antes, mi idea era poner variables en memoria que comenzaran en 0x89, yo cambie el programa pero me olvide de cambiar unas partes del texto.
Entonces con ese udata le digo al linker que quiero que todo lo que reserve ahi se ubique en la posicion 0x89, a pesar que comienza en 0x60 para el linker ese pedazo de memoria.

Antes de continuar parece que el linker necesita un poco de explicacion.
Vos tenes un compilador. En este caso es el mpasm , este compilador lo que hace es trasformar tu archivo assembler, uno por uno, en un codigo objeto. Es un codigo objecto por cada archivo. Entonces ¿como se arma el codigo maquina que va en el PIC cuando tengo 2 archivos?. Esto lo hace el linker. El linker comienza a ver todos los archivos y suponete que tenes esto:

Código: ASM
  1. Archivo1:    udata_acs
  2. Var1:   res     1
  3. Var2:   res     1
  4. Buff:   res     8
  5.  
  6. Archivo2:    udata_acs
  7. Var5:   res     1
  8. Var4:   res     1
  9. Buff1:  res     8
(Estarian separado en cada archivo solo lo junto para que quede compacto)

El linker recibe esos codigos objectos y por ejemplo lee el primer archivo... mmm el compilador me dice que debo "reservar" 3 variables (ademas de eso crea "simbolos" para indicarle el nombre al linker) y que ocupan 10 bytes y estan en el accessbank.
Entonces el linker busca en su archivo de linker y observa que ACCESSBANK ocupa de 0x00 a 0x5F.  Como no tiene direccion de inicio lo pone apenas comienza de 0x00 a 0x09, y guarda para el mismo como un "puntero" al ACCESSBANK. listo! ya ubicamos el primer archivo, ahora debemos ir por el segundo, cuando lee el segundo, de nuevo otra ves el compilador le dice que debe reservar otros 10! y en el access bank, para eso el muy picaron ya sabe donde comienza y donde termina el ACCESSBANK por que ya lo leyo, y sabe de donde tiene que poner los datos, por ese "puntero" que guardo. Usa ese "puntero" para comenzar de 0x0A a 0x13, Si por alguna razon tuvo muchas variables y se excedio pasandose del 0x5F, el linker va a tirar un error, y va a decirte: Es imposible meter esta cantidad de datos en ACCESSBANK, por que vos estas usando 0x80 de datos y el largo es de 0x5F nomas.

De la misma forma funciona el codigo.
Si vos tenes varios archivos no hace falta incluir TODOS. simplemente si observas yo puse: la directiva code y no org. Si hago asi para todos los archivos ASM que tenga, no necesito incluirlos para nada. El linker va a comenzar por uno por ejemplo el main, va a ver cuanta memoria posee con el archivo del linker, va a ver que rango de memoria peude usar, seria imposible que vos hagas un 0xFFFF cuando la memoria solo alcanza hasta 0x1FFF por ejemplo, y el linker te acusa,
Comienza por un archivo, y el compilador ASM le indico con sus ORG y CODE que parte es codigo y donde esta ubicado. El linker comienza a armar esto en la fhas, pone X cosa en un lugar, pone Y cosa en otro lugar. Y termine mi archivo, nuevamente guardo un "puntero" de la direccion del final del archivo, cuando viene el otro archivo, comienza a llenar desde ese puntero.

Y no hice ningun include!. El include podrias verlo como copiar todo el otro archivo en uno solo. Que se hace para mayor simplicidad. ( no es una copia exactamente hablando, pero es para que veas la direferencia )
Pero ahora sin ningun include, como es que podes llamar a la funcion de otro archivo? Clasico de un delay.
Para eso el compilador crea simbolos ( estos simbolos luego lo utiliza el linker ) para que se unan. Ejemplo:

main.s
Código: ASM
  1. .extern  _Delay1ms
  2.  
  3.    CALL _Delay1ms

Delay.s
Código: ASM
  1. .global  _Delay1ms
  2.  
  3. _Delay1ms:
  4.             ;Aca codigo delay
  5.             RETURN

Aqui lo que hago es decirle primero al compilador que cree un simbolo _Delay1ms, con extern le digo que ese simbolo proviene de otro archivo. y con .global le dige que ese simbolo esta para que lo usen los demas archivos.
Luego el linker observa ambos archivos  y conoce que desde main.s se llama a _Delay1ms del otro archivo. Como el linker es el que pone los pedazos de codigo a su gusto. Una ves que ubica el codigo en las flash ( supongamos que a Delay1ms lo puso en la posicion de la FLASH 0xF0, transforma por si solo ese simbolo _Delay1ms del CALL en un CALL 0xF0, sin tu intervencion.

Podras observar una cosa, y es que NADA te garantiza cual archivo es el que va a tomar primero el linker, si va a respetar las posiciones de memoria de codigo y datos que le des, si no hay direccion asignada los va a acomodar como el quiera. Entonces vos no podes saber si en 0x00 va a estar Var1 o Var5, pero esto a vos no te importa!, por que cuando haces una instruccion con ese Var1, el linker sabe donde lo ubico y reemplaza ese Var1 por la direccion del mismo. ESTA es la diferencia de un codigo que se amolda solo (rellocatable) y uno absoluto ( en el que vos controlas valor por valor la posicion de memoria flash y la de datos ).

CBLOCK es absoluto. Y ese es uno de los problemas cuando tenes varios archivos, como ves en el ejemplo de arriba que el linker es el que me posiciona las variables a su gusto y luego las "linkea" las une con sus nombres en las instrucciones, en el caso de CBLOCK esto no pasa. Y cuando agregas variables simplemente tenes que saber que posicion ocupan Fue el caso de tener 2 archivos con un CBLOCK que comienza en 0x20 por ejemplo.

Otra cosa tambien es que con CBLOCK vos sos el que tiene el poder de seleccionar la posicion. Si haces un

CBLOCK 0x5E
Var1 ;0x5E
Var2 ;0x5F
Var3 ;0x60
ENDC

cuando hagas un ADDWF VAR3,F,ACCESS no va a funcionar. Por que la direccion es 0x60 y va a intentar escribir los SFR y no la direccion 0x60 de memoria de datos. Pero una cosa mas, NADIE pero NADIE ( linker , compilador ) te lo va a acusar que te pasaste, que estas escribiendo una posicion de memoria que no debes,etc , por que el linker no sabe que eso son "variables" son solo constantes que se van a reemplazar el programa. Voy a intentar crear un ejemplo en el que se use un ADDWF Var2,F,ACCCESS y vemos la diferencia a la salida del compilador


Con CBLOCK el ADDWF quedaria algo asi (obviamente esto ya esta compilado y se pierden los nemonicos, pero es para el ejemplo )

ADDWF 0x5F,F,ACCESS

Sin CBLOCK y con udata_acs:

ADDWF <simboloDeVar2>,F,ACCESS

Luego el linker cuando posiciona Var2 por que esta definido en udata_acs reemplaza la direccion alli (los ultimos 8 bits en este caso obviamente)

Y aqui va la pregunta...
¿Debo o no usar CBLOCK ?

Para un codigo simple no es problema. Pero te fuiste a otro PIC y tal ves cambio todo eso. O si tenes muchos archivos con variables en cada uno, ejemplo LCD,Delays,RS232,main, cada uno con un CBLOCK y si, es un dolor de cabeza a no ser que tires valores grandes y que quede espacio entre los CBLOCKs para ahorrarte ese dolor de reacomodar todo.
Nuevamente con CBLOCK al ser vos el que posiciona las variables sos vos el encargado de revisar que esten bien, que no se "sobrepongan". Esto es un codigo absoluto.

Ahora voy a aclarar una cosa, por ahi dije que para el linker el banco 0 esta dividido en 2, Y eso es verdad, Realmente el banco 0 es un pedazo de memoria de 0x00 a 0xFF, eso se puede ver cuando hicimos una instruccion con BANKED y la direccion era menor a 0x5F ( estando seleccionado el banco 0 obviamente ), pero se crea una "regla" en el archivo del linker diciendo que esta separada en 2, sino el linker podria creer que todo el banco 0 es accesible como ACCESSBANK y ubicar variables que pasen los 0x5F de memoria. y luego en el programa falle. Con esa regla (archivo) limitamos al linker a posicionar las variables en esa porcion de memoria nomas. La cuales traen las ventajas de avisarnos cuando lo superamos ( que no entran mas) despreocuparnos por donde van. etc.

Espero lograr hacerte entender lo que hace el linker, obviamente es mas complicado, como que se crean tablas de simbolos, simbolos localres, tablas de secciones con cada uno su puntero etc etc etc.
Haber en C y no en ASM.... cuando uno hace un extern variable; es lo mismo que aca, es decirle al linker que tiene que unirlo con la variable definida en otro archivo. Como ves el linker/compilador funciona de la misma forma que aca. Solo cambiamos el compilador de uno de ASM por uno de C.
« Última modificación: 07 de Octubre de 2015, 21:36:10 por KILLERJC »

Desconectado RALF2

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2060
Re: PIC18 y sus misterios
« Respuesta #24 en: 07 de Octubre de 2015, 20:20:41 »
Veamos a ver sino estoy equivocado:

Citar
Hola RALF2 por lo que yo entiendo el Banco 0  empieza en la posición 060h y termina en la 0FFh y el con udata 0x66 le esta diciendo que posicione la variable V1 en la posición 0x66

El banco 0 va de 0x000 a 0x0FF, pero en lo que respecta al access bank se utiliza los bytes que van desde 0x000 a 0x05F, la posicion 0x061 corresponderia a banco 0 tambien, pero para poder acceder a ella hay que utilizar el bank select (pag. 66 del data sheet).
« Última modificación: 07 de Octubre de 2015, 20:46:31 por KILLERJC, Razón: Perdon modifique sin querer, creo presionar citar :P »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: PIC18 y sus misterios
« Respuesta #25 en: 07 de Octubre de 2015, 20:50:38 »
Veamos a ver sino estoy equivocado:

Citar
Hola RALF2 por lo que yo entiendo el Banco 0  empieza en la posición 060h y termina en la 0FFh y el con udata 0x66 le esta diciendo que posicione la variable V1 en la posición 0x66

El banco 0 va de 0x000 a 0x0FF, pero en lo que respecta al access bank se utiliza los bytes que van desde 0x000 a 0x05F, la posicion 0x061 corresponderia a banco 0 tambien, pero para poder acceder a ella hay que utilizar el bank select (pag. 66 del data sheet).

Respondi arriba, estaba editandolo. Te respondo:

El banco 0 realmente comienza en 0x00 y termina en 0xFF
Lo que se puede acceder cuando en el opcode es access es de 0x00 a 0x5F
Si queres acceder a memorias 0x60 a 0xFF tenes que usar acceso indirecto o por el BANKED, usando el registro BSR formando la direccion completa BSR:Direccion ( 12 bits )
La separacion de 0x00 a 0x5F como access bank y 0x60 a 0xFF es imaginara del linker. Es para limitar las variables que vaya a poner en esas posiciones de memoria, asi sabe que si intentas poner 0x80 bytes ahi va a saltar un error por que el largo es de 0x5F nomas.
En resumen es para que el linker se maneje.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: PIC18 y sus misterios
« Respuesta #26 en: 08 de Octubre de 2015, 01:39:32 »
En una respuesta a RALF LINK

Lo que sigue a continuacion no tiene NADA que ver con PIC18, ni con ASM, sino con el proceso de compilacion.

Hable sobre que como el compilador genere un .o y luego el linker los une, pero esto es un invento hasta que no se demuestre obviamente.
Para demostrar masomenos que eso realmente ocurre observamos la salida de la consola del MPLAB:

Compilacion con el mpasmx del archivo configuracion.asm , genera 3 archivos, object ( .o ), listing ( .lst ) y error ( .err )

Código: [Seleccionar]
"/opt/microchip/mplabx/v3.10/mpasmx/mpasmx" -q -p18f2550 -u -l\"build/default/production/configuration.lst\" -e\"build/default/production/configuration.err\" -y -o\"build/default/production/configuration.o\" \"configuration.asm\"
Compilacion con el mpasmx del archivo main.asm , genera 3 archivos, object ( .o ), listing ( .lst ) y error ( .err ) , el listing y error son para el usuario

Código: [Seleccionar]
"/opt/microchip/mplabx/v3.10/mpasmx/mpasmx" -q -p18f2550 -u -l\"build/default/production/main.lst\" -e\"build/default/production/main.err\" -y -o\"build/default/production/main.o\" \"main.asm\"
Finalmente Linkeamos con el mplink,

Entradas: el archivo linker ( .lkr ) opciones como _EXTENDEDMODE (indica que tengo activo el set extendido) y que use el main.o y configuration.o creado antes
Salidas: el .map que indica cuanto ocupan cada espacio y como se distribuyo la memoria, y el .cof que ya es el archivo compilado

Código: [Seleccionar]
"/opt/microchip/mplabx/v3.10/mpasmx/mplink"  "/opt/microchip/mplabx/v3.10/mpasmx/LKR/18f2550_g.lkr"  -p18f2550  -w  -m"dist/default/production/PIC18asm.X.production.map" -u_EXTENDEDMODE  -z__MPLAB_BUILD=1  -odist/default/production/PIC18asm.X.production.cof  build/default/production/main.o build/default/production/configuration.o
Finalmente, llama a otro ejecutable que transforma el .cof en un .hex , lo traduce de un formato a otro. este es el mp2hex

Código: [Seleccionar]
MP2HEX 5.08, COFF to HEX File Converter
Copyright (c) 1998-2011 Microchip Technology Inc.
Errors    : 0

Y aqui queda demostrado que eso ocurre! realmente OCURRE!,

Compilador

Para seguir investigando vamos a crear un simple proyecto con 2 archivos, vamos a llamar de un archivo a otro, vamos a usar variables definidas en un lado y en otro. Y vamos a ver los resultados que obtenemos, finalmente ver como queda posicionado en memoria TODO esto.

Para esto creamos 2 archivos, que llame: main.s y auxiliar.s , estos archivos estan simplificados al maximo. Es decir no tiene codigo para configurar los modulos, no inclui el .inc para hacer mas visible esto, ni nada por el estilo. Tienen muy pocas intrucciones tambien.

Aqui dejo los 2 archivos:

main.s ( si, no posee include, lo saque a proposito y no deben agregarlo para que funcione )

Código: ASM
  1. ;************************************************    
  2. ;   Definicion de variables
  3. ;************************************************    
  4.  
  5.         ; Externo lo de afuera, y global para que los demas lo vean
  6.         global  Var1
  7.         extern  _Suma, Var3
  8.    
  9. Bank0:  udata_acs
  10. Var1:   res     1
  11. Var2:   res     1
  12.        
  13. ;************************************************    
  14. ;   Vectores de reset e interrupcion
  15. ;************************************************    
  16.    
  17. Rst:    code    0x00    ;Vector de Reset
  18.         GOTO    Main
  19.    
  20.         org    0x08     ;Vector de Interrupcion Alta Prioridad
  21.         RETURN
  22.    
  23.         org    0x18     ;Vector de Interrupcion Baja Prioridad
  24.         RETURN
  25.  
  26. ;************************************************    
  27. ;   Programa Principal
  28. ;************************************************    
  29.    
  30. Main:
  31.     CALL    _Suma
  32.     NOP
  33.     MOVLW   0x78
  34.     IORWF   Var3
  35.     NOP
  36.     GOTO    $           ;Loop infinito
  37.  
  38. ;----------- Fin de programa ---------------------        
  39.     END

auxiliar.asm

Código: ASM
  1. ;************************************************    
  2. ;   Mas variables, 1 mas y definiciones
  3. ;************************************************
  4.  
  5.         ; Externo lo de afuera, y global para que los demas lo vean
  6.         extern  Var1
  7.         global  _Suma, Var3
  8.        
  9.         udata_acs
  10. Var3:   res     1
  11.  
  12.        
  13. ;************************************************    
  14. ;   CODIGOOOOOOOOOOOOOOOOOO
  15. ;************************************************      
  16.         code
  17.        
  18. _Suma:
  19.         MOVLW   0x10
  20.         ADDWF   Var1
  21.         RETURN
  22.        
  23.        
  24. ; Fin del archivo      
  25.        
  26.         END

OK compilamos y..... TODO PERFECTO!
Probamos nuestro codigo. Este comienza en el vector de reset, va al Main, entra en el CALL y se ejecuta _Suma del otro archivo, modifica la variable que esta definida en el primer archivo, vuelve y ahi desde el main.s modifico la variable definida en el auxiliar.
Y lo que es peor funciona! .. Lo pueden simular

Antes dijimos que el linker va a acomodar el programa donde MAS le guste, va a posicionar las variables como le guste si es que no especificamos una direccion concreta.
Vamos a la memoria de programa y tenemos esto:

Código: [Seleccionar]
     Line     Address       Opcode           Label                       DisAssy               
        1  0000          EF0D                              GOTO 0x1A                           
        2  0002          F000                              NOP                                 
        3  0004          0000                              NOP                                 
        4  0006          FFFF                              NOP                                 
        5  0008          0012                              RETURN 0                             
        6  000A          0E10         _Suma                MOVLW 0x10                           
        7  000C          2600                              ADDWF Var1, F, ACCESS               
        8  000E          0012                              RETURN 0                             
        9  0010          FFFF                              NOP                                 
       10  0012          FFFF                              NOP                                 
       11  0014          FFFF                              NOP                                 
       12  0016          FFFF                              NOP                                 
       13  0018          0012                              RETURN 0                             
       14  001A          EC05         Main                 CALL 0xA, 0                         
       15  001C          F000                              NOP                                 
       16  001E          0000                              NOP                                 
       17  0020          0E78                              MOVLW 0x78                           
       18  0022          1202                              IORWF Var3, F, ACCESS               
       19  0024          0000                              NOP                                 
       20  0026          EF13         _.org_1_0026         GOTO 0x26

Veamos como estan ubicados. Los vectores de reset e interrupcion estan en sus correspondientes lugares como se pidio. (0x0 , 0x8 y 0x18), El Main sigue luego del vector de interrupcion, esto es obvio por que eso pedimos. Dijimos con el "org" esto va a partir de ACA (0x18). Y _Suma ???? Como era tan pequeño y entraba entre los vectores de interrupcion el linker decidio ponerlo ahi!. Es decir el linker acomodo solo la seccion de codigo, hasta aprovechando el espacio en este caso. ¿Esto va a ocurrir siempre?, no esto no ocurre siempre asi. Pero aca se puede ver como es el linker quien toma los 2 archivos, y los une en uno solo sin necesidad de includes. Ahora veamos la memoria de datos:

Código: [Seleccionar]
    Address      Symbol      Hex     Decimal        Binary       Char 
000           Var1        0x00    0            00000000        '.'     
001           Var2        0x00    0            00000000        '.'     
002           Var3        0x00    0            00000000        '.'     

El linker me acomodo las secciones de datos de cada archivo ( access ) como a el le gusto. Y todo esto:

- Sin indicar direcciones ( a excepcion de los vectores de reset/interrupcion )
- Sin includes .. y no me importan donde esta la función (si al final del archivo o no), yo puedo llamarla, solo tengo que decirle: "Esto esta en otro archivo arreglatelas vos linker".

Al comienzo hablamos que el compilador genera varios archivo mas aparte del .o , vamos a build/default/production/ desde la carpeta de nuestro proyecto y... encontramos todos los archivos esos, como todo compilo bien no hay errores, por lo cual main.err y auxiliar.err estan vacios. ahora vamos a ver los listing, este archivo nuevamente repito y remarco lo crea el compilador, y no el linker.

Veamos algunos, y de paso les muestro lo que quiero que vean. Al abrir el archivo al final nos encontramos con esto:

mains.lst
Código: [Seleccionar]
SYMBOL TABLE
  LABEL                             VALUE

Main                              0000001A
Var1                              00000000
Var2                              00000001
Var3                              00000000
_.org_1_0026                      00000026
_Suma                             00000000
__18F2550                         00000001

auxiliar.lst

Código: [Seleccionar]
SYMBOL TABLE
  LABEL                             VALUE

Var1                              00000000
Var3                              00000000
_Suma                             00000000
__18F2550                         00000001

Se ven la tabla de los simbolos, cada archivo posee la suya. Ahi vemos todas las "etiquetas" que creamos y tambien las que difinimos como "externas" es decir que existen (en algun lugar), esto al compilador no le interesa, el solo compila.

Ademas hay un __18F2550 agregado por el compilador, esto no se si les recuerda cuando tiene un archivo para muchos micros y ponen:

Código: [Seleccionar]
ifdef __18F2550
   Hacer algo
endif
ifdef __16F628A
   Hacer otra cosa
endif

Para eso esta :P.
Otra cosa interesante de esto se ve en la parte del codigo dentro de estos lst:

main.lst
Código: [Seleccionar]
LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00001         list
                      00002 ;************************************************   
                      00003 ;   Definicion de variables
                      00004 ;************************************************   
                      00005         
  0000                00006         global  Var1
  0000                00007         extern  _Suma, Var3
                      00008     
                      00009 Bank0:  udata_acs
000000                00010 Var1:   res     1
000001                00011 Var2:   res     1
                      00012         
                      00013 ;************************************************   
                      00014 ;   Vectores de reset e interrupcion
                      00015 ;************************************************   
                      00016     
                      00017 Rst:    code    0x00    ;Vector de Reset
000000 EF?? F???      00018         GOTO    Main
                      00019     
                      00020         org    0x08     ;Vector de Interrupcion Alta Prioridad
000008 0012           00021         RETURN
                      00022     
                      00023         org    0x18     ;Vector de Interrupcion Baja Prioridad
000018 0012           00024         RETURN
                      00025 
                      00026 ;************************************************   
                      00027 ;   Programa Principal
                      00028 ;************************************************   
00001A                00029 Main:
00001A EC?? F???      00030     CALL    _Suma
00001E 0000           00031     NOP
000020 0E78           00032     MOVLW   0x78
000022 12??           00033     IORWF   Var3
000024 0000           00034     NOP
000026 EF?? F???      00035     GOTO    $           ;Loop infinito
                      00036
                      00037 ;----------- Fin de programa ---------------------       
                      00038     END
auxiliar.lst
Código: [Seleccionar]
LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00001
                      00002 ;************************************************   
                      00003 ;   Mas variables Wiii
                      00004 ;************************************************
                      00005
                      00006         ; Externo lo de afuera, y global para que los demas lo vean
  0000                00007         extern  Var1
  0000                00008         global  _Suma, Var3
                      00009         
                      00010         udata_acs
000000                00011 Var3:   res     1
                      00012
                      00013         
                      00014 ;************************************************   
                      00015 ;   CODIGOOOOOOOOOOOOOOOOOO
                      00016 ;************************************************       
                      00017         code
                      00018         
000000                00019 _Suma:
000000 0E10           00020         MOVLW   0x10
000002 26??           00021         ADDWF   Var1
000004 0012           00022         RETURN
                      00023         
                      00024         
                      00025 ; Fin del archivo       
                      00026         
                      00027         END

Observen la posicion de cada una de las instrucciones/datos ( es la columna de la izquierda ) , es justamente LOC (Ubicacion) , lo que ven a la derecha de ese numero es el opcode de la instruccion, las directivas tiene LOC 0.
Viendo el main.lst notamos como cuando creamos datos los numera, Var1 ocuparia la posicion de memoria 000000 de datos, Var2 la 000001 de datos, luego cuando comienza el codigo ( code ) el indice cambia y comienza nuevamente de 0, responde a los "org" y va dando la posicion de la flash como si solo de ese archivo se tratase. Esto significa que tiene un "puntero" para datos y un puntero para "programas" o para ser mas correcto es un puntero por seccion.

Luego vamos a nuestro auxiliar.lst y encontramos algo curioso: el dato comienza en 0x00 y no 0x02 ( si recordamos del main) y el codigo tambien. Estarian superponiendose "supuestamente", esto no es asi. Luego el linker va a acomodar todo eso. Ya que como dijimos y vuelvo a repetir, esto al compilador NO le importa, NO es su trabajo.

Nombremos ademas otra cosa, recuerda cual era el opcode de el ADDWF? era asi 0010 01fa xxxx xxxx  (0x26xx con f=1 y a=0)
En este caso f es 1, a es 0 y pero ¿x?. Veran que tiene un 0x26?? , ese opcode no es valido, Ese opcode luego el linker lo va a acomodar cuando proceda a unir todo y reemplaze los simbolos por las posiciones de memoria que les asigno el  linker a esos datos.

Linker

Se vio claramente el tema de los simbolos, como el compilador piensa en un solo archivo a la ves, y luego es el linker quien reune todos estos pedazos. Solo nos queda un solo archivo para ver. Y es lo que devuelve el linker, ademas del .cof que ya conocemos, el linker devuelve un .map, podriamos decirlo como un informe del linker, asi como el .lst es un informe del compilador.

Abrimos el MAP y encontramos:

Primero un informe de las secciones ( lo recorte un poco )

Código: [Seleccionar]
                                 Section Info
                  Section       Type    Address   Location Size(Bytes)
                ---------  ---------  ---------  ---------  ---------
                      Rst       code   0x000000    program   0x000004
                   .cinit    romdata   0x000004    program   0x000002
                   .org_0       code   0x000008    program   0x000002
                    .code       code   0x00000a    program   0x000006
                   .org_1       code   0x000018    program   0x000012
.config_300000_BUILD/DEFAULT/PRODUCTION/CONFIGU    romdata   0x300000    program   0x000001
                  ...........................................................
.config_30000D_BUILD/DEFAULT/PRODUCTION/CONFIGU    romdata   0x30000d    program   0x000001
                    Bank0      udata   0x000000       data   0x000002
               .udata_acs      udata   0x000002       data   0x000001

Veamos que secciones tiene mi linker, pero antes no se si se preguntaron el por que al codigo de _Suma no lo puso luego del vector de reset, si este entraba ahi. Aca hay algunas respuestas. Cada seccion tiene un nombre, a la izquierda vemos cuales son. Rst ( Miren la etiqueta en el programa ) ubicado en el 0x00, en la memoria de programa y de largo 4 bytes. y luego de eso... La seccion .cinit, seccion utilizada por C pero que nuestro linker parece tener ya pre-establecido (Esto evito que _Suma ubique la posicion de comienzo). Luego tenemos los .org que pusimos y el .code de nuestro auxiliar!. Luego de eso esta la lista de fuses. y al ultimo tenemos 2 secciones, si 2, la primera llamada Bank0 y la otra .udata_acs , ¿ pero no lo definimos a los con udata_acs ?, Si pero sin querer agregue la etiqueta Bank0 en el main.s :P. Mientras que auxiliar no tiene nada. , observen ademas que ahi dice donde comienza, el largo y donde se almanena, es decir en la memoria de datos. Si yo no hubiera agregado la etiqueta los hubiera puesto todo dentro de una misma seccion. Lo mismo si antes de la etiqueta Main hubiera puesto "code", esto hubiera hecho que se junte en una sola seccion "code" el codigo de auxiliar ( y ya no entraria mas entre medio de los vectores - Al final pruebo esto )

Siguiendo un poco mas abajo el archivo se puede encontrar las porciones de memoria contiguas llenas de Flash, como que no hay mucho para explicar aca:

Código: [Seleccionar]
                              Program Memory Usage
                               Start         End     
                           ---------   ---------     
                            0x000000    0x000005     
                            0x000008    0x00000f     
                            0x000018    0x000029     
                            0x300000    0x300003     
                            0x300005    0x300006     
                            0x300008    0x30000d     
            44 out of 33048 program addresses used, program memory utilization is 0%

Y finalizando, mas SIMBOLOS!

Código: [Seleccionar]
                            Symbols - Sorted by Name
                   Name    Address   Location    Storage File                     
              ---------  ---------  ---------  --------- ---------               
                   Main   0x00001a    program     static /home/x/workspace/MPLAB/PIC18asm.X/main.asm
           _.org_1_0026   0x000026    program     static /home/x/workspace/MPLAB/PIC18asm.X/main.asm
                  _Suma   0x00000a    program     extern /home/x/workspace/MPLAB/PIC18asm.X/auxiliar.asm
                   Var1   0x000000       data     extern /home/x/workspace/MPLAB/PIC18asm.X/main.asm
                   Var2   0x000001       data     static /home/x/workspace/MPLAB/PIC18asm.X/main.asm
                   Var3   0x000002       data     extern /home/x/workspace/MPLAB/PIC18asm.X/auxiliar.asm


Donde dice la direccion asignada, el nombre, donde se ubican, y si son locales o globales, esto es 1 por cada archivo. Se observa que esas variables que declaramos globales estan como extern y las que son solamente locales, es decir solo del archivo y no se pueden acceder de otro lado son static.
( ¿ Ahora te suena los modificadores static y extern de C ? )

-----------------------------------
Probando mas cosas

Probando unir las secciones. Comente que iba a probar esto y ver como quedaba, lo que hice fue: Quitarle el Bank0: al udata_acs del main.s y antes del Main: le agregue un "code" asi como esta el archivo auxiliar.s, Resumen:

main.s ( Cambios, asi quedaron ahora)
Código: ASM
  1. udata_acs
  2. Var1:   res     1
   
Código: ASM
  1. code
  2. Main:

Simulo:
- Memoria de datos igual.
- Memoria de programa: CAMBIO!, ahora esta todo luego de los vectores, por que ahora es todo un pedazo grande de instrucciones.
- Los archivos .lst perdieron ese simbolo ( Bank0 )
- El .map ahora esta formado por otra cosa:


Código: [Seleccionar]
                  Section       Type    Address   Location Size(Bytes)
                ---------  ---------  ---------  ---------  ---------
                      Rst       code   0x000000    program   0x000004
                   .cinit    romdata   0x000004    program   0x000002
                   .org_0       code   0x000008    program   0x000002
                   .org_1       code   0x000018    program   0x000002
                    .code       code   0x00001a    program   0x000016
.config_300000_BUILD/DEFAULT/PRODUCTION/CONFIGU    romdata   0x300000    program   0x000001
               .udata_acs      udata   0x000000       data   0x000003

Ahora .udata_acs esta todo en una seccion propia, y .code en su propia seccion, conteniendo a ambos codigo de los 2 archivos. Como ahora la seccion ".code" era muy grande no entro entre medio de los vectores. Y el linker jamas puede poner un GOTO por el mismo para aprovechar eso. Tampoco lo podria dividir ya que sino alteraria el programa.


Error de linker - Simbolo faltante
Bueno ya probe esto, ahora quiero ver si le meto un error, Voy a comentar el global a un archivo y ver que sucede

Comente la linea "global Var1" en el main.s, asi de esa forma no se crea el simbolo y auxiliar.s no tiene donde unirse y obtengo un error:

Código: [Seleccionar]
make[2]: *** [dist/default/production/PIC18asm.X.production.hex] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2

MPLINK 5.08, LINKER
Error - could not find definition of symbol 'Var1' in file 'build/default/production/auxiliar.o'.
Errors    : 1

¿De quien es ese error?, parece del linker, la cultura popular dira que es del compilador, ya que este hace todo. Si voy a los archivos main.err y auxiliar.err veo y ..... NADA, vacios!, claramente al compilador le importa poco si existen o no por fuera del archivo xD, solo el linker quien es el encargado de unir las cosas.

Error de linker - Memoria Fuera de rango
(Esto no es la idea de ponerle una direccion, realmente si vamos a hacer un codigo que el linker lo acomode solo no deberiamos poner direcciones)

A mi main lo vuelvo al original y le hago un cambio mas:

Código: ASM
  1. Bank0:          udata_acs 0x5F
  2. Var1:   res     1
  3. Var2:   res     1
(Aclarar que el Bank0 esta ahi asi creo otra seccion, como se vio en el map)

Con CBLOCK Var1 se definiria como 0x5F y Var2 como 0x60 sin problemas.
Si yo compilo asi, termino con esto:

Código: [Seleccionar]
Error - section 'Bank0' can not fit the absolute section. Section 'Bank0' start=0x0000005f, length=0x00000002
Errors    : 1

Exacto, no podes alojar eso ahi. ya que esta en el borde y solo hay 1 lugar, nuevamente los .err generados por el compilador estan vacios.

Error del compilador - Mala instruccion
Y ya que estamos por curiosodad, veamos que sale de un archivo .err
Volvemos al original y le cambie el IORWF Var3 por IOXWF Var3

Miramos la consola y vemos los errores:

Compilador:
Código: [Seleccionar]
Warning[207] /home/fabian/workspace/MPLAB/PIC18asm.X/main.asm 34 : Found label after column 1. (IOXWF)
Error[122]   /home/fabian/workspace/MPLAB/PIC18asm.X/main.asm 34 : Illegal opcode (Var3)

Linker:
Código: [Seleccionar]
Error - Error reading object file 'build/default/production/main.o'
Errors    : 1

El compilador que no entiende nada y el linker que no encontro los archivos .o por que se suspendio todo y no se generaron, ahora voy al .err y tengo lo mismo que me dio por la consola:

Código: [Seleccionar]
Warning[207] /home/fabian/workspace/MPLAB/PIC18asm.X/main.asm 34 : Found label after column 1. (IOXWF)
Error[122]   /home/fabian/workspace/MPLAB/PIC18asm.X/main.asm 34 : Illegal opcode (Var3)

Bueno esto es todo, un lindo paseo por las herramientos y la compilacion, si alguna ves leyeron de listing, map entre otras opciones en C, es realmente esto.
El compilador C ( mejor dicho su ejecutable ) puede llegar a hacer todo en un solo paso y no en 2 como hice al comienzo, este seria un caso bastante especial, pero por dentro ( internamente) estan divididos asi como esta explicado, el compilador C funciona como el de ASM, va  crear varias secciones de la misma forma, nomas que estas ya tienen un nombre particular como .text , .data y .bss .
Por eso mucho no me queria meter aca con esto xD, ya que esto es programacion general y no solo de PIC18, en fin, espero no haber dicho cualquier barbaridad y haber demostrado algo. Estoy seguro que hay gente que me supera en conocimientos por mucho, y seguro que algun defecto le va a encontrar, pero esto es hasta lo que yo se.
« Última modificación: 10 de Octubre de 2015, 02:16:44 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re:PIC18 y sus misterios
« Respuesta #27 en: 09 de Octubre de 2015, 12:06:55 »
Gracias de nuevo KILLERJC, estoy aprendiendo un montón y espero poder seguir aprendiendo.

Miquel_S
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC18 y sus misterios
« Respuesta #28 en: 09 de Octubre de 2015, 17:09:34 »
Ya saben como va el post, cualquier cosa pidan, si lo se voy a intentar decirlo como es.
Ahi voy a hacer un codigo para que envie datos por la UART y reciba por interrupcion para yair_xiox , mas que obvio es que va a ser un solo dato y recibir un dato, lo que haga con el dato luego es tema de el.
Mejor aun ahora que lo pienso voy a hacer un loop. es decir, lo recibido lo envio de vuelta

Desconectado yair_xiox

  • PIC16
  • ***
  • Mensajes: 210
Re:PIC18 y sus misterios
« Respuesta #29 en: 09 de Octubre de 2015, 17:16:44 »
gracias killer, igual en el trabajo no me dejan programar en asembler todo es en c


 

anything