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:
void parpadea(void)
{
output_high(LED);
delay_ms(500);
output_low(LED);
delay_ms(500);
}
Si ahora en mi main yo hago, por ejemplo:
void main(void)
{
//...inicializacion omitida...
while(1)
{
parpadea();
}
}
Es altamente probable, que el CCS traduzca lo anterior a:
void main(void)
{
//...inicializacion omitida...
while(1)
{
output_high(LED);
delay_ms(500);
output_low(LED);
delay_ms(500);
}
}
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:
void main(void)
{
//...inicializacion omitida...
while(1)
{
parpadea();
//...
parpadea();
//...
parpadea();
//...
}
}
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:
inline void parpadea(void)
{
output_high(LED);
delay_ms(500);
output_low(LED);
delay_ms(500);
}
void main(void)
{
//...inicializacion omitida...
while(1)
{
parpadea();
//...
parpadea();
//...
parpadea();
//...
}
}
Deberia obligar al compilador a que en realidad, reemplace internamente a la hora de compilar lo anterior por:
void main(void)
{
//...inicializacion omitida...
while(1)
{
output_high(LED);
delay_ms(500);
output_low(LED);
delay_ms(500);
//...
output_high(LED);
delay_ms(500);
output_low(LED);
delay_ms(500);
//...
output_high(LED);
delay_ms(500);
output_low(LED);
delay_ms(500);
//...
}
}
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.