El tamaño de pila limitado de los PIC de presupuesto es un área problemática y he ajustado mi código para adaptarse a esta realidad. Actualmente adopto un paradigma aproximado de agrupar funciones estrechamente relacionadas en un módulo y declarar todas las variables estáticas globales en el módulo (para reducir la cantidad de variables almacenadas en el segmento automático, y los problemas de mutabilidad solo son relevantes en ISR, que considero .) No hago esto porque sea una buena práctica, pero la realidad es que tiene una cantidad finita de espacio para asignar todas las variables de funciones locales que existen en un proyecto completo.
En el mundo integrado de chips de 8/16 bits, ¿es este un método apropiado, siempre que esté seguro de tomar las precauciones necesarias? También hago cosas como asignar > 256 bytes de RAM para búferes de Ethernet y tengo que acceder a esa memoria a través de punteros para poder evitar la semántica de la banca de memoria. ¿Lo estoy haciendo mal? Mi aplicación funciona, pero estoy 100% abierto a sugerencias de mejora.
Tal vez me estoy perdiendo algo aquí (los párrafos ayudarían) pero con el compilador C18, las variables locales dentro de una función generalmente se asignan en la pila de software, por lo que no tengo idea de lo que significa lo siguiente:
pero la realidad es que tiene una cantidad finita de espacio para asignar todas las variables de funciones locales que existen en un proyecto completo
Al mover todas sus variables a globales dentro de un módulo, necesita que haya espacio para todas ellas al mismo tiempo.
buffers y tengo que acceder a esa memoria a través de punteros para poder evitar la semántica de la banca de memoria.
Qué compilador estas usando?
Se utilizan dos enfoques para la asignación de variables en los compiladores PIC. Algunos usan una pila de software indexada a partir de FSR2, mientras que otros simplemente usan variables superpuestas estáticamente. ambos planteamientos tienen ventajas y desventajas. El uso de variables superpuestas significa que no hay posibilidad de un desbordamiento de pila en tiempo de ejecución. También significa que uno puede tener aproximadamente 64-128 bytes de variables globales a las que se puede acceder desde cualquier instrucción sin tener que preocuparse por la banca. Desafortunadamente, excluye la recursividad, dificulta ciertas situaciones que involucran punteros de función y, a menudo, conduce a un código que está inflado con movlb
instrucciones porque los compiladores a menudo no son muy buenos para organizar los bancos de manera eficiente.
La mejor disposición de las variables dependerá del tipo de compilador que esté utilizando. Desafortunadamente, el código optimizado para un compilador a menudo funcionará mal en otro.
Por cierto, no tengo idea de por qué Microchip no puede hacer un chip que, por ejemplo, proporcione 16 bytes de direccionamiento indirecto de FSR2 y ocho bytes de FSR0 y FSR1, mientras deja 64-96 bytes del "banco común" disponible para el almacenamiento del usuario. , pero por alguna razón, la mayoría de los PIC que he visto hacen que el uso del área "común" sea una propuesta de "todo o nada" a pesar de que pocas rutinas necesitarán más de 16 bytes de marco de pila local.
Lo que describes no es una buena idea. Sin embargo, si lo tiene funcionando en un proyecto en particular y ha sido bien probado, déjelo en paz.
Generalmente asigno variables en un PIC 18 de cuatro maneras diferentes:
Un ejemplo de estado global podrían ser los valores A/D filtrados finales. Las señales analógicas se leen más rápido de lo que se necesitan los resultados en el módulo AD. Esto aplica dos polos de filtrado de paso bajo a cada señal y también posiblemente algo de escala. El estado del filtro es privado para el módulo AD con solo los valores finales filtrados y escalados declarados como globales, ya que estos son todo lo que el resto del sistema necesita conocer.
Usualmente uso el banco de acceso para el estado global. Debe ser una colección de variables individuales de varios módulos, por lo que generalmente se ajusta fácilmente. Si necesita exportar búferes completos por algún motivo, cada uno de ellos debe estar en su propia sección y, por supuesto, cualquier otro módulo que acceda a dichos búferes debe saber que no están en el banco de acceso.
Por lo general, los coloco en la memoria almacenada, con todo el estado local de un módulo en el mismo banco. Defino la constante LBANK (banco local) en la parte superior del módulo para definir en qué banco estarán las variables locales de ese módulo. Esto se garantiza definiendo secciones del enlazador en el archivo del enlazador .BANKn donde N es el número de banco. Luego, en el código, las variables se definen en esos bancos nombrados para garantizar que el enlazador los colocará allí. Conocer el banco en el momento de la creación es útil para permitir una gestión bancaria inteligente.
C18 hace esto con lo que se denominan variables "automáticas" en C. Sin embargo, aunque C18 parece generar un código confiable, su elección de administración de memoria solo puede llamarse muerte cerebral en el mejor de los casos. Solo hay 3 FSR, lo que los hace preciosos. C18 toma dos de estos para su propio uso, dejando la aplicación solo con FSR0. C18 tiene una pila de datos, pero increíblemente, el diseño de la pila se elige para que empujar y sacar no sean instrucciones individuales. También tiene un modelo de paso de argumentos que limpia la persona que llama, que consume memoria innecesariamente para la mayoría de las llamadas a subrutinas normales, pero eso es una digresión para otro día.
Kellenjb
Nate
davidcary
jason s