2010-11-04 16 views
6

El tamaño de pila limitado de PIC de presupuesto es un área problemática y he ajustado mi código para adaptarlo a esta realidad. Actualmente, adopto un paradigma aproximado de agrupar funciones estrechamente relacionadas en un módulo y declarar todas las variables globalmente estáticas en el módulo (para reducir la cantidad de variables almacenadas en el auto psect, y los problemas de mutabilidad solo son relevantes en los ISR, que explico .) No hago esto porque es una buena práctica, pero la realidad es que tienes una cantidad finita de espacio para asignar todas las variables de función locales que existen en un proyecto completo. En el mundo integrado de chips de 8/16 bits, ¿es este un método apropiado, con la condición de que estoy seguro de tomar las precauciones necesarias? También hago cosas como asignar 256 bytes de RAM para Ethernet (sé que debería ser 1500 como MTU estándar, pero tenemos una situación personalizada y memoria RAM muy limitada) y tengo que acceder a esa memoria a través de punteros para poder evitar la semántica de la memoria bancaria. ¿Lo estoy haciendo mal? Mi aplicación funciona, pero estoy 100% abierto a sugerencias de mejora. [c]¿Mejores prácticas para la gestión de pila/memoria PIC18?

Respuesta

3

Sé que esto se le preguntó hace 4 años pero todavía no se ha respondido correctamente. Creo que lo que el OP está preguntando es su enfoque para evitar una limitación del compilador HiTech PICC18 C válido y/o la mejor práctica. Como se menciona en un comentario posterior, la limitación (una bastante mala y poco publicitada por Hitech) es "el compilador Hi-Tech solo permite 256 bytes de variables automáticas". En realidad, la limitación es peor que eso, ya que es un total de 256 bytes para variables y parámetros locales. La advertencia del enlazador cuando se excede esto también es bastante críptica. Siempre que las funciones estén en diferentes ramas del árbol de llamadas, entonces el compilador puede solapar las variables para reutilizar el espacio. Esto significa que puede tener efectivamente más de 256 bytes. Pero tenga en cuenta que el controlador de interrupción (o controladores si utiliza el esquema de prioridad) tiene su propio árbol de llamadas que comparte el bloque local/param de 256 bytes.

Locales Las dos soluciones para reducir el espacio requerido para los locales son: hacer que los locales sean globales o hacerlos estáticos. Hacerlas estáticas mantiene el alcance de la misma manera y siempre que la función no sea llamada desde interrupciones es seguro (de todos modos, el compilador no permite la interconexión). Esta es probablemente la opción preferida. El inconveniente es que el compilador no puede reutilizar las ubicaciones de esas variables para reducir el consumo general de memoria. Mover las variables al alcance global permite la reutilización, pero la gestión de la reutilización debe ser gestionada por el programador. Probablemente el mejor equilibrio es hacer que las variables simples estén estáticas, pero para hacer que grandes fragmentos de memoria, como los almacenamientos intermedios de cadenas, sean globales y reutilizarlos cuidadosamente.

Tenga cuidado con la inicialización.

foo() 
{ 
int myvar = 5; 
} 

debe cambiar a

foo() 
{ 
static int myvar; 
myvar = 5; 
} 

Parámetros Si vas por ahí pasar grandes cantidades de datos por el árbol de llamadas en los parámetros que se ejecutará rápidamente en la misma limitación de 256 bytes. Su mejor opción aquí puede ser pasar un puntero a una/s estructura/s de "opciones" globalmente asignadas. Alternativamente, puede tener variables de configuración globales que son establecidas por la persona que llama más arriba y leídas por calle abajo del árbol. Realmente depende del diseño del software, qué enfoque es mejor.

He luchado con los mismos problemas que el OP y creo que la mejor opción a largo plazo es alejarse del uso del compilador de Hitech.La decisión de optimización que tomaron los compiladores para asignar todos los locals/params en un bloque solo es realmente apropiada para el PICS de tamaño de ram muy pequeño. Para grandes PICS, se quedará sin local/param lejos antes de llegar al tamaño de ram del dispositivo. Luego debe comenzar a piratear su código para que coincida con el compilador que es perverso.

En resumen ... Sí, su enfoque es válido. Pero considere simplemente hacer locales estáticos si es apropiado, ya que, en general, la reducción del alcance hace que su código sea más seguro.

+0

Un punto a tener en cuenta con la conversión de local a estática de alcance de función es tener cuidado de verificar la inicialización. – Felix

0

Como casi no tiene memoria, debe contar cada byte de RAM. El uso de variables locales (automático) permite reutilizar la memoria donde la necesite (local en la función). Cuando mueve las variables al espacio de direcciones estáticas globales, le da a cada variable un espacio único. Eso es desperdicio de espacio de direcciones.

El compilador de Microchip permite que diferentes variables compartan la misma dirección. No tengo los documentos a mano, pero esto se puede hacer por pragma.

Pero lo que necesita es un análisis de los requisitos de RAM. Cuando vea que la pila no puede contener todas las variables, pero las variables automáticas reducirían el uso de la memoria global, debería considerar aumentar el tamaño de la pila con el código de inicio y el script del enlazador.

+0

Estamos utilizando el compilador Hi-Tech PICC18 Pro. Las diferencias entre él y el Microchip C18 son muchas, pero las más importantes son que el compilador de alta tecnología solo permite hasta 256 bytes de variables automáticas y este compilador no tiene scripts de enlazador que yo pueda editar (que yo sepa). – Nate

+0

OP está hablando de pila/espacio local no RAM en general. – Felix

0

Best Practive es elegir un hardware que se ajuste a los requisitos.

Existen microcontroladores que cuestan solo unos dolares más, pero ahorran cientos o miles de dólares en costos de desarrollo. Si se trata de un desarrollo de hobby, es posible que su esfuerzo no cuente. Pero en el mundo real a menudo puede encontrar hardware que está diseñado solo con vista de los costos de hardware.

Especialmente el PIC18 no es el mejor ejemplo para el código compacto, lo que también puede ser un problema con la memoria flash.

+0

Esta no es la primera vez que escucho este punto. Está bien tomado, haré un caso para usar AVR uCs para proyectos futuros y posiblemente herramientas de desarrollo de IAR. No controlo los fondos y este proyecto ya tiene una cantidad sustancial de firmware escrito para los chips actuales, cambiar los usuarios no es una opción en este momento. – Nate

+0

@harper ¡Las empresas comerciales dirigidas por gerentes no técnicos son exactamente las que empujan a los desarrolladores a utilizar el chip más pequeño posible! – Radu

+0

@Nate Un AVR con limitaciones de RAM sufre los mismos problemas que el PIC. Si bien las preferencias personales de uP están bien (y el AVR son buenas fichas) no es, en última instancia, una respuesta a su pregunta. – boz

1

Mi experiencia con compiladores/enlazadores para chips con memoria limitada es que, siempre que no use funciones recursivas e informe al compilador sobre eso, entonces el compilador es muy capaz de determinar la cantidad mínima de stack-space eso es necesario
Incluso he visto compiladores que dan a cada variable con almacenamiento automático una dirección fija global (sin ninguna pila), donde varias variables se asignan a la superposición de memoria, siempre que sus vidas no se superpongan.

El consejo general al realizar optimizaciones (velocidad o espacio) es: realice mediciones para comprobar que su optimización tiene un efecto positivo.

0

Un poco tarde, pero también debería echar un vistazo más de cerca a la guía de usuario del compilador C18 (si usaba este compilador).

Puede disminuir la pila drásticamente asignando estáticamente variables locales (anulando la palabra clave auto). Aún mejor, puede usar el identificador de almacenamiento superpuesto, que permite ubicar diferentes variables de tiempo de vida no superpuestas en la misma dirección, minimizando la RAM. (El compilador C18 debe operar en modo no extendido).

0

Este sonido migratorio es obvio, pero trate de no utilizar variables de 16 bits en precursores de 8 bits.Las variables de 16 bits son correctas y se necesitan en arquitecturas más grandes, pero en arquitecturas limitadas (8 bits), una aritmética de 16 bits es una manera rápida de agotar las memorias RAM y ROM en muy poco tiempo.

Si intenta incrementar una variable de 16 bits, el compilador incluiría una biblioteca de incremento de 16 bits, que en la mayoría de los casos consume mucho espacio.

Además, intente no dividir o multiplicar, ya que para algunos controladores están implementados por software.

Personalmente, voy siempre para char y cuando necesite una operación dividir, use rotar 'n' veces para dividir por 2 n veces.

Espero que esto ayude!

+1

Abajo, ya que ofrece consejos generales y no aborda la pregunta principal del OP. – Felix

2

Mientras que el compilador C18 usó algunos FSR (punteros) para administrar la pila de datos, parece que el nuevo compilador XC8 de Microchip usa una pila compilada, por lo que debe saber exactamente cuánto espacio ocupa la pila en compilación hora. También sabrá exactamente dónde está almacenada cada variable de pila. Leí todo sobre esto en el XC8 user's guide y suena genial. Esa característica debería hacer que esta pregunta sea discutible, suponiendo que estés usando XC8.