Uso de malloc en PIC

10

¿Cómo puedo usar las funciones malloc() y free() en un PIC? He comprobado el encabezado stdlib.h y no hay ninguna mención de ellos. Estoy usando MCC18.

¿Alguien tuvo que usarlos?

Los necesito porque estoy portando una biblioteca de Windows XP al PIC. La guía de portabilidad dice a

  

Adaptar las especificidades del sistema operativo.   funciones a mis PIC

Pero no sé cómo "traducir" las funciones malloc() y free() .

    
pregunta stef

7 respuestas

8

En muchas aplicaciones, uno tendrá que asignar memoria, pero no tendrá que liberar nada mientras se guarda algo que se asignó después. En tal sistema, todo lo que tiene que hacer es usar el enlazador para definir una matriz utilizando toda la RAM disponible, establecer un puntero al inicio de esa matriz y luego usar una función malloc fácil y agradable:

char *next_alloc;
void *malloc(int size)
{
    char  *this_alloc;
    this_alloc = next_alloc;
    if ((END_OF_ALLOC_SPACE - this_alloc) < size)
      return -1;
    next_alloc += size;
    return this_alloc;
}
void free(void *ptr)
{
    if (ptr)
        next_alloc = (char*)ptr;
}

Agradable y fácil, y solo una sobrecarga total de dos bytes para cualquier número de asignaciones. Si se llama a free () en un bloque, se desasignará ese bloque y todo lo que se encuentre después.

Los patrones de asignación un poco más complicados se pueden manejar usando dos punteros: uno que asigna cosas desde la parte inferior de la memoria hacia arriba, y uno de los cuales va desde la parte superior de la memoria hacia abajo. También es posible utilizar un recolector de basura compactador si los datos en el montón son homogéneos y se sabe dónde están todas las referencias externas a él.

    
respondido por el supercat
13

Esto no es una respuesta a su pregunta, pero la asignación de memoria dinámica generalmente está mal vista en entornos de RAM pequeños y en ausencia de un sistema operativo (por ejemplo, en el mundo de los microcontroladores) ... el espacio de pila que tiene disponible en un dispositivo integrado El entorno se mide normalmente en cientos de bytes ...

Implementar malloc y free es esencialmente el mantenimiento de una lista enlazada de estructuras de "segmento libre", y como puede imaginar, los metadatos asociados con los segmentos libres no son insustanciales cuando se comparan con la cantidad de memoria típicamente disponible ... es decir la "sobrecarga" de administrar una agrupación de memoria dinámica consume una cantidad significativa de los recursos disponibles.

    
respondido por el vicatcu
13

malloc() en microcontroladores generalmente se considera una "cosa mala". Pero, si es absolutamente necesario, querrá encontrar una versión de terceros.

Si tiene suerte, el código que está transfiriendo puede no depender de la reutilización de bloques de memoria. Si este es el caso, puede escribir un asignador simple que devuelva un puntero a un búfer de RAM, luego avanza el puntero en el tamaño de bloque solicitado.

He utilizado con éxito este enfoque antes de trasladar bibliotecas de PC a microcontroladores.

A continuación, configuraría el asignador con my_malloc_init() y asignaría la memoria con my_malloc() . my_free() está ahí para satisfacer la dependencia, pero en realidad no hará nada. Eventualmente, te quedarás sin espacio, por supuesto.

Para hacer que esto funcione, deberá medir el requisito de memoria del caso más desfavorable de su código (haga esto en una PC si es posible) y luego configure HEAP_SIZE en consecuencia. Antes de ingresar a la parte de su biblioteca que requiere memoria dinámica, llame a my_malloc_init() . Antes de volver a usar, asegúrese de que nada siga apuntando a heap .

uint8_t heap[HEAP_SIZE];
uint8_t *heap_ptr;

void my_malloc_init(void)
{
    heap_ptr = heap;
}

void *my_malloc(size_t len)
{
    uint8_t *p = heap_ptr;
    heap_ptr += len;
    if (heap_ptr >= heap + HEAP_SIZE)
        return NULL;
    else
        return p;
}

void my_free(void)
{
    // do nothing
}

(nota: en el mundo real, es posible que deba considerar la alineación del puntero, es decir, redondear heap_ptr por 2 o 4 bytes)

Otra opción es usar una estructura de asignación más simple que la que malloc() generalmente proporciona, como una FreeList , aunque esto puede no le permite asignar bloques de tamaño variable.

    
respondido por el Toby Jaffey
11

No sé si la biblioteca estándar C18 admite malloc y free , pero La nota de aplicación de Microchip AN914 muestra cómo puede implementar el suyo propio.

En cualquier caso, Thomas y otros carteles han sugerido, el uso de memoria dinámica en PIC con su muy pequeño espacio RAM está lleno de peligros. Puede quedarse rápidamente sin espacio contiguo debido a la falta de administradores de memoria virtual más avanzados que el sistema operativo completo le ofrece A las asignaciones fallidas y se bloquea. Peor aún, puede que no sea determinista, y probablemente será un problema depurar.

Si lo que estás haciendo está realmente determinado dinámicamente en el tiempo de ejecución (raro para la mayoría de los elementos integrados), y solo necesitas asignar espacio en un par de ocasiones muy especiales , podría ver malloc y free son aceptables.

    
respondido por el Nick T
2

Bueno, ¿qué tan grande es tu PIC en términos de memoria?

malloc es una manera muy ineficiente de asignar memoria a . El problema con esto es que la memoria puede fragmentarse con frees y mallocs frecuentes y con solo unos pocos kilobytes de memoria, las fallas en la asignación son muy comunes. Es muy probable que si está utilizando un chip más pequeño o un PIC18 anterior, no haya soporte para malloc, ya que Microchip lo vio como muy difícil de implementar (o incluso imposible en algunos casos) o no se usa lo suficiente como para que sea vale la pena. Por no hablar de eso, pero también es bastante lento, estás considerando 1 ciclo para usar un búfer estático ya disponible y de 100 a 1000 ciclos para hacer un malloc.

Si desea asignar estáticamente, cree cosas como un búfer para sus funciones de sprintf (si las hay, alrededor de 128 bytes), un búfer para su tarjeta SD (si corresponde), etc., hasta que elimine la necesidad de malloc . Idealmente, solo lo usa cuando lo necesita absolutamente y no puede evitar la asignación estática, pero estas situaciones suelen ser raras y quizás una señal de que debería estar mirando microcontroladores más grandes / más potentes.

Y si está desarrollando / portando un "sistema operativo" en el PIC18 y si es compatible con microcontroladores, probablemente tenga soporte para la asignación estática. Por ejemplo, SQLite3 admite la asignación estática: le asigna una gran matriz de búfer y la utiliza cuando sea posible, aunque no sea para microcontroladores. Si no es así, ¿está seguro de que está diseñado para un PIC18 pequeño?

    
respondido por el Thomas O
2

Si está considerando malloc() y free() para su software integrado, le sugiero que eche un vistazo a uC / OS-II y OSMemGet() y OSMemPut() . Mientras que malloc() le permite asignar un bloque de memoria arbitrario, OSMem*() le da un bloque de tamaño fijo de un grupo preasignado. Considero que este enfoque es un buen equilibrio entre la flexibilidad de malloc() y la solidez de la asignación estática.

    
respondido por el trondd
0

AFAIK, para hacer esto correctamente, realmente necesita estar mirando un dispositivo con algún tipo de unidad de administración de memoria (MMU). Si bien existen mecanismos de asignación dinámica para la serie PIC18, realmente no van a ser tan sólidos, y hablando como alguien que ha trabajado en un firmware que supera los límites de la serie PIC18, puedo decir que no va a obtener una aplicación de gran tamaño allí si gasta toda la sobrecarga en un administrador de memoria.

Mejor solución: intente entender qué está haciendo y por qué necesita una asignación dinámica. Vea si no puede modificar el factor para trabajar con la asignación estática. (Puede ocurrir que esto simplemente no sea posible, si la biblioteca / aplicación está diseñada para hacer algo que se escala libremente o no tiene límites de la cantidad de información que puede aceptar). Pero a veces, si realmente piensa sobre lo que estás tratando de hacer, podrías encontrar que es posible (y posiblemente incluso bastante fácil) usar una asignación estática.

    
respondido por el andersop

Lea otras preguntas en las etiquetas