domingo, 6 de mayo de 2012

Manejo de memoria en sistemas integrados

Las herramientas de desarrollo que hemos utilizado para programar el pic, como MickroBasic, o las herramienta de programación como la de Arduino que utilizan lenguajes como C++ u otros que utilizan lenguajes de programación que muchas veces no son enfocados precisamente para sistemas integrados, nosotros las utilizamos para desarrollo de aplicaciones de alto nivel, pero no son una opción viable para un sistema embebido.


Por ejemplo, muchas de las bibliotecas proporcionadas por Arduino se escriben como clases de C++, en donde este lenguaje permite el control de bajo nivel de una manera similar a C, y que nos permite enviar estructuras como a la "antigua",  pero es necesario saber como tomar la ventaja en utilizar este lenguaje en sistemas embebidos y no utilizarlo en nuestra contra.


Cuando estamos escribiendo aplicaciones que vamos a utilizar en nuestro escritorio, muchas veces no tenemos que preocuparnos en la memoria y los almacenamientos de estas ya que a pocos kilobytes de residuos no es nada en este contexto y si tenemos fugas de memoria, no nos fijamos en que nuestro programa esté bien reservado la memoria y son algunas veces tomado como si tuvieramos memoria infinita o parecido.


En el computo integrado, la memoria y el almacenamiento es muy limitado, por ejemplo un Arduino Mega viene con un ATMEGA1280, que tiene al rededor de 8 KB de memoria RAM,  o algunos como el AT90 tienen 16 MB de almacenamiento flash externo, por lo que si desarrollamos el aplicaciones de la misma manera que desarrollamos aplicaciones de escritorio, vamos a tener muchisismos problemas.


El mayor riesgo en el manejo de memoria en sistemas integrados es la asignación de memoria dinámica, tanto C como C++ ofrecen asignación memoria dinámica, pero como C++ soporta programación orientada a objetos y todos los patrones de programación orientada a objetos están diseñados para la asignación dinámica de computadoras con mucha memoria, debemos de tener un cuidado especial el utilizar C++.


¿Usamos asignación dinámica de memoria?


Estas son algunas de las dificultades de la asignación de memoria dinámica, la cual se debe de evitar en los sistemas integrados.


  • Motículos de asignación o llamados en inglés "Heap", son difícil de predecir cuanta memoria se va a ocupar.
  • El uso de pilas permite pérdidas de memoria, lo cual es muy peligroso en los sistemas con poca memoria.
  • Los sistemas integrados no tienen memoria virtual para recurrir si se acaba el espacio.
  • El sistema de manejo de memoria implica una sobrecarga de procesamiento y memoria para cada asignación de cualquier elemento (Por el contrario, la asignación estática es "liviana" de alguna forma).
  • No existe un control operativo para informar si hay un segmentation fault, por ejemplo, entonces tendremos más probablemente, errores de referencia a punteros cuando exista memoria liberada dinámicamente. 
  • Puede que existan como colisiones inesperadas entre la pila y los motículos, sobretodo si la pila se fragmenta.


Otra cuestión es que, si es muy necesario hacer una asignación dinámica en un sistema integrado, no debe ser realizado dentro de bucles, solo se debe hacer al inicio del código, para que de este modo se pueda utilizar el puntero de la pila y detectar las colisiones.


¿Como evitamos la asignación dinámica?


Una de las claves para evitar la asignación dinámica es hacer un buen diseño antes de programar un sistema integrado, esto es muy recomendable, el analizar lo que va a hacer nuestro programa, obviamente no vamos a predecir si vamos a tener un fallo o no, pero vamos a tomar conciencia de lo que debemos de hacer al hacer el computo de este tipo y esto lo podemos hacer tambien leyendo las especificaciones técnicas del integrado que estemos utilizando, por ejemplo el sistema operativo de tiempo real RTOS, permite unicamente hacer 8 tareas simultáneas y para cada tarea un límite de 256 bytes de espacio de pila.


Otra cosa que podemos hacer es utilizar técnicas oreintadas a objetos, sin asignación de memoria dinámica, por ejemplo en las bibliotecas de Arduino, definir los objetos de forma estática en el espacio de las variables globales, esto es muy bueno ya que los objetos están disponibles a nivel global y se puede acceder a ellos desde cualquier parte sin tener que utilizar punteros, por ejemplo. Aunque como hemos visto en algunas otras materias, el uso de variables globales muchas veces es malo, pero en cierta parte nos benefician en sistemas integrados.


¿Es buena idea utilizar la recursividad?



Nosotros utilizamos, muchas veces, formas recursivas en nuestros programas cuando necesitamos hacer algo, pero hay un problema en computo integrado, la recursividad, al igual que la asignación de memoria dinámica, no son faciles de predecir en tiempo de compilación por lo que aumenta considerablemente el riesgo de rebasar la pila. podemos utilizar funciones recursivas solo cuando la función es pequeña, por ejemplo que la tengamos funciones de O(log n).



Bueno espero que esto nos ayude a realizar códigos de manera más eficientes y pensar en como diseñar mejor nuestros programar, ya que por ejemplo, cuando yo realicé mi proyecto de PIC, tenia muchos problemas con este tipo de cosas y después de investigar, me he dado cuenta que yo queria programar como si estuviera en una computadora, cuando no estaba tomando las consideraciones adecuadas para hacer un programa de computo integrado, el cual es diferente.

1 comentario: