Bug dans le compilateur Keil ARM avec les gestionnaires d'interruption et C ++?

8

J'ai un problème avec l'écriture des gestionnaires d'interruption dans le compilateur Keil ARM pour LPC1114. Lorsque j'écris un programme en C ++ et que je spécifie l'option du compilateur --cpp, tout le code des gestionnaires d'interruption disparaît, il est remplacé par une boucle infinie. J'ai écrit un programme simple qui illustre mon problème.

#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();
}

Lorsque j'essaye de compiler ce code avec l'option de compilation --cpp, j'obtiens une boucle infinie en disasm:

SysTick_Handler PROC
            EXPORT  SysTick_Handler           [WEAK]
            B       .
            ENDP

C'est l'endroit où doit être __NOP () du programme ci-dessus. Et il est là lorsque je compile du code avec l'option de compilation --c99 ou sans options supplémentaires. La version Keil MDK est 4.12. Quelqu'un peut-il me dire s'il existe une solution ou une solution?

x4mer
la source
Comme votre ISR ne fait rien, il est juste optimisé? Vous pouvez peut-être essayer de désactiver l'optimisation ou d'y déclarer quelque chose volatile.
Nick T
L'optimisation est définie sur -level0, Optimiser pour le temps - désélectionnée. __NOP () n'est pas rien. Mais j'ai également essayé de changer les variables globales dans le gestionnaire d'interruption ou d'appeler des fonctions. Le code fourni ci-dessus a été simplifié pour être juste si petit pour reproduire le problème.
x4mer
1
A déposé une demande de support technique à Keil, republiera ici toute réponse.
x4mer
Pourquoi avez-vous besoin d'un __NOP (); appel? Ne pouvez-vous pas simplement utiliser un simple point-virgule?
Kevin Vermeer

Réponses:

14

La référence "faible" signifie simplement que la routine sera remplacée par une routine dans votre code du même nom. Lorsque vous utilisez C, c'est simple, les noms seront toujours identiques mais le nom C ++ modifie les fonctions (pour la surcharge de fonctions, etc.), de sorte que le nom compilé ne correspondra probablement pas au nom ISR par défaut. Vous devez encapsuler la fonction (ou au moins une référence directe, je ne suis pas sûr des détails que je travaille principalement en C) dans un wrapper "C" externe pour forcer le compilateur à ne pas modifier le nom.

extern "C" {
  void SysTick_Handler(void)
  {
    // do whatever
  }
}
timrorr
la source
2
Je vous remercie. Cela fonctionne exactement comme vous l'avez écrit dans l'exemple. Et aussi je peux déclarer la fonction dans le fichier d'en-tête comme extern "C" void SysTick_Handler (void); et écrire plus tard mon gestionnaire d'interruption sous forme classique, c'est-à-dire sans "C" externe.
x4mer
Oh mon Dieu! Merci pour cette excellente réponse! Tant de temps perdu parce que je ne le savais pas) Merci encore!