Uso excesivo de RAM estática AVR con operaciones matemáticas de tipo mixto

Reduje un problema en mi código que crea 260 bytes adicionales de uso de RAM estática:

BYTE Height = 150;

BYTE sampleLevel(BYTE ADCchan,BYTE averages)
{
    float samp;
    //int samp;
    BYTE level;

    samp = avgSampleADC(ADCchan,averages);
    level = 100-(samp*100/Height);

    return level;
}

BYTEaquí hay un tipo uint8_t. Si hago un comentario float sampy lo convierto en un inttipo, el uso de RAM estática vuelve a ser lo que esperaba. Supongo que esto tiene algo que ver con la operación matemática level = 100-(samp*100/Height);, pero no sé qué es. ¿Qué está sucediendo para crear tal comportamiento?

Si está utilizando un programa como AVR Studio, debería poder echar un vistazo al desensamblador y averiguar en qué se está compilando el código C para su función; eso podría darte algunas pistas sobre lo que está sucediendo. Evitaría usar punto flotante en el AVR a menos que fuera absolutamente necesario.

Respuestas (4)

Para muchas funciones matemáticas, existe una compensación entre el uso de RAM y la velocidad. Supongo que la biblioteca de coma flotante AVR estará optimizada para la velocidad.
Bitrex tiene razón: intente evitar el punto flotante en los microcontroladores a menos que sea absolutamente necesario. ¿Realmente necesita punto flotante, o lo hará el punto fijo? Puede emular el punto fijo colocando un punto decimal virtual en algún lugar de un int.

En tu ejemplo multiplicas samppor 2 3 . El resultado, almacenado en un BYTEno tendrá una precisión muy alta. En un caso como ese, puede elegir un factor de escala que sea más fácil de calcular que el 2 3 . Encuentre una aproximación de la forma A 2 norte . En este caso 171 256 ~ 0.668 es una buena opción, con un error de solo 0.2%. Y es mucho más fácil de calcular: multiplique por 171 y desplace 8 bits a la derecha. No se necesita división.

solo recuerde convertir un uint8_t en un int16_t antes de multiplicarlo por 171 o probablemente obtendrá resultados "interesantes"
@vicatcu: ¿Es lo mismo "interesante" que la maldición china "Que vivas tiempos interesantes"? :)

¿Estás usando flotadores en algún otro lugar? Si no, el flotante aquí puede estar extrayendo toda la biblioteca de punto flotante, que puede estar asignando memoria para sí mismo. Muy rara vez hay necesidad de usar punto flotante en aplicaciones integradas, ya que no necesita el amplio rango de PF para procesar el rango limitado de valores de entradas del mundo real como ADC, etc. Recuerde que FP le brinda rango, no precisión. Casi siempre es mucho más pequeño y rápido usar punto fijo, y un valor de punto fijo siempre será más preciso que uno de FP del mismo tamaño.

"Recuerda que FP te da rango, no precisión". Eso no es del todo cierto. IEEE-754 le brinda 23 dígitos en precisión simple (52 en doble), lo que prefiero llamar muy preciso. En ingeniería, a menudo no se necesitan más de 4 dígitos significativos.
@stevenvh Todavía es solo una aproximación: una vez me encontré con un problema al agregar algunas cifras de moneda simples que se almacenaron en flotadores: el resultado de algo como $ 45.82 más $ 22.18 terminó como $ 67.99999999999 ... no es lo que se esperaba, pero exactamente lo que la metodología flotante IEEE dice que debería ser...
@Matt: las conversiones base no siempre son perfectas, pero nunca necesitará esos 23 dígitos significativos, y redondear a 20 (¡que aún no desea!) Por lo general, solucionará el problema. (Escribir pi en 23 dígitos y decir que es solo una aproximación es peor que simplemente criticar).
@ Matt: para ilustrar cuán absurdos son los 23 dígitos: ¡le permiten dar la distancia tierra-sol a la 1 pm (así es, un picómetro) exactamente!
@stevenvh Absolutamente: hizo que el cliente cambiara a double en lugar de float y no solo los resultados fueron más precisos, sino que también fue un código más rápido y más pequeño;) Solo uso floats si es absolutamente necesario (que generalmente puedo argumentar que nunca lo es ) . .)
@stevenvh 1:00 p. m. podría ser la diferencia entre que una nave espacial aterrice en Marte y desaparezca. Oh, lo siento, ¿es un picómetro o un picoyarda?
@stevenh, IEEE 754 le brinda 23 BITS en precisión simple. Esto da como resultado alrededor de 7 dígitos significativos en base 10. Para representar la distancia del sol a la tierra con resolución de picómetro, necesitaría alrededor de 74 bits en la mantisa.
@W5Vo - ¡Uy! ¡Supongo que aún no estoy del todo despierto!
@W5Vo Tal vez con 74 bits podría sumarse correctamente;)
Eso es de hecho 23 bits . Incluso entonces, nunca he necesitado doble precisión para los resultados finales, los resultados de cálculo intermedios son un asunto diferente.
@stevenvh odio esas estadísticas porque nunca se especifican por completo. ¿Es esa distancia cuando se los trata a ambos como masas puntuales? ¿La distancia más corta entre dos puntos cualesquiera? Sé que no importa porque solo lo estabas usando como ejemplo, pero son un poco contradictorios. Básicamente estás diciendo... "Incluso con esta aproximación, puedo realizar este cálculo súper preciso". Pero entonces el cálculo nunca se especifica completamente. /fin de perorata
@JGord: tenía algunos órdenes de magnitud, pero muestra la futilidad de una precisión muy alta. No importa cómo defina la distancia (de centro a centro tiene sentido), en realidad nunca será el valor que su número de alta precisión dice que es. Y eso se aplica a cada número de 20 dígitos significativos.
@JGord Si todo lo que necesita es <1% de error, no importa si son medidas del centro de masa o de la superficie :)
No, lo sé, lo entiendo completamente. Odio cómo se representan siempre esas estadísticas. Creo que leí uno en alguna parte que afirmaba que 3.14 era una aproximación lo suficientemente buena para que PI estimara el diámetro de la tierra al diámetro de un átomo de hidrógeno o algo por el estilo. Y yo estaba sentado allí pensando cómo diablos sabemos el diámetro de un átomo de hidrógeno jaja...

Lo que probablemente estés viendo es lo que se conoce como Promoción Variable .

Al realizar cualquier operación matemática que involucre múltiples tipos de variables, todas las variables dentro de la fórmula se promocionan a tipos de la mayor precisión (flotante en su caso). Por lo tanto, la variable Altura se copiará en una variable flotante temporal antes de que se realice la operación.

Esto solo representará una pequeña parte del aumento del uso de la memoria.

El resto probablemente se deba a la inclusión de toda la biblioteca de punto flotante en el sistema. Sin conocer el funcionamiento interno de la biblioteca de coma flotante del AVR, no puedo decir qué haría con dicha memoria (la mayoría de la memoria utilizada sería la memoria del programa y no la RAM).

Como ha mencionado stevenvh , hay formas mucho más eficientes de realizar este tipo de operaciones que no utilizan la biblioteca de punto flotante en absoluto, y el punto flotante, como se ha mencionado correctamente en otra parte, no es realmente lo que busca aquí, ya que tiene un factor de error inherente. Lo que realmente desea es el doble , no el flotador , ya que esta es una precisión fija con una mejor precisión que el flotador; sin embargo, aún no es tan eficiente como hacer matemáticas enteras al 100%.

He visto una explosión en la utilización de la memoria flash en avr-gcc si no usa el -lmindicador en el enlazador para vincular las rutinas de emulación de coma flotante optimizadas avr a través de la biblioteca matemática. Probablemente también debería tener la eliminación de funciones no utilizadas (-ffunction-sections)configurada en los indicadores del compilador y -Wl,-gc-sectionsconfigurada en los indicadores del vinculador si le importa minimizar la huella de memoria. Tenga en cuenta los guiones iniciales en todas las banderas.

Como referencia, las preguntas frecuentes del manual avr-gcc hablan explícitamente de esto. Aquí también hay otra buena referencia para las optimizaciones que puede aplicar en avr-gcc.

Habiendo dicho todo lo anterior, ahorrará la mayor cantidad de memoria simplemente no usando variables de punto flotante en su código, si puede formular su problema estrictamente en números enteros o matemáticas de punto fijo , ¡debería hacerlo!