5

I'm writing some code for a Texas Instruments Stellaris Launchpad board (a Cortex-M4F, the chip is a LM4F120H5QR). I'm using the IRMP library for infrared decoding, which works fine, as long as I don't use any floating point math outside of its ISR. Just a single operation such as in

MAP_SysCtlDelay((MAP_SysCtlClockGet())/ 30.0);

breaks the IRMP library. The chip still runs, IRMP calls all its required functions, UART transmissions work, but IRMP can't decode any infrared reception anymore.

At the very top of my main function I've got:

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

In fact, if I comment out those lines, the software just hangs during intialization.

I've tried several flavours of those FPU enabling functions (ROM_, MAP_, FPUStackingEnable, FPULazyEnable), but nothing seems to fix the problem.

The past 4 hours of Googling have proven useless, so I was hoping to find an answer here.

Edit: More weirdness: if I compile with -O0, IRMP doesn't decode anything either. As soon as I set optimizations to O1 or higher, it starts working again (provided no floating point arithmetic takes place outside of the timer ISR routine and the functions it calls).

Oh, and in case it helps, arm-none-eabi-gcc --version gives:

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

I'm compiling with the following options:

-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

Edit 2: I should add that no actual floating point calculations happen in the IRMP code. That is to say: all variables are integers. However, there are a lot of defines which are intermediate floats, e.g.:

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

These constants are compared with other uint16_t types in the actual code. I'm not quite sure why this requires FP arithmetic in the run-time code, it's all fixed values which can be folded into integers.

AVH
  • 151
  • 5

1 Answers1

5

Why don't you try to remove all the floating point calculations from the interrupt service routines. Many folks would point out that it shouldn't be in there in the first place.

Pre-calculate floating point things in the mainline code flow so that it does not need to be in the ISR. This may require some rethinking of the algorithms used but will often lead to more robust and leaner code.

Michael Karas
  • 56,889
  • 3
  • 70
  • 138
  • +1, I'm not familiar enough with that platform to be sure but sounds like the FPU operations are not atomic leaving it in an undefined state. Another (not good long term) thing would be to disable interrupts while doing all FPU code in your main code just to see if that solves it. – PeterJ Feb 07 '13 at 03:53
  • I agree that the ISR is not the ideal location for FP calculations, so if all else fails, I guess I'll have to do that. However, I'd rather just have the library work instead of having to wade through all the code and cripple it just for the sake of getting it to work. – AVH Feb 07 '13 at 10:21
  • As for the FPU operations not being atomic: the existence of the FPUStackingEnable() function would suggest otherwise. Also, I can break the code by executing 1 single FP operation even before initializing the IRMP library. After that my main() is just an empty busy loop. – AVH Feb 07 '13 at 10:23
  • @Michael Karas: I went through the code, there's not FP arithmetic in there anyway. See my update nr 2 in the original question. – AVH Feb 08 '13 at 01:20
  • @Darhuuk - Sorry if I answered wrong for your specific situation. My comment still stands for doing Interrupt time code in that it is generally a bad practice to do things like floating point inside it an ISR. For most programming like this it is wisest to keep code executed at each interrupt to a minimum. Simply enabling the option to supposedly enable the floating point inside ISRs places a big burden on each interrupt routine to in terms of having to push a lot of big registers to the stack. Look at the disassembly code....ouch. – Michael Karas Feb 08 '13 at 05:16
  • @Darhuuk - Have you looked to see if you may be possibly getting corruption in your program related to having the STACK size and location such that it is growing too big or running into another critical data area? – Michael Karas Feb 08 '13 at 05:18
  • @Michael Karas: No problem, I get what you are trying to say and I agree that in most cases it's not really appropriate to do FP math in an ISR. Although, with the FPU in an M4F, the slowest FP instruction takes "only" 14 cycles, and my use case is not timing critical at all, so it shouldn't matter much. – AVH Feb 08 '13 at 10:41
  • @Michael Karas: I've increased the stack size up to 8Kb and nothing changes, so either I'm doing something wrong in the linker script or it's a different problem. – AVH Feb 08 '13 at 10:41
  • @Michael Karas The problem turned out to be stack related. Switching to a different linker script fixed it. If you add something like that in your answer I will gladly accept it ;). – AVH Feb 08 '13 at 22:37