TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Nocturno en 13 de Septiembre de 2007, 06:03:08

Título: Complicando para simplificar
Publicado por: Nocturno en 13 de Septiembre de 2007, 06:03:08
Este hilo también podía haberse llamado "Añadiendo código para optimizar".

Lo que pretendo compartir con vosotros es algo que he observado en mis programas en C, e imagino que muchos de vosotros también lo ha visto.

He adquirido la costumbre de revisar el código ASM que generan mis programas una vez compilados y cuando veo algo que me sorprende por su tamaño, intento mejorarlo.

Así, en ocasiones he observado como a veces un código más largo o complejo en C, genera paradójicamente un código más compacto, corto y rápido en ASM.

Os dejo por aquí un ejemplo, y me comprometo a ir posteando los que me vaya encontrando a lo largo del camino por si sirve de ilustración.

Observad este trocito de código, que compara una Variable de 16 bits con una constante:
if (Variable>0x0A00)
      Variable=0;


Pues bien, al compilarlo genera un ASM de 12 CICLOS:
Código: ASM
  1. ....................    if (Variable>0x0A00)
  2. 0047:  BCF    03.5
  3. 0048:  MOVF   22,W
  4. 0049:  SUBLW  09
  5. 004A:  BTFSC  03.0
  6. 004B:  GOTO   055
  7. 004C:  XORLW  FF
  8. 004D:  BTFSS  03.2
  9. 004E:  GOTO   053
  10. 004F:  MOVF   21,W
  11. 0050:  SUBLW  00
  12. 0051:  BTFSC  03.0
  13. 0052:  GOTO   055

Puestos a probar otras alternativas, lo modifiqué así:
if ((Variable>>8)>0x0A)
      Variable=0;


Y el código generado se redujo en dos ciclos:
Código: ASM
  1. ....................    if ((Variable>>8)>0x0A)
  2. 005B:  MOVF   22,W
  3. 005C:  MOVWF  23
  4. 005D:  CLRF   24
  5. 005E:  MOVF   24,F
  6. 005F:  BTFSS  03.2
  7. 0060:  GOTO   065
  8. 0061:  MOVF   23,W
  9. 0062:  SUBLW  0A
  10. 0063:  BTFSC  03.0
  11. 0064:  GOTO   067

Mi grata sorpresa vino cuando compilé esta tercera versión del código:
if (make8(Variable,1)>0x0A)
      Variable=0;


Con esta última version, obviamente más larga y compleja que la primera, el código ASM se quedó en 4 CICLOS:
Código: ASM
  1. ....................    if (make8(Variable,1)>0x0A)
  2. 0055:  MOVF   22,W
  3. 0056:  SUBLW  0A
  4. 0057:  BTFSC  03.0
  5. 0058:  GOTO   05B

Os recomiendo reviséis el ASM porque, sobre todo en micros pequeñitos, podemos ganar bastante haciendo ligeros cambios en nuestros programas.
Título: Re: Complicando para simplificar
Publicado por: elmasvital en 13 de Septiembre de 2007, 11:50:26
A ver comentemoslo de forma amistosa...

en el primer compilado de 12 ciclos en ASM estamos haciendo que el micro compare 2 números de 16 bits.

en el segundo compilado de 10 ciclos en ASM estamos haciendo que el micro convierta una variabe de 16 a 8 bits y lo compare con uno de 8 bits

y en el tercer caso hay algo que no me cuadra muy bien, pq hace tiempo que no toco ccs... Make8 es una instrucción del precompilador? Es una rutina?... No me cuadra en ningun caso pq si fuera algo del precompilador no podrias hacerlo en medio del programa y si fuera una rutina deberia plasmarse tal cosa en ASM y claramente ese compilado muestra unicamente una comparacion de dos numeros de 8 bits.

Tambien puede ocurrir algo y es que en las rutinas generales que mete ccs en el compilado asm esté la de make8... entonces si veriamos ahorro de codigo pero deberia reflejarse en un desplazamiento de la variable a algun registro y el salto a esa rutina en el asm cosa que no se ve en el asm del 3er caso.

Comprueba el hex resultante manolo en ambos casos a ver si cambia de tamaño.

1 saludo.
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 13 de Septiembre de 2007, 12:28:55
Es muy simple, José Antonio.

make8 es una función del compilador, que extrae un byte de un word (o incluso de un long word).

Como el compilador sabe cuál es el byte que voy a extraer porque se lo estoy indicando con una constante, genera el código asm que apunta directamente a ese byte en la memoria (MOVF   22,W) y se ahorra el resto de operaciones.

Este CCS, cuando no tiene bugs, está muy bien hecho.
Título: Re: Complicando para simplificar
Publicado por: sander en 13 de Septiembre de 2007, 12:50:13
Aqui hay algo que no me cuadra, la primera instruccion  que pones es variable > 0x0A00 , si variable es igual a 0X0A01 se cumplira la condicion, en tu ultima "optimizacion"  comparas la parte alta de variable con 0x0A y si variable vale  0x0A01 no se no entra el if , entonces lo primero y lo ultimo no es lo mismo.
Título: Re: Complicando para simplificar
Publicado por: micro_cadaver en 13 de Septiembre de 2007, 12:54:18
es la optimizacion del C mediante el propio programador. aunque en el caso de sander habria que probar otro metodo.
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 13 de Septiembre de 2007, 13:52:47
Normalmente cuando veo en mis programas que no hay espacio u otra anormalidad, procuro llevar ciertas funciones al asm
de todas formas es una buena costumbre, así se conoce como trabaja el compilador, aprovechando este hilo, recuerdo haber leido en uno de tus post manolo, algo relacionado a usar los if en vez de los case para simplificar el código generado, no recuerdo donde está el post.
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 13 de Septiembre de 2007, 14:56:11
Sander, tienes razón. Es muy buena la observación, aunque para el caso que lo necesito no me afecta en absoluto.
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 17 de Marzo de 2008, 18:32:45
Acerca de las directivas #inline y #separate

en la ayuda dice:

#inline:
"Tells the compiler that the function immediately following the directive is to be implemented INLINE.   This will cause a duplicate copy of the code to be placed everywhere the function is called.  This is useful to save stack space and to increase speed. Without this directive the compiler will decide when it is best to make procedures INLINE."


#separate:
"Tells the compiler that the procedure IMMEDIATELY following the directive is to be implemented SEPARATELY.  This is useful to prevent the compiler from automatically making a procedure INLINE. This will save ROM space but it does use more stack space. The compiler will make all procedures marked SEPARATE, separate, as requested, even if there is not enough stack space to execute"

probando con unas funciones, antes y después, cambiando las directivas, tengo las siguientes estadisticas:



(http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=18676.0;attach=6419)



debido a limitaciones no he comprobado fisicamente si aumenta la velocidad de ejecución del código, pero si esto es cierto, para aquellos que necesiten velocidad, les caerá bien, (y en aquellos pic que sean generosos en memoria de programa)

Título: Re: Complicando para simplificar
Publicado por: sander en 17 de Marzo de 2008, 19:57:39
Alguna vez use el separate porque el codigo resultaba muy grande, en esa ocacion analice un poco el codigo en ensamblador que genero el compilador y lo que hacia era sustituir el codigo por un call o un goto hacia la subrutina, por lo que me parece que la velocidad de ejecucion no mejora mucho que digamos 1 call + 1 return 4 ciclos de reloj, claro que segun la aplicacion esto puede ser importante.

Saludos
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 18 de Marzo de 2008, 04:00:55
Pero no es solamente el goto o el call; también te evitas que guarde contexto en el stack.
Título: Re: Complicando para simplificar
Publicado por: stk500 en 18 de Marzo de 2008, 04:27:15
Tranquilo en mi PC leyendos las compliaciones de Manolo,  :D :D :D :D y lo que hace el Ron,  :D :D :D siga Maestros  :lol: :lol: :lol:
porque hare despues mis preguntas,  :D :D :D
Título: Re: Complicando para simplificar
Publicado por: RICHI777 en 18 de Marzo de 2008, 12:08:58
Hola, en si la funcion make8 se puede implementar como macro, son casi standar de factos las implementaciones de Les dejo la implementacion de HI y LO
Código: [Seleccionar]
/* Get High byte of the an word */
#define HI( Data )                                                \
           (( byte ) (((( word ) Data ) >> 8 ) & 0xFF ))          \

/* Get Low byte of an word */
#define LO( Data )                                                \
           (( byte ) ((( word )( Data )) & 0xFF ))                \
En mi caso estas macros las tengo implementadas en un modulo que exporto de proyecto en proyecto y asi no dependo tanto de las funciones que me brinde el compilador.

En el caso de las optimizaciones es muy buena la observacion de sander, el tema seria lo mismo si la Variable que en ejemplo 1 es un word pase a ser un byte, al compilador le resulta menos esfuerzo lidiar con bytes que con words, de ahi la optimización.

Saludos !



Título: Re: Complicando para simplificar
Publicado por: sander en 18 de Marzo de 2008, 13:34:17
Pero no es solamente el goto o el call; también te evitas que guarde contexto en el stack.

mmm guarda el contexto en el stack cuando salta a una interrupcion, pero para una subrutina lo principal seria la inicializacion de las variables locales que usa la subrutina, pero esto lo hace con el #inline o el #separate

Saludos
Título: Re: Complicando para simplificar
Publicado por: RICHI777 en 18 de Marzo de 2008, 13:37:21
Me parece que mas que el contexto de stack es el "Stack frame" ....
Título: Re: Complicando para simplificar
Publicado por: Sispic en 18 de Marzo de 2008, 14:42:50

Os recomiendo reviséis el ASM porque, sobre todo en micros pequeñitos, podemos ganar bastante haciendo ligeros cambios en nuestros programas.


No te conozco Manolo ... asi que ahorrando ciclines .
Se supone que "Variable" es de 16 bits

if (make8(Variable,1)>0x0A)
Si el byte menos significativo no lo verifica  no se cumple "if (Variable>0x0A00)" si por ejemplo "Variable" vale 0x0A01
Aunque quizas ya te valia asi .



Título: Re: Complicando para simplificar
Publicado por: Nocturno en 18 de Marzo de 2008, 15:31:58
Sí, maestro, ya se dió cuenta de mi error Sander unos meses atrás  :D :D :D

Aqui hay algo que no me cuadra, la primera instruccion  que pones es variable > 0x0A00 , si variable es igual a 0X0A01 se cumplira la condicion, en tu ultima "optimizacion"  comparas la parte alta de variable con 0x0A y si variable vale  0x0A01 no se no entra el if , entonces lo primero y lo ultimo no es lo mismo.
Título: Re: Complicando para simplificar
Publicado por: Sispic en 18 de Marzo de 2008, 16:36:45
Eso me pasa por leer tanto despues de salir  de farra hasta las 8 AM.  8)
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 23 de Mayo de 2008, 17:41:24
como trabaja #zero_ram

El funcionamiento de #zero_ram, es limpiar la ram a través del direccionamiento indirecto.

En un 16F, con el par INDF + FSR y en un 18F con FSR0H + POSTINC0, si analizan mejor el código generado por #zero_ram, consume mas lineas en asm, porque usan variables para hacer decrementos, en cambio si se le indica al puntero hasta donde debe llegar, menos lineas:

ej: 18F

Código: C
  1. void limpiar_la_ram(){
  2. #asm
  3.       lfsr  FSR0,primer_banco_ram
  4. next: clrf  POSTINC0
  5.       btfss FSR0H,3  // ultimo_banco_ram
  6.       bra   next
  7. #endasm
  8. }

gasté 4 lineas, en contraste con las 13 lineas que genera el #zero_ram

Código: ASM
  1. 0008:  MOVLW  FE
  2. 000A:  MOVWF  00
  3. 000C:  MOVLW  08
  4. 000E:  MOVWF  01
  5. 0010:  MOVLW  02
  6. 0012:  MOVWF  FE9
  7. 0014:  MOVLW  00
  8. 0016:  MOVWF  FEA
  9. 0018:  CLRF   FEE
  10. 001A:  DECFSZ 00,F
  11. 001C:  BRA    0018
  12. 001E:  DECFSZ 01,F
  13. 0020:  BRA    0018


Título: Re: Complicando para simplificar
Publicado por: Gonzalo_BlackHawk en 23 de Mayo de 2008, 23:39:38
Hola a todos. Muy interesantes sus opiniones chicos. Yo tambien soy fan de exprimir el C hasta ahorrarme el ultimo microsegundo, sin embargo hay casos donde optimizar en forma viciosa hace que el código sea ilegible y que el mantenimiento del mismo sea un dolor de cabeza, sobre todo cuando hace tiempo que no lo tocamos. Obviamente queda en manos de uno decidir cuando ya hemos optimizado lo suficiente, y esto hay que analizarlo con cada caso.

Un ejemplo de lo que digo es colocar a cero todos los elementos de una matriz. Puedes hacerlo mediante un bucle o bien individualmente, lo cual esta comprobado que reduce el código en ASM. Esto no conlleva importancia cuando tenemos una matriz de 10 elementos, sin embargo, no creo que tener un código en C que borra una matriz de 32 x 128 elementos en forma individual sea lo mas comodo, pero eso ya es ha gusto del programador.

Saludos.
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 24 de Mayo de 2008, 01:14:28
Gonzalo, pero eso depende del tamaño de la matriz. Si quieres poner a 0 una de 32 x 128 obviamente siempre saldrá más corto el ASM con un bucle que de manera individual.
Título: Re: Complicando para simplificar
Publicado por: Gonzalo_BlackHawk en 24 de Mayo de 2008, 09:18:11
Si Nocturno, menos mal que estas atento a mis errores, eso me pasa por escribir cansado, no se en lo que estaba pensando  :(. Anduve probando con una matriz de 32 x 128 y se puede reducir el tiempo de ejecucion del borrado hasta un cierto punto, luego comienza a subir nuevamente. Fijense, aqui coloca a uno todo los elementos de una matriz 32 x 128 utilizando dos bucles anidados:

(http://s1.subirimagenes.com/fondosycapturas/514941sin-optimizacin.jpg)

Tenemos un tiempo de 76 ms aprox. Ahora elimino el primer bucle y cambio manualmente el primer indice de la matriz, quedandome:

(http://s1.subirimagenes.com/fondosycapturas/514953optimizacin-parcial.jpg)

Me he ahorrado unos 16 ms aprox. Ahora bien, en vez de reemplazar el bucle de 32 elementos, voy a eliminar el bucle de 128 elementos y a dejar el anterior como estaba, haciendo que el segundo indice de la matriz cambie individualmente. Lo que obtengo es:

(http://s1.subirimagenes.com/fondosycapturas/514961optimizacin-parcial.jpg)

Fijense como el tiempo sube nuevamente a los 76 ms. No hay que ser adivino para imaginarse que cuando tratemos de eliminar ambos bucles y asignar valores individualmente a cada uno de los 4096 elementos de la matriz el tiempo de ejecucion se nos ira por las nubes. Sin lugar a duda Nocturno tenia razon, existe un punto de inflexion a la hora de optimizar una asignacion de valores a elementos de matrices de gran tamaño.  Me disculpo nuevamente por el error infligido.

A modo de comentario, otra forma de optimizar un poco el código es tratar de utilizar siempre el fast_io y de reemplazar cocientes o multiplicaciones con potencias de 2 por desplazamiento de bits, entre otros. He visto gente que hilando fino empieza a reemplazar las funciones built-in de CCS por algunas mas elaboradas pero mas rapidas (por ejemplo sprintf, que segun he visto no es para nada eficiente) pero a mi gusto ya el código deja de ser legible, pero bueno, cada programador tiene sus necesidades y gustos.

Un saludo a todos.

Título: Re: Complicando para simplificar
Publicado por: Nocturno en 24 de Mayo de 2008, 12:33:21
Magnífico análisis el que has hecho, Gonzalo. Nada de pedir disculpas, todo lo contrario, eso nos fuerza a pensar y nos enriquece más.

Habría otra forma de inicializar ese bucle de forma más rápida aún, si no me equivoco: mediante punteros.

Obtenemos el puntero al primer elemento del array y hacemos un bucle que lo vaya incrementando hasta el 4096 (32x128), ya que los elementos del array estarán situados de manera contigua en la RAM.
Título: Re: Complicando para simplificar
Publicado por: RICHI777 en 24 de Mayo de 2008, 15:12:53
Hola, porque no usar un memset de esta manera:
memset( Matriz, 0, sizeof( Matriz ));

Pondra en este caso en 0 todo el array y el compilador calculara exactamente el tamaño de la misma.
Saludos
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 24 de Mayo de 2008, 15:58:21
...Habría otra forma de inicializar ese bucle de forma más rápida aún, si no me equivoco: mediante punteros.
Obtenemos el puntero al primer elemento del array y hacemos un bucle que lo vaya incrementando hasta el 4096 (32x128), ya que los elementos del array estarán situados de manera contigua en la RAM.


con el direccionamiento indirecto se hace mas rápido aún.

Título: Re: Complicando para simplificar
Publicado por: Nocturno en 24 de Mayo de 2008, 16:03:44
Buen punto el del memset, Richi.

No he entendido tu sugerencia, Pedro.
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 24 de Mayo de 2008, 16:12:03
por el hecho de que los arrays son contiguos, con solo conocer la dirección del primer dato de la ram puedes recorrer el arreglo usando los registros virtuales INDF ó PRE/POSTINC(n)

hasta ahora he concluido que dichos registros son una forma de puntero por hardware, caso contrario, los que hemos conocido siempre al declararlos en c
Título: Re: Complicando para simplificar
Publicado por: Gonzalo_BlackHawk en 24 de Mayo de 2008, 18:02:06
Hola chicos, anduve probando las opciones que han expuesto y he obtenido resultados interesantes. Le uso de la instrucción memset tal como lo ha expresado RICHI77/ me ha dejado asombrado, ha podido colocar a uno todos los elementos de una matriz de 32 x 128 en un poco mas de medio milisegundo (Recuerden que con 2 bucles anidados o bien asignacion de valor en forma individual la demora era de entre 70 a 76 ms!!!!!!). Aqui dejo una foto para que vean tanto el código como el stopwatch:

(http://s1.subirimagenes.com/fondosycapturas/517009optimizacion-3.jpg)

Como mi matriz es de bits y no de bytes, hay que tener cuidado en definir el valor de la instruccion memset pues esta siempre completa bytes, estoy hay que contemplarlo con cualquier tipo de datos que no sea int.

Luego he probado con punteros tal como ha indicado Nocturno, el resultado tambien es extraordinario, el código se ejecuta en unos pocos milisegundos tal como se ve en la siguiente imagen. Aqui tambien hay que tener en cuenta el tipo de matriz que es, el tamaño de los punteros (en los 18F son de 2 bytes), pero con una programación flexible puede lograrse y con grandes beneficios como hemos podido ver.

(http://s1.subirimagenes.com/fondosycapturas/517294optimizacion-4.jpg)

Quedaria probar lo que ha dicho Pedro, pero la verdad que no entiendo a que se refiere, podrias explicarnos como deberiamos hacerlo Palitroquez??? yo siempre pense que el direccionamiento indirecto es el que se realiza con punteros, como el metodo que postee en este mensaje, tal vez alguien me saque de la confusión.

Un saludo a todos.

Título: Re: Complicando para simplificar
Publicado por: RICHI777 en 24 de Mayo de 2008, 19:37:11
Hola, me alegro mucho de los resultados y tambien felicitaciones por la forma de trabajo, por tu profresionalismo y la forma que expones las pruebas. Con respecto a la mejora puedo detallar, en forma general porque no conozco la arquitectura MicroChip.
Inicializando con Arrays
El compilador en este caso debe efectuar una multiplicación para acceder a cada miembro del array, y si el procesador no la tiene como instrucción nativa debe suplirla con alguna funciíon intrinsica o propia del mismo, por eso esta es la solución mas lenta.

Trabjando con punteros como indico Nocturno
En este caso se define un puntero al comienzo del array, y luego se incrementa el mismo por el sizeof de cada elemento, en este caso la navegacion por cada elemento se hace con aritmetica de punteros que al compilador solo le cuesta una suma ( sizeof de cada elemento )

Memset 
El memset normalmente es implementado directamente en assembler ya que es parte de la libreria RTL ( Real Time library ) entonces el fabricante del compilador deberia aprovechar lo maximo de la arquitectura.

Seria bueno exponer el codigo assembler generado por cada de las opciones para ver los resultados.

Saludos !
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 27 de Mayo de 2008, 16:08:43
Hola.

He pensado mucho en lo escribiré jaja porque cada vez que analizaba el asm generado por el ccs, me cambiaba la perspectiva. En fin en vez de montar un discurso, mejor resumo el análisis:

en base a los 2 ejemplos montados por Gonzalo:

1) con punteros:

Código: C
  1. #include <18F2525.h>
  2. #fuses HS
  3. #use  Delay(clock=20M)
  4.  
  5. short Matriz[32][128];
  6.  
  7. void Main()
  8. {
  9. long *P;
  10. long A;
  11. int16 espacio;
  12.  
  13. P=Matriz;
  14.  
  15. espacio=sizeof(Matriz);
  16.  
  17. for(A=0;A<=espacio;A++){
  18.  *P=0xFFFF;
  19.   P++;
  20. }
  21. delay_cycles(1);
  22. }

no entiendo porque puntero es long ¿? Gonzalo el tamaño del puntero es independiente del tipo de datos que manejes.

en este caso vamos a rellenar bytes con 0xff, el código iría así:

Código: C
  1. #include <18F2525.h>
  2. #fuses HS
  3. #use  Delay(clock=20M)
  4.  
  5. short Matriz[32][128];
  6.  
  7. void Main()
  8. {
  9. int *P;
  10. long A;
  11. int16 espacio;
  12.  
  13. P=Matriz;
  14.  
  15. espacio=sizeof(Matriz);
  16.  
  17. for(A=0;A<=espacio;A++){
  18. *P=0xFF;
  19.   P++;
  20. }
  21. delay_cycles(1);
  22. }

el tiempo: 1,95ms sigue alto. ¿porque? bueno es por el overhead o como lo llamo yo, el factor de multiplicación, que se monta en asm, el contador A se comprueba mediante restas, lo cuál aumenta el tiempo de cálculo y se ve reflejado al final del bucle.




2) con memset

Código: C
  1. #include <18F2525.h>
  2. #fuses HS
  3. #use  Delay(clock=20M)
  4.  
  5. short Matriz[32][128];
  6.  
  7. void Main()
  8. {
  9. int16 espacio;
  10. espacio=sizeof(Matriz);
  11. memset(Matriz,0xFF,espacio);
  12. delay_cycles(1);
  13. }

Digamos que para este ejemplo, el compilador optimiza al máximo en asm con memset, la instrucción con menos factor de multiplicación es decfsz.

En ambos casos, el compilador usa Direccionamiento indirecto, el asunto es que en algunos casos puede no optimizar del todo.


Este estudio me llevó a una conclusión: mientras menos variables usemos para hacer calculos en un bucle, menos tiempo se llevará. porque el factor de multiplicación será menor, (y además que liberas preciada RAM)

pd: a lo que yo llamo factor de multiplicación es la misma operación de cálculo que tiene que hacer el pic en cada pasada del bucle.

Título: Re: Complicando para simplificar
Publicado por: Nocturno en 28 de Mayo de 2008, 00:17:44
Yo no entiendo eso del factor de multiplicación, ¿podrías explicar qué es?
Título: Re: Complicando para simplificar
Publicado por: Gonzalo_BlackHawk en 28 de Mayo de 2008, 00:21:17
Hola Palitroquez. Un gusto como siempre encontrar opiniones contigo.

Citar
no entiendo porque puntero es long ¿? Gonzalo el tamaño del puntero es independiente del tipo de datos que manejes.

Obviamente que es asi, estuve investigando bastante y al parecer tenia equivocado mis conceptos acerca de como CCS maneja los punteros. Paso a contar mi experiencia. Anteriormente y tal como se ve en el programa yo tomo el puntero como un tipo de datos de 2 bytes simplemente porque en el 18F2525 los registros se identifican con una dirección de 12 bits (desde el registro 0x000 hasta el 0xFFF) y con una variable int me quedaba corto.

Lo que no me cerraba era que cuando incrementaba el puntero  (y por lo tanto la dirección) saltaba dos registros por vez, pareceria ser que cada dirección en la memoria de datos contiene 2 bytes, pero estuve leyendo el datasheet medio rapidito y descarte esa hipotesis. Como no encontraba explicación como pueden darse cuenta en el programa, lo que hago es completar con '1' dos bytes consecutivos con cada pasada del bucle, por eso es que hago a *P = 0xFFFF; y asi coloco un parche a la situación. Como emparchar las cosas no es lo que mas me gusta hacer segui investigando.

Lo que yo pensaba (en forma equivocada) que cuando uno declara un puntero el tipo de datos que le asigna al mismo no esta realmente indicando el rango de direcciones a las que puede apuntar (Como uno puede llegar a suponer, me he fijado en el mapa de la memoria y P siempre se define en 2 bytes, sin importar el tipo de dato que le coloquemos) sino que indica el tamaño del segmento de memoria a la que señala el puntero. Definiendolo con un tipo de datos int el puntero cubre un solo registro que es la forma convencional de direccional la memoria, defiendolo en cambio con un tipo de datos long el puntero apunta de a dos registros, lo cual nos permitiria facilitar ciertas tareas como por ejemplo direccionar matrices con elementos de 16 bits de una manera muy sencilla. Puede extrapolarse este pensamiento al tipo de datos int32 y float, me he tomado el trabajo de probarlos. En CCS los punteros a bits no estan permitidos por lo tanto asignar un tipo de datos short a un puntero dara como resultado el correspondiente error al tratar de compilar el programa. Obviamente esto es un artilugio que realiza CCS para un direccionamiento indirecto mas amplio de la memoria, como muchas cosas la ayuda de CCS no indica nada sobre esto.

Otra cosita, aqui hay un error:

Código: [Seleccionar]
for(A=0;A<= Espacio;A++){
deberia colocarse:

Código: [Seleccionar]
for(A=0;A<Espacio;A++){
Si el tamaño de la matriz es de 4096 elementos, o sea 512 bytes, en el primer caso el bucle completará un byte de más porque A incrementará desde 0 a 512, o sea 513 veces. Por lo tanto el segundo bucle es el correcto.

Saludos a todos.
Título: Re: Complicando para simplificar
Publicado por: RICHI777 en 28 de Mayo de 2008, 10:19:48
Muy buena la investigacion !!!, medio que no entendi nada, yo por suerte trabajo con micros lineales y mas ortogonales, y este tipo de cosas no me pasan.
Saludos !
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 28 de Mayo de 2008, 16:15:32
Manolo:

a lo que yo llamo factor de multiplicación es lo que se usa en asm para hacer retardos ciclicos por software.

un ejemplo bien explicado lo tienes en http://micropic.wordpress.com/2007/02/09/retardos-por-software/

(http://micropic.files.wordpress.com/2007/02/ret11.png)

tomando en cuenta la primera rutina, tenemos que la línea goto CICLO tiene un factor de multiplicación de 2,porque tomará 2 ciclos de reloj por cada decremento de CONT.

Si continuas viendo los ejemplos posteriores, verás que a medida que se agregan registros anidados, ese factor aumenta y de allí se puede calcular con presición el tiempo consumido.

en el ejemplo anterior se usa a favor, en lo que refiere a este hilo está en contra y es perjudicial para nosotros. Por ello tratamos de cambiar las lineas que escribimos en c, para ver como lo traduce el compilador.

bueno, mas o menos es la relación que hago respecto al listado de los ejemplos que puso Gonzalo.

Lo que si tengo claro es que al manejar punteros o memset, el compilador usará direccionamiento indirecto, ahora bien, lo que uno tiene que analizar es como el compilador le hace las preguntas a INDF,POSTINCx,FSRx y para ello memset demostró ser el que lo hacía en menor tiempo.



Gonzalo:
Ante todo, cualquier ejemplo es válido siempre que cumpla su cometido, como en ccs no se puede manejar punteros a nivel de bits (al menos no se como y no he averiguado), entonces una forma corta que ví, fué trabajando por bytes. Una Matriz[32][128] -> 32x128=4096bits / 8bits = 512Bytes contiguos. Es mas rapido trabajar con int8 que con int16 (*)

*Con un pic con registros de 16bits, otro gallo cantaría

Título: Re: Complicando para simplificar
Publicado por: migsantiago en 28 de Mayo de 2008, 17:40:03

Gonzalo:
Ante todo, cualquier ejemplo es válido siempre que cumpla su cometido, como en ccs no se puede manejar punteros a nivel de bits (al menos no se como y no he averiguado), entonces una forma corta que ví, fué trabajando por bytes. Una Matriz[32][128] -> 32x128=4096bits / 8bits = 512Bytes contiguos. Es mas rapido trabajar con int8 que con int16 (*)

*Con un pic con registros de 16bits, otro gallo cantaría



Pali, hace más de un año platicamos aquí sobre como lograr apuntar variables de 1 bit...

Alternativa a arreglos de 1 bit
http://www.todopic.com.ar/foros/index.php?topic=15810.msg101438#msg101438

Tú estabas ahí,  :D
Título: Re: Complicando para simplificar
Publicado por: Gonzalo_BlackHawk en 29 de Mayo de 2008, 01:03:54
Hola a todos.

Es mas rapido trabajar con int8 que con int16 (*)

Difiero contigo Pedro, en este caso trabajar con int16 para el llenado de la matriz es más rapido que utilizando int8. Y aun mejor, trabajar con int32 es todavia más rápido y dado que ocupamos la misma cantidad de memoria en los 3 casos, un 13 % del 18F2525 para ser más exactos, una mayor demanda de RAM no es un factor limitante para no trabajar apuntando a 2 registros o 4 (para el caso de int32) al mismo tiempo.
Obviamente, antes de tirar semejante refutación (y mas ha alguien con tu reputación Pedro) y no quedar en verguenza me he tomado el trabajo de comprobar que mi comentario realmente es válido. A continuación presento como de costumbre las ventanas de mplab que exponen tanto el código como el tiempo que demoro en ejecutarse el llenado de la matriz de 4096 elementos con punteros apuntando a 1, 2 y 4 registros a la vez, en ese orden.

(http://s1.subirimagenes.com/fondosycapturas/539337puntero-8-bits.jpg)

Este es el caso expuesto por Palitroquez y como ya sabemos da casi 2 milisegundos. Ahora veamos cuando llenamos de a dos registros simultaneamente:

(http://s1.subirimagenes.com/fondosycapturas/539342puntero-16-bits.jpg)

Vemos que el tiempo que demora en ejecutar todo es un poco mas de un milisegundo, fijense que la variable [A] ya no se incrementa 512 veces sino 256, por eso divido por dos el tamaño de la matriz. Veamos si utilizo un llenado de 4 registros simultaneamente:

(http://s1.subirimagenes.com/fondosycapturas/539349puntero-32-bits.jpg)

Observen que el tiempo que tarda en llenar la matriz es de tan solo 647 microsegundos!!!!!. Es casi tan bajo como el tiempo obtenido por memset. Aqui tal como pueden deducir, el bucle de llenado solo se realiza 128 veces.

De estos tres casos se pueden sacar conclusiones interesantes. Primero, y tal como lo ha dicho Palitroquez, implementar un bucle origina demoras y cuanto mas ciclos debe realizar el bucle mas tarda en ejecutarse obviamente. Por eso cuantos mas registros llenamos a la vez menos cantidad de veces tenemos que realizar el bucle y por lo tanto menos tiempo demoramos.

Ahora bien, no es tan sencilla la cuestión, pues aunque para la matriz del ejemplo trabajar con un puntero en int8, int 16 o int32 nos supone solo un cambio de definicion del tipo de datos, no todas las matrices con las que trabajemos tendran un tamaño tan "adecuado" por decirlo de algun modo (Una matriz de 512 bytes es una ganga pues es multiplo de 1, 2 y 4 bytes) y por lo tanto si intentamos trabajamos con int32 en algunos casos nos encontraremos que nos faltan completar registros o bien que nos pasamos de dirección. Lo mismo puede ocurrir con int16 y una matriz, por ejemplo, que ocupa un numero de registros impares. La aplicación de estos metodos dependen mucho del tipo de dato que contiene la matriz y del tamaño de la misma. Por lo tanto yo creo que aqui el metodo con memset se lleva todos los premios y que los otros metodos son aplicables cuando el tiempo no es un factor crítico o bien vienen a titulo informativo.

Ahora me voy a dormir, veo punteros por todos lados. :D

Saludos desde Argentina.
Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 02 de Junio de 2008, 16:27:41
Ciertamente Gonzalo, Te doy la razón. Cambiando el tipo de datos a 16-32bits, aumenta la velocidad.

Cuando mencioné:

Citar
Es mas rapido trabajar con int8 que con int16 (*)

me basaba en la hecho de que, si tenemos un dato > 1 byte y trabajando con un pic cuyo bus de datos es de 8 bits, entonces el contador de programas tiene que hacer 2 operaciones en cada dato para completar su procesamiento (por ej: un long, sería 2 operaciones de 1 byte, un int32 serian 4 operaciones).

Obviamente el compilador de manera inteligente, juega con los registros de 8 bits para tardar menos en cada bucle. También cuenta otro hecho de que dado este ejemplo donde se puede tratar la matriz con los 3 tipos de datos e igual funciona y a medida que el tipo de dato es mayor, el número de iteraciones es mucho menor (con 32 bits son 128 repeticiones en comparación con int8 que son 512 veces)

Citar
...y mas ha alguien con tu reputación Pedro y no quedar en verguenza me he tomado el trabajo de comprobar que mi comentario realmente es válido.

jaja ¿cuál reputación?  :D, para nada. Si tu tienes un argumento válido; perfecto, entonces estas en el derecho de corregirme a mi o a cualquiera que tenga una idea/duda. De esto se trata los foros, de aclarar o corregir ideas.

Realmente "estaba" seguro que cambiando de int8 a int16 iba a tardar mas, es mas, imprimí los 3 programas que simulaste, y los asm generados son similares,



Mig, no me acordaba ese hilo  :8}


Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 08 de Octubre de 2008, 15:20:21
Para el que no lo sepa:

Cuando se quiere leer un pin de un puerto, se usa input(PIN_puerto)

bien, deben saber que existe otro BUILT-IN: input_state(PIN_puerto), éste puede llegar a ser mas conveniente porque consume menos lineas en asm. La Razón: la dice la ayuda del ccs, con input_state NO se cambia el TRIS

Código: [Seleccionar]
....................    delay_cycles(1);
003A:  NOP
....................    a=input_state(PIN_B0);
003B:  CLRF   3B       
003C:  BTFSC  06.0     
003D:  INCF   3B,F
....................    delay_cycles(1);
003E:  NOP
....................    a=input(PIN_B0);
003F:  BSF    03.5
0040:  BSF    06.0
0041:  BCF    03.5
0042:  CLRF   3B
0043:  BTFSC  06.0
0044:  INCF   3B,F
....................    delay_cycles(1);
0045:  NOP

Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 09:14:17
Estaba optimizando un programa en CCS para que quepa en un PIC 16F727 porque ya anda a tope, y para mi sorpresa, un array de bytes ocupa menos si lo dimensiono a 16 que si lo dimensiono a 12.

Esto ocupa menos
Código: C
  1. unsigned int8 Parametros[16];

que esto:
Código: C
  1. unsigned int8 Parametros[12];
Título: Re: Complicando para simplificar
Publicado por: RICHI777 en 31 de Marzo de 2010, 10:46:34
Manolo deja de lado el ron !!!!

Saludos !
Título: Re: Complicando para simplificar
Publicado por: migsantiago en 31 de Marzo de 2010, 11:56:59
Estaba optimizando un programa en CCS para que quepa en un PIC 16F727 porque ya anda a tope, y para mi sorpresa, un array de bytes ocupa menos si lo dimensiono a 16 que si lo dimensiono a 12.

Hola Manolo, por favor danos más detalles para entender porqué pasa eso.  :huh:
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 12:10:28
Lo juro, aún no he llegado al punto de saturación de ron.

En mi programa, en estas dos compilaciones, lo único que cambio es el dimensionamiento de un array de int8 como indiqué antes. Podéis comprobar cómo el consumo de RAM sube 4 bytes en la parte de la derecha, pero a cambio el programa se reduce en 113 bytes (134 bytes si contamos los fragmentos no usados).

(http://img248.imageshack.us/img248/7995/compilandoconarray16y12.jpg)
Título: Re: Complicando para simplificar
Publicado por: migsantiago en 31 de Marzo de 2010, 12:18:51
Vale, te creemos. Pero entonces habría que analizar el código fuente y su volcado ASM.  ;-)
Título: Re: Complicando para simplificar
Publicado por: Suky en 31 de Marzo de 2010, 13:28:06
 :shock: Este CCS y sus cositas!  :?
Título: Re: Complicando para simplificar
Publicado por: BrunoF en 31 de Marzo de 2010, 13:33:53
Yo te creo mano, me ha pasado infinidad de veces eso.

Si estan ante un 18F o superior, siempre pueden poner #OPT 11 para intentar optimizar un poquito mas el codigo.

Por otro lado, cuidado con ese stack worst case, te estas pasando de los 8 niveles maximo para ese PIC en algun caso...Se te va a resetar el micro por overflow del STACK...;)
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 13:39:00
No sé de qué va eso del stack, ¿cómo puedo optimizar mi código para que utilice un nivel menos?, ¿qué tipo de funciones lo llenan?
Título: Re: Complicando para simplificar
Publicado por: MLO__ en 31 de Marzo de 2010, 13:47:26
Hola.

Una preguntica: Como accedo a esa info desde el MPLAB?

(http://img248.imageshack.us/img248/7995/compilandoconarray16y12.jpg)

Saludos
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 13:50:09
En el menú "View" tienes "Memory usage gauge" que te da la misma información, y te pinta un grafiquito.
Título: Re: Complicando para simplificar
Publicado por: MLO__ en 31 de Marzo de 2010, 13:52:57
Seee

Pero es que quería esa info mas detallada ... como la tuya ...  :P Eso esta compilado desde el IDE del CCS cierto?

Saludos
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 13:53:18
Yes, my friend
Título: Re: Complicando para simplificar
Publicado por: BrunoF en 31 de Marzo de 2010, 14:08:24
No sé de qué va eso del stack, ¿cómo puedo optimizar mi código para que utilice un nivel menos?, ¿qué tipo de funciones lo llenan?

El STACK es la pila. Cada vez que se ejecuta una instruccion CALL o se ingresa al ISR(vector de interrupcion) por haber sucedido una interrupción, se carga la PILA en 1 nivel. Las instrucciones RETURN y RETFIE son las instrucciones que la descarga.

El STACK es el lugar donde se almacenan las posiciones de memoria de codigo que le permiten al PIC saber adónde debe volver cuando se ha finalizado de ejecutar una sub-rutina(una "función").

En CCS es algo más complejo responder a la pregunta. Esto es debido a que principalmente, el CCS elige por defecto si una funcion debe ser llamada como subrutina, o ser incluida como MACRO.

Un caso práctico lo ilustra mejor:

Código: C#
  1. void parpadea(void)
  2. {
  3.     output_high(LED);  
  4.     delay_ms(500);
  5.     output_low(LED);  
  6.     delay_ms(500);    
  7. }

Si ahora en mi main yo hago, por ejemplo:

Código: C#
  1. void main(void)
  2. {
  3.     //...inicializacion omitida...
  4.     while(1)
  5.     {
  6.        parpadea();
  7.     }
  8. }

Es altamente probable, que el CCS traduzca lo anterior a:

Código: C#
  1. void main(void)
  2. {
  3.     //...inicializacion omitida...
  4.     while(1)
  5.     {
  6.         output_high(LED);  
  7.         delay_ms(500);
  8.         output_low(LED);  
  9.         delay_ms(500);    
  10.     }
  11. }

eliminando en realidad a la subrutina, y de esa manera, ahorrandose el nivel de STACK( por no tener que hacer el CALL y llamarla).

Ahora, si mi main fuese asi:

Código: C#
  1. void main(void)
  2. {
  3.     //...inicializacion omitida...
  4.     while(1)
  5.     {
  6.         parpadea();
  7.         //...
  8.         parpadea();
  9.         //...
  10.         parpadea();
  11.         //...
  12.     }
  13. }

Ya el CCS detecta que llamas a la funcion 3 veces, por lo que reemplazar su contenido directamente puede afectar duramente a la ROM que ocupe el codigo, por lo que en ese caso lo que probablemente hara es utilizar a parpadea() como funcion, consumiendo el nivel de STACK pero ahorrando ROM.

Este comportamiento puede cambiarse. Podés forzar a que el compilador, por ejemplo, utilice a parpadea() como MACRO, no importa la cantidad de veces que sea llamada(obviamente pagando las  consecuencias en ROM) agregando el modificador INLINE.

Ejemplo:

Código: C#
  1. inline void parpadea(void)
  2. {
  3.     output_high(LED);  
  4.     delay_ms(500);
  5.     output_low(LED);  
  6.     delay_ms(500);    
  7. }
  8.  
  9. void main(void)
  10. {
  11.     //...inicializacion omitida...
  12.     while(1)
  13.     {
  14.         parpadea();
  15.         //...
  16.         parpadea();
  17.         //...
  18.         parpadea();
  19.         //...
  20.     }
  21. }

Deberia obligar al compilador a que en realidad, reemplace internamente a la hora de compilar lo anterior por:

Código: C#
  1. void main(void)
  2. {
  3.     //...inicializacion omitida...
  4.     while(1)
  5.     {
  6.         output_high(LED);  
  7.         delay_ms(500);
  8.         output_low(LED);  
  9.         delay_ms(500);    
  10.         //...
  11.         output_high(LED);  
  12.         delay_ms(500);
  13.         output_low(LED);  
  14.         delay_ms(500);    
  15.         //...
  16.         output_high(LED);  
  17.         delay_ms(500);
  18.         output_low(LED);  
  19.         delay_ms(500);    
  20.         //...
  21.     }
  22. }

Si bien la eleccion que hace el CCS automaticamente no es tan sencilla seguramente como sólo considerar la cantidad de veces que se llama a la subrutina(también es relevante cuántas líneas ASM ocupa, el tiempo que debe tardar en ejecutarse,etc) es una buena primera aproximación para intentar explicarlo.

Por defecto, considerá que cada vez que llamás a una función el STACK se incrementa en un lugar. Obviamente cuando se retorna de la subrutina se libera esa posición. Entonces el problema surge cuando anidás muchas llamandas a subrutinas. Las interrupciones ocupan se comportan como una funcion más. Ocupan 1 lugar al ingresar y lo liberan al finalizar.

Reducí la cantidad de subrutinas anidadas para bajar el nivel máximo de STACK. Por otro lado, el CCS no es tan inteligente, sólo analiza el peor caso considerando los anidamientos presentes en tu código, pero no puede predecir si el flujo de tu código efectivamente puede llegar a ejecutar todos los niveles del peor caso por lo que puede estar advirtiendo de un peor caso que técnicamente jamás puede ocurrir en tu flujo de ejecución.

Saludos.


Título: Re: Complicando para simplificar
Publicado por: MLO__ en 31 de Marzo de 2010, 14:11:30
 :shock:

Muy buena info maestro!!!!!

Es decir que es mejor usar funciones que retornen datos (asi no los retornen) para asegurar la descarga del STACK?

Saludos
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 14:20:24
Magnífico Don Bruno, lo tendré en cuenta.

Me parece que mi programa no llega ni a 4 niveles de pila, por lo que imagino que CCS ha supuesto un caso que no podrá darse.
En cualquier caso lo revisaré.

Gracias
Título: Re: Complicando para simplificar
Publicado por: BrunoF en 31 de Marzo de 2010, 14:26:07
Hola MLO.

No. Es lo mísmo. Toda porción de código puede escribirse o bien como subrutina("función") o bien como MACRO. La diferencia es que en el primer caso, se ahorra ROM mediante la reutilización de código, pero se ocupa temporalmente 1 nivel de PILA al ejecutarse. La segunda no ocupa nivel de PILA, pero ocupa ROM cada vez que se la llama.

Lo mejor es no anidar muchas funciones unas dentro de otras, porque ahi es cuando sucede el problema. Ni hablar cuando hay interrupciones presentes.Estas consumen 1 nivel de STACK, y cualquier llamada a subrutina que hagamos dentro de ellas seguiran incrementando aun más la cantidad de PILA necesaria.

Para imaginarlo más prácticamente. "La PILA es una memoria limitada que permite al PIC saber cómo volver a casa".
Imaginen que son viajantes y parten siempre desde su casa. Pueden recorrer la ciudad donde se encuentran actualmente sin mayores problemas de memoria, una calle por vez, pero si por casualidad son llamados a otra ciudad inmediatamente, deben recordar desde donde retomar el recorrido en la ciudad en la que estaban. Una vez terminado el recorrido por una ciudad, si quedaba algo de una ciudad previa por recorrer, utilizan esa memoria para saber desde donde retomar el recorrido. Bueno, ahora sólo pueden recordar 8 posiciones(en los 16F que es el caso involucrado) de ciudades previas. Si se exceden, Alzheimer se apodera y los problemas aparecen porque no hay más lugar para almacenar otra posición.


Título: Re: Complicando para simplificar
Publicado por: Suky en 31 de Marzo de 2010, 14:27:27
No sé de qué va eso del stack, ¿cómo puedo optimizar mi código para que utilice un nivel menos?, ¿qué tipo de funciones lo llenan?

 :z) Así me dejaste y me corrió un chucho por la espalda!  :D :D

Muy bien explicado Bruno!  :-)

Es decir que es mejor usar funciones que retornen datos (asi no los retornen) para asegurar la descarga del STACK?

Hay que colocar la directiva INLINE para que reemplace el código y no la tome como función.

Saludos!


Edit: Bueno, lo explico bien detalladito el maestro Bruno  :mrgreen:
Título: Re: Complicando para simplificar
Publicado por: BrunoF en 31 de Marzo de 2010, 14:29:52
Magnífico Don Bruno, lo tendré en cuenta.

Me parece que mi programa no llega ni a 4 niveles de pila, por lo que imagino que CCS ha supuesto un caso que no podrá darse.
En cualquier caso lo revisaré.

Gracias

Fijate si no sucede lo que comento en rojo en el post anterior.

Si bien decís que no hay más de 4 funciones anidadas, si JUSTO sucede una interrupción en el peor caso(cuando el PIC tiene 4 niveles de STACK ocupados por tus funciones anidadas) la interrupción mísma ya te ocupa un 5to lugar. Si ahora encima hacés llamadas a subrutinas dentro de la interrupción, seguís elevando los niveles de STACK. Te hacen falta tener 4 funciones mas anidadas dentro de la interr. para reventar la STACK.

Y ojo, que hay funciones que por mas que vengan con el CCS consumen posiciones de PILA seguramente, como un printf();

Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 14:30:23

 :z) Así me dejaste y me corrió un chucho por la espalda!  :D :D


Es que los enfermos del ASM tenéis unas costumbres muy raras: ¡Una pila para recordar el camino de vuelta!, con lo fácil que es tirar de GPS, hombre.
Título: Re: Complicando para simplificar
Publicado por: BrunoF en 31 de Marzo de 2010, 14:40:05
Mano, ahora que lo recuerdo. Usá el call Tree para ver cómo están anidadas las funciones en tu programa. Ahí seguro salta el peor caso cómo ocurre y los demás que deban ser corregidos u optimizados.
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 31 de Marzo de 2010, 14:46:24
Magnífica herramienta de depuración. Siempre he visto el botón del Call tree y nunca me había dado por pulsarlo.

He encontrado hasta 7 niveles de profundidad, porque la librería del LCD hace muchas llamadas, así que no me extraña que en alguna parte se consuman los 9 niveles que indica la compilación, aunque aún no lo encuentro.

Sigo buscando.
Título: Re: Complicando para simplificar
Publicado por: Suky en 31 de Marzo de 2010, 14:50:20

 :z) Así me dejaste y me corrió un chucho por la espalda!  :D :D


Es que los enfermos del ASM tenéis unas costumbres muy raras: ¡Una pila para recordar el camino de vuelta!, con lo fácil que es tirar de GPS, hombre.

Jejeje! En los 16F preocúpate de forma sería que tienen 8 niveles, en los 18F es de 32, y en los PIC24 es por software  :P
Título: Re: Complicando para simplificar
Publicado por: MLO__ en 31 de Marzo de 2010, 14:59:38
Excelente info.

La función sprintf también consume PILA

Mejor voy a cambiar a una de 9V cuadrada .. y que sea alcalina para que aguante mas!!!

Título: Re: Complicando para simplificar
Publicado por: PalitroqueZ en 31 de Marzo de 2010, 16:23:46
umm pero yo tengo una duda, cuando dice stack used ¿es la pila por hardware o la que genera por software el ccs?

Título: Re: Complicando para simplificar
Publicado por: MGLSOFT en 31 de Marzo de 2010, 23:28:08
Magnífica herramienta de depuración. Siempre he visto el botón del Call tree y nunca me había dado por pulsarlo.

He encontrado hasta 7 niveles de profundidad, porque la librería del LCD hace muchas llamadas, así que no me extraña que en alguna parte se consuman los 9 niveles que indica la compilación, aunque aún no lo encuentro.

Sigo buscando.

Si usas el Captouch seguramente estas ocupando 2 posiciones mas de la pila...

Una forma de evitar ese problema seria usar dos pics encimados, asi la pila seria mas alta.. :D :D :D
Título: Re: Complicando para simplificar
Publicado por: Nocturno en 01 de Abril de 2010, 01:43:21
Pues sí que lo uso...
Título: Re: Complicando para simplificar
Publicado por: MGLSOFT en 01 de Abril de 2010, 09:00:07
Como lo de apilar PICs fue solo un chiste, salvo que lo hayas probado y que funciones.. :mrgreen: :mrgreen:

Deberias optar por:

Podrias poner un trazador en el software a ver si en algun momento se supera el nivel de pila (stack)... Eso te ayudaria a depurarlo.
Título: Re: Complicando para simplificar
Publicado por: Cryn en 01 de Abril de 2010, 10:48:06
Jejeje! En los 16F preocúpate de forma sería que tienen 8 niveles, en los 18F es de 32, y en los PIC24 es por software  :P
El 18f4550 tiene solo 24 niveles, pero ya es mucho más que un 16.

Al menos eso me decía el compilador