Ошибка в компиляторе Keil ARM с обработчиками прерываний и C ++?

8

У меня проблема с записью обработчиков прерываний в компиляторе Keil ARM для LPC1114. Когда я пишу программу на C ++ и указываю опцию компилятора --cpp, весь код из обработчиков прерываний исчезает, он заменяется бесконечным циклом. Я написал простую программу, которая иллюстрирует мою проблему.

#include "LPC11xx.h"           // LPC11xx definitions
#define SYSTICK_DELAY 120000   // for 10 ms systick @ 12MHz osc

void SysTick_Handler(void)
{
  __NOP();
}

int main (void) 
{
  SystemInit();                   // from system_LPC11xx.c
  SysTick_Config(SYSTICK_DELAY);  // from core_cm0.h
  // Loop forever
  while (1) __NOP();
}

При попытке скомпилировать этот код с параметром компилятора --cpp, я получаю бесконечный цикл в disasm:

SysTick_Handler PROC
            EXPORT  SysTick_Handler           [WEAK]
            B       .
            ENDP

Это место, где должна быть программа __NOP () сверху. И это там, когда я компилирую код с опцией компилятора --c99 или без дополнительных опций. Версия Keil MDK - 4.12. Может кто-нибудь сказать мне, есть ли решение или обходной путь?

x4mer
источник
Поскольку ваш ISR ничего не делает, он просто оптимизируется? Возможно, вы могли бы попытаться отключить оптимизацию или объявить что-то volatileв ней.
Ник Т
Оптимизация установлена ​​на уровне -0, Оптимизация по времени - не выбрана. __NOP () не является ничем. Но я также попытался изменить глобальные переменные в обработчике прерываний или вызвать функции. Приведенный выше код был упрощен, чтобы быть настолько маленьким, чтобы воспроизвести проблему.
x4mer
1
Подал запрос технической поддержки в Keil, перепишу здесь любой ответ.
x4mer
Зачем вам нужен __NOP (); вызов? Разве вы не можете использовать простую точку с запятой?
Кевин Вермеер

Ответы:

14

«Слабая» ссылка просто означает, что подпрограмма будет заменена подпрограммой в вашем коде с тем же именем. При использовании C это просто, имена всегда будут идентичны, но имя C ++ меняет функции (для перегрузки функций и т. Д.), Поэтому скомпилированное имя, вероятно, не будет соответствовать имени ISR по умолчанию. Вам нужно обернуть функцию (или, по крайней мере, прямую ссылку, я не уверен в специфике, над которой я в основном работаю в C), во внешнюю оболочку "C", чтобы компилятор не искажал имя.

extern "C" {
  void SysTick_Handler(void)
  {
    // do whatever
  }
}
timrorr
источник
2
Спасибо. Это работает именно так, как вы написали в примере. А также я могу объявить функцию в заголовочном файле как extern "C" void SysTick_Handler (void); и позже напишу мой обработчик прерываний в классической форме, т.е. без внешнего "C".
x4mer
Боже мой! Спасибо за этот отличный ответ! Столько времени было потрачено впустую из-за незнания этого) Еще раз спасибо!