una sram que memoria mega liberar informatica estatica aleatorio acceso debugging memory embedded avr avr-gcc

debugging - que - ¿Cómo puedo visualizar el uso de memoria(SRAM) de un programa AVR?



que es una sram en informatica (8)

El enfoque habitual sería llenar la memoria con un patrón conocido y luego verificar qué áreas se sobrescriben.

He encontrado un problema en un programa de C que se ejecuta en un microcontrolador AVR (ATMega328P). Creo que se debe a una colisión de pila / pila, pero me gustaría poder confirmarlo.

¿Hay alguna manera de visualizar el uso de SRAM por la pila y el montón?

Nota: el programa se compila con avr-gcc y usa avr-libc.

Actualización: el problema real que tengo es que la implementación de malloc está fallando (devolviendo NULL ). Todo el proceso de malloc produce en el inicio y toda free liberación se produce al final de la aplicación (lo que en la práctica nunca ocurre porque la parte principal de la aplicación está en un bucle infinito). Así que estoy seguro de que la fragmentación no es el problema.


En sistemas operativos similares a Unix, una función de biblioteca llamada sbrk () con un parámetro de 0 le permite acceder a la dirección más alta de la memoria de almacenamiento dinámico asignada dinámicamente. El valor de retorno es un puntero nulo * y podría compararse con la dirección de una variable asignada de pila arbitraria.

Usar el resultado de esta comparación debe usarse con cuidado. Dependiendo de la CPU y la arquitectura del sistema, la pila puede crecer hacia abajo desde una dirección alta arbitraria, mientras que el montón asignado se moverá hacia arriba desde la memoria de límite bajo.

A veces, el sistema operativo tiene otros conceptos para la administración de la memoria (es decir, OS / 9) que coloca el montón y la pila en diferentes segmentos de memoria en la memoria libre. En estos sistemas operativos, especialmente para sistemas integrados, debe definir los requisitos de memoria máximos de sus aplicaciones con anticipación para permitir que el sistema asigne segmentos de memoria de tamaños coincidentes.


No utilice la asignación dinámica / de montón en objetivos incrustados. Especialmente con un procesador con recursos tan limitados. Más bien, rediseñe su aplicación porque el problema volverá a aparecer a medida que su programa crezca.


Puede verificar el uso estático de la RAM usando la utilidad avr-size , como se describe en
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=62968 ,
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=82536 ,
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=95638 ,
y http://letsmakerobots.com/node/27115

avr-size -C -x Filename.elf

(documentación de tamaño avr: http://ccrma.stanford.edu/planetccrma/man/man1/avr-size.1.html )

Sigue un ejemplo de cómo configurar esto en un IDE: En Código :: Bloques, Proyecto -> Opciones de compilación -> Pasos previos / posteriores a la compilación -> Pasos posteriores a la compilación, incluyen:

avr-size -C $(TARGET_OUTPUT_FILE) o
avr-size -C --mcu=atmega328p $(TARGET_OUTPUT_FILE)

Ejemplo de salida al final de la construcción:

AVR Memory Usage ---------------- Device: atmega16 Program: 7376 bytes (45.0% Full) (.text + .data + .bootloader) Data: 81 bytes (7.9% Full) (.data + .bss + .noinit) EEPROM: 63 bytes (12.3% Full) (.eeprom)

Los datos son su uso de SRAM, y es solo la cantidad que el compilador sabe en el momento de la compilación. También necesita espacio para las cosas creadas en el tiempo de ejecución (especialmente el uso de la pila).

Para verificar el uso de la pila (RAM dinámica), desde http://jeelabs.org/2011/05/22/atmega-memory-use/

Aquí hay una pequeña función de utilidad que determina la cantidad de RAM que actualmente no se usa:

int freeRam () { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); }

Y aquí hay un bosquejo usando ese código:

void setup () { Serial.begin(57600); Serial.println("/n[memCheck]"); Serial.println(freeRam()); }

La función freeRam () devuelve cuántos bytes existen entre el final del montón y la última memoria asignada en la pila, por lo que es efectivamente cuánto puede crecer la pila / montón antes de que colisionen.

Podría verificar el retorno de esta función en torno al código que sospecha que puede estar causando una colisión de pila / montón.


Si está utilizando tanto la pila como el montón, puede ser un poco más complicado. Voy a explicar lo que he hecho cuando no se utiliza ningún montón. Como regla general, todas las empresas para las que he trabajado (en el dominio del software C embebido) han evitado usar el montón para pequeños proyectos incrustados, para evitar la incertidumbre de la disponibilidad de memoria del montón. Usamos variables declaradas estáticamente en su lugar.

Un método es llenar la mayor parte del área de la pila con un patrón conocido (por ejemplo, 0x55) al inicio. Esto generalmente se hace con una pequeña cantidad de código al principio de la ejecución del software, ya sea justo al inicio de main (), o quizás incluso antes de que comience main (), en el código de inicio. Tenga cuidado de no sobrescribir la pequeña cantidad de pila en uso en ese momento, por supuesto. Luego, después de ejecutar el software por un tiempo, inspeccione el contenido del espacio de la pila y vea dónde está intacto el 0x55. Cómo "inspeccionar" depende de su hardware de destino. Suponiendo que tenga un depurador conectado, entonces simplemente puede detener la ejecución del micro y leer la memoria.

Si tiene un depurador que puede hacer un punto de interrupción de acceso a la memoria (un poco más sofisticado que el punto de interrupción de la ejecución habitual), puede establecer un punto de interrupción en una ubicación de pila particular, como el límite más lejano de su espacio de pila. Eso puede ser extremadamente útil, porque también te muestra exactamente qué bit de código se está ejecutando cuando llega a esa extensión de uso de la pila. Pero requiere que su depurador admita la función de punto de interrupción de acceso a la memoria y, a menudo, no se encuentra en los depuradores de "gama baja".

Si también está utilizando montón, entonces puede ser un poco más complicado porque puede ser imposible predecir dónde colisionarán la pila y el montón.


Si puede editar el código para su montón, puede rellenarlo con un par de bytes adicionales (complicado en recursos tan bajos) en cada bloque de memoria. Estos bytes podrían contener un patrón conocido diferente de la pila. Esto podría darle una pista si choca con la pila al verla aparecer dentro de la pila o viceversa.


Suponiendo que está usando solo una pila (por lo tanto no es un RTOS ni nada) y que la pila está al final de la memoria, creciendo hacia abajo, mientras que la pila se inicia después de la región BSS / DATA, creciendo. He visto implementaciones de malloc que realmente comprueban el apilador y fallan en una colisión. Podrías intentar hacer eso.

Si no puede adaptar el código malloc, puede optar por poner su pila al inicio de la memoria (usando el archivo de enlace). En general, siempre es una buena idea saber / definir el tamaño máximo de la pila. Si lo pones al principio, obtendrás un error al leer más allá del comienzo de la RAM. El montón estará al final y probablemente no pueda crecer más allá del final si es un ejemplo decente (en su lugar, devolverá NULL). Lo bueno es que sabes que tienes 2 casos de error separados para 2 temas separados.

Para averiguar el tamaño máximo de pila, puede llenar su memoria con un patrón, ejecutar la aplicación y ver hasta dónde llegó, vea también la respuesta de Craig.


Usted dice que malloc está fallando y devolviendo NULL:

La causa obvia que debería considerar al principio es que su montón está "lleno", es decir, la memoria que le pidió a malloc no se puede asignar, porque no está disponible.

Hay dos escenarios a tener en cuenta:

a: Tienes un montón de 16 K, ya has centrado en 10 K e intentas malloc otros 10K. Su montón es simplemente demasiado pequeño.

b: Más comúnmente, tienes un montón de 16 k, has estado haciendo un montón de llamadas malloc / free / realloc y tu montón está menos del 50% ''lleno'': Llamas a malloc por 1K y FALLA: ¿qué pasa? Respuesta: el espacio libre del montón está fragmentado: no hay un 1 K contigioso de memoria libre que se pueda devolver. C Los administradores de la pila no pueden compactar la pila cuando esto sucede, por lo que generalmente se encuentra en una mala situación. Existen técnicas para evitar la fragmentación, pero es difícil saber si este es realmente el problema. Necesitará agregar cuñas de registro a malloc y gratis para tener una idea de qué operaciones de memoria dinámica se están realizando.

EDITAR:

Dice que todos los mallocs ocurren al inicio, por lo que la fragmentación no es el problema.

En cuyo caso, debería ser fácil reemplazar la asignación dinámica con estática.

Ejemplo de código antiguo:

char *buffer; void init() { buffer = malloc(BUFFSIZE); }

nuevo código:

char buffer[BUFFSIZE];

Una vez que haya hecho esto en todas partes, su LINKER debería avisarle si todo no cabe en la memoria disponible. No olvide reducir el tamaño del almacenamiento dinámico, pero tenga en cuenta que algunas funciones del sistema en tiempo de ejecución de io pueden seguir utilizando el almacenamiento dinámico, por lo que es posible que no pueda eliminarlo por completo.