libc, incluido con gcc y avr-gcc, tiene una función que se usa para contar los ceros iniciales al convertir de un int
o uint
en un float
o un double
. Esta función usa una tabla de 256 bytes para acelerar la operación de conteo de cero, lo cual está bien para computadoras con mucha memoria, pero no tan buena para los microcontroladores donde 256 bytes es 1/4 o 1/8 del ram total disponible.
avr-gcc incluye una biblioteca, libm.o
que tiene definiciones alternativas para algunas funciones, incluida la función que requiere __clz_tab
. Esta definición requiere menos memoria, por lo que debe indicar al vinculador que vincule contra libm.
Esto se hace agregando -lm
a la línea de comando del vinculador.
Sin embargo, la posición de este parámetro de comando es importante: solo resolverá los enlaces a los símbolos antes de este parámetro, por lo que para aprovechar al máximo el parámetro -lm
debería estar lo más cerca posible del final de la línea de comando.
En mi Makefile
se ve así:
CXX=avr-gcc
CFLAGS=$(MCU) $(CPU_SPEED) -g -Os -w -Wl,--gc-sections -ffunction-sections -fdata-sections
LFLAGS= -Wl,--section-start=.text=0x0000,-Map=program.map
INCLUDE=-I ../include/arduino/
LIBS=-L ../lib -larduino -lm
default: program.hex
program.hex: program.elf
avr-objcopy -O ihex $< $@
program.elf: bcu_usb.cpp main.cpp programmer.cpp
$(CXX) $(CFLAGS) $(LFLAGS) $(INCLUDE) $^ -o $@ $(LIBS)
Tenga en cuenta que el último elemento en la línea de comando del compilador es $(LIBS)
y el último elemento en LIBS
es el -lm
que garantiza que compiler da prioridad a las definiciones en libm cuando hay varias definiciones disponibles.
Las versiones recientes de avr-gcc han resuelto este problema por lo que esto no ocurre incluso sin el -lm
, sin embargo, el IDE arduino todavía está instalando y utilizando las versiones anteriores de avr-gcc, y winavr no se ha actualizado ya que este error fue corregido.
Puede leer el informe de errores aquí:
enlace