Проблемы с FPU Cortex-M4F

Я пишу код для платы запуска Texas Instruments Stellaris Launchpad (Cortex-M4F, чип LM4F120H5QR ). Я использую библиотеку IRMP для инфракрасного декодирования, которая отлично работает, если я не использую математику с плавающей запятой за пределами ISR. Всего одна операция, такая как в

MAP_SysCtlDelay((MAP_SysCtlClockGet())/ 30.0);

ломает библиотеку IRMP. Чип все еще работает, IRMP вызывает все необходимые функции, передачи UART работают, но IRMP больше не может декодировать инфракрасный прием.

В самом верху моей mainфункции у меня есть:

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

На самом деле, если я закомментирую эти строки, программа просто зависнет во время инициализации.

Я пробовал несколько разновидностей этих функций включения FPU (ROM_, MAP_, FPUStackingEnable, FPULazyEnable), но, похоже, ничто не решает проблему.

Последние 4 часа гугления оказались бесполезными, поэтому я надеялся найти ответ здесь.

Редактировать: еще одна странность: если я компилирую с -O0, IRMP также ничего не декодирует. Как только я устанавливаю оптимизацию на O1 или выше, она снова начинает работать (при условии, что арифметика с плавающей запятой не выполняется вне процедуры ISR таймера и функций, которые она вызывает).

О, и в случае, если это поможет, arm-none-eabi-gcc --versionдает:

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

Я компилирую со следующими параметрами:

-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

Редактировать 2: я должен добавить, что в коде IRMP не происходит реальных вычислений с плавающей запятой. То есть: все переменные являются целыми числами. Однако существует множество определений, которые являются промежуточными поплавками, например:

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

Эти константы сравниваются с другими uint16_tтипами в реальном коде. Я не совсем уверен, почему для этого требуется арифметика FP в коде времени выполнения, это все фиксированные значения, которые можно сложить в целые числа.

Ответы (1)

Почему бы вам не попытаться удалить все вычисления с плавающей запятой из подпрограмм обслуживания прерываний. Многие люди сказали бы, что это не должно быть там в первую очередь.

Предварительно вычисляйте значения с плавающей запятой в основном потоке кода, чтобы их не нужно было использовать в ISR. Это может потребовать некоторого переосмысления используемых алгоритмов, но часто приводит к более надежному и компактному коду.

+1, я недостаточно знаком с этой платформой, чтобы быть уверенным, но похоже, что операции FPU не являются атомарными, оставляя ее в неопределенном состоянии. Еще одна (нехорошая в долгосрочной перспективе) вещь - отключить прерывания при выполнении всего кода FPU в вашем основном коде, просто чтобы посмотреть, решит ли это проблему.
Я согласен с тем, что ISR не является идеальным местом для вычислений FP, поэтому, если ничего не помогает, я думаю, мне придется это сделать. Тем не менее, я бы предпочел, чтобы библиотека работала вместо того, чтобы пробираться через весь код и калечить его только ради того, чтобы заставить его работать.
Что касается операций FPU, которые не являются атомарными: существование функции FPUSTackingEnable() предполагает обратное. Кроме того, я могу сломать код, выполнив 1 единственную операцию FP даже до инициализации библиотеки IRMP. После этого мой main() - это просто пустой цикл занятости.
@Michael Karas: Я просмотрел код, там все равно нет FP-арифметики. Смотрите мое обновление № 2 в исходном вопросе.
@Darhuuk - Извините, если я неправильно ответил в вашей конкретной ситуации. Мой комментарий по-прежнему означает выполнение временного кода прерывания, поскольку, как правило, это плохая практика делать такие вещи, как плавающая запятая внутри ISR. Для большинства подобных программ разумнее всего свести код, выполняемый при каждом прерывании, к минимуму. Простое включение опции предположительного включения операций с плавающей запятой внутри ISR налагает большую нагрузку на каждую процедуру прерывания с точки зрения необходимости помещать в стек множество больших регистров. Посмотрите на код дизассемблирования....ой.
@Darhuuk - Вы искали, может ли ваша программа получить повреждение, связанное с размером и расположением STACK, таким образом, что он становится слишком большим или сталкивается с другой важной областью данных?
@Michael Karas: Нет проблем, я понимаю, что вы пытаетесь сказать, и я согласен с тем, что в большинстве случаев не совсем уместно выполнять математику FP в ISR. Хотя с FPU в M4F самая медленная инструкция FP занимает «всего» 14 циклов, и мой вариант использования вообще не критичен по времени, поэтому это не должно иметь большого значения.
@Michael Karas: я увеличил размер стека до 8 КБ, и ничего не изменилось, поэтому либо я делаю что-то не так в скрипте компоновщика, либо это другая проблема.
@Michael Karas Проблема оказалась связанной со стеком. Переключение на другой скрипт компоновщика исправило это. Если вы добавите что-то подобное в свой ответ, я с радостью приму это;).