Problemas con la FPU Cortex-M4F

Estoy escribiendo código para una placa Texas Instruments Stellaris Launchpad (una Cortex-M4F, el chip es un LM4F120H5QR ). Estoy usando la biblioteca IRMP para la decodificación de infrarrojos, que funciona bien, siempre que no use ninguna matemática de punto flotante fuera de su ISR. Una sola operación como en

MAP_SysCtlDelay((MAP_SysCtlClockGet())/ 30.0);

rompe la biblioteca IRMP. El chip aún se ejecuta, IRMP llama a todas sus funciones requeridas, las transmisiones UART funcionan, pero IRMP ya no puede decodificar ninguna recepción de infrarrojos.

En la parte superior de mi mainfunción tengo:

  // Enable FPU
  MAP_FPULazyStackingEnable();
  MAP_FPUEnable ();

De hecho, si comento esas líneas, el software simplemente se bloquea durante la inicialización.

Probé varias versiones de esas funciones de habilitación de FPU (ROM_, MAP_, FPUStackingEnable, FPULazyEnable), pero nada parece solucionar el problema.

Las últimas 4 horas de búsqueda en Google han resultado inútiles, así que esperaba encontrar una respuesta aquí.

Editar: Más rarezas: si compilo con -O0, IRMP tampoco decodifica nada. Tan pronto como configuro las optimizaciones en O1 o superior, comienza a funcionar nuevamente (siempre que no se realice una aritmética de punto flotante fuera de la rutina ISR del temporizador y las funciones que llama).

Ah, y en caso de que ayude, arm-none-eabi-gcc --versionda:

arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.7.3 20121207 (release) [ARM/embedded-4_7-branch revision 194305]

Estoy compilando con las siguientes opciones:

-DPART_LM4F120H5QR -DARM_MATH_CM4 -DTARGET_IS_BLIZZARD_RA1 -I$SOMEDIR/stellarisware 
-Os -Wall -std=gnu99 -c -fmessage-length=0 -fsingle-precision-constant -mcpu=cortex-m4 
-mfpu=fpv4-sp-d16 -mthumb -mfloat-abi=softfp -ffunction-sections -fdata-sections

Edición 2: debo agregar que no se realizan cálculos reales de punto flotante en el código IRMP. Es decir: todas las variables son números enteros. Sin embargo, hay muchas definiciones que son flotantes intermedias, por ejemplo:

#define IRMP_KEY_REPETITION_LEN (uint16_t)(F_INTERRUPTS * 150.0e-3 + 0.5)

Estas constantes se comparan con otros uint16_ttipos en el código real. No estoy muy seguro de por qué esto requiere aritmética FP en el código de tiempo de ejecución, todos son valores fijos que se pueden doblar en números enteros.

Respuestas (1)

¿Por qué no intenta eliminar todos los cálculos de coma flotante de las rutinas del servicio de interrupción? Mucha gente señalaría que, en primer lugar, no debería estar allí.

Calcule previamente las cosas de punto flotante en el flujo de código de la línea principal para que no sea necesario que estén en el ISR. Esto puede requerir un replanteamiento de los algoritmos utilizados, pero a menudo conducirá a un código más robusto y más ágil.

+1, no estoy lo suficientemente familiarizado con esa plataforma para estar seguro, pero parece que las operaciones de FPU no son atómicas y lo dejan en un estado indefinido. Otra cosa (que no es buena a largo plazo) sería deshabilitar las interrupciones mientras hace todo el código FPU en su código principal solo para ver si eso lo resuelve.
Estoy de acuerdo en que el ISR no es la ubicación ideal para los cálculos de FP, así que si todo lo demás falla, supongo que tendré que hacerlo. Sin embargo, prefiero que la biblioteca funcione en lugar de tener que leer todo el código y paralizarlo solo para que funcione.
En cuanto a que las operaciones de FPU no sean atómicas: la existencia de la función FPUStackingEnable() sugeriría lo contrario. Además, puedo descifrar el código ejecutando 1 sola operación FP incluso antes de inicializar la biblioteca IRMP. Después de eso, mi main() es solo un bucle ocupado vacío.
@Michael Karas: revisé el código, de todos modos no hay aritmética FP allí. Vea mi actualización nr 2 en la pregunta original.
@Darhuuk: lo siento si respondí mal para su situación específica. Mi comentario sigue siendo válido para el código de tiempo de interrupción, ya que generalmente es una mala práctica hacer cosas como un punto flotante dentro de un ISR. Para la mayoría de la programación como esta, es mejor mantener el código ejecutado en cada interrupción al mínimo. El simple hecho de habilitar la opción para supuestamente habilitar el punto flotante dentro de los ISR supone una gran carga para cada rutina de interrupción en términos de tener que empujar una gran cantidad de registros grandes a la pila. Mira el código de desmontaje... ouch.
@Darhuuk: ¿Ha mirado para ver si es posible que su programa esté corrupto relacionado con el tamaño y la ubicación de la PILA de tal manera que está creciendo demasiado o se está ejecutando en otra área de datos críticos?
@Michael Karas: No hay problema, entiendo lo que intentas decir y estoy de acuerdo en que, en la mayoría de los casos, no es realmente apropiado hacer operaciones matemáticas FP en un ISR. Aunque, con la FPU en un M4F, la instrucción FP más lenta toma "solo" 14 ciclos, y mi caso de uso no es crítico en absoluto, por lo que no debería importar mucho.
@Michael Karas: Aumenté el tamaño de la pila hasta 8 Kb y nada cambia, así que estoy haciendo algo mal en el script del enlazador o es un problema diferente.
@Michael Karas El problema resultó estar relacionado con la pila. Cambiar a un script de enlazador diferente lo arregló. Si agrega algo así en su respuesta, lo aceptaré con gusto;).