2010-04-16 26 views
3

Je pense que je peux avoir un problème de débordement de pile ou quelque chose de similaire dans mon code de firmware embarqué. Je suis un nouveau programmeur et je n'ai jamais eu affaire à un SO donc je ne sais pas si c'est ce qui se passe ou pas. Le microprogramme commande un périphérique avec une roue dont les aimants sont régulièrement espacés et la carte est équipée d'un capteur à effet Hall qui détecte la présence d'un aimant. Mon microprogramme actionne le stepper et compte également les pas tout en surveillant le capteur magnétique afin de détecter si la roue a calé. J'utilise une interruption de minuterie sur ma puce (8 bits, 8057 acres) pour régler les ports de sortie pour contrôler le moteur et pour la détection de calage. Le code de détection de décrochage ressemble à ceci ...Cela ressemble-t-il à un débordement de pile?

// Enter ISR 
    // Change the ports to the appropriate value for the next step 
    // ... 

    StallDetector++;  // Increment the stall detector 

    if(PosSensor != LastPosMagState) 
    { 
     StallDetector = 0; 

     LastPosMagState = PosSensor; 
    } 
    else 
    { 
     if (PosSensor == ON) 
     { 
      if (StallDetector > (MagnetSize + 10)) 
      { 
       HandleStallEvent(); 
      } 
     } 
     else if (PosSensor == OFF) 
     { 
      if (StallDetector > (GapSize + 10)) 
      { 
       HandleStallEvent(); 
      } 
     } 
    } 

ce code est appelé chaque fois que l'ISR est déclenché. PosSensor est le capteur d'aimant. MagnetSize est le nombre de pas de pas qu'il faut pour traverser le champ magnétique. GapSize est le nombre de pas entre deux aimants. Donc, je veux détecter si la roue se coince soit avec le capteur sur un aimant ou pas sur un aimant.

Cela fonctionne très bien pendant longtemps, mais après un moment, le premier événement de décrochage se produira car 'StallDetector> (MagnetSize + 10)' mais quand je regarde la valeur de StallDetector, il est toujours autour de 220! Cela n'a pas de sens parce que MagnetSize est toujours autour de 35. Donc l'événement de décrochage aurait dû être déclenché à 46, mais d'une manière ou d'une autre jusqu'à 220? Et je ne définis pas la valeur du détecteur de décrochage ailleurs dans mon code.

Avez-vous un conseil sur la façon dont je peux traquer la racine de ce problème?

L'ISR se présente comme suit

void Timer3_ISR(void) interrupt 14 
{ 
    OperateStepper(); // This is the function shown above 
    TMR3CN &= ~0x80; // Clear Timer3 interrupt flag   
} 

HandleStallEvent définit quelques-uns variables à leurs valeurs par défaut afin qu'il puisse tenter un autre mouvement ...

#pragma save 
#pragma nooverlay 
void HandleStallEvent() 
{ 
///* 
    PulseMotor = 0;     //Stop the wheel from moving 
    SetMotorPower(0);    //Set motor power low 
    MotorSpeed = LOW_SPEED; 
    SetSpeedHz(); 
    ERROR_STATE = 2; 
    DEVICE_IS_HOMED = FALSE; 
    DEVICE_IS_HOMING = FALSE; 
    DEVICE_IS_MOVING = FALSE; 
    HOMING_STATE = 0; 
    MOVING_STATE = 0; 
    CURRENT_POSITION = 0; 
    StallDetector = 0; 
    return; 
//*/ 
} 
#pragma restore 

Répondre

2

Est-ce que PosSensor est volatile? Autrement dit, mettez-vous à jour PosSensor quelque part, ou lisez-vous directement un GPIO?

Je suppose que GapSize est plutôt grand (> 220?) Il me semble que vous pourriez avoir une condition de concurrence.

// PosSensor == OFF, LastPosMagState == OFF 
    if(PosSensor != LastPosMagState) 
    { 
     StallDetector = 0; 

     LastPosMagState = PosSensor; 
    } 
    else 
    { 
// Race Condition: PosSensor turns ON here 
// while LastPosMagState still == OFF 
     if (PosSensor == ON) 
     { 
      if (StallDetector > (MagnetSize + 10)) 
      { 
       HandleStallEvent(); 
      } 
     } 
     else if (PosSensor == OFF) 
     { 
      if (StallDetector > (GapSize + 10)) 
      { 
       HandleStallEvent(); 
      } 
     } 
    } 

Vous devriez mettre en cache la valeur de PosSensor une fois, juste après avoir fait StallDetector ++, de sorte qu'en cas de changements PosSensor au cours de votre code, vous ne commencez pas à tester la nouvelle valeur.

+0

On dirait que cela a résolu le problème. Je ne suis toujours pas sûr de savoir comment StallDetector a pu obtenir jusqu'à 200+ mais j'ai ajouté une ligne de code qui met en cache la valeur PosSensor au début de cette fonction, a changé quelques noms de variables et maintenant il a été exécuté pour plus de 1500 mouvements séquentiels sans problèmes! – PICyourBrain

+0

PosSensor et LastPosMagState étaient tous deux désactivés. Cela a permis à StallDetector d'approcher la valeur (GapSize + 10). Alors la condition de course frappe; PosSensor est activé après if (PosSensor! = LastPosMagState), mais avant if (PosSensor == ON), donc StallDetector n'est pas mis à 0 alors qu'il aurait dû l'être, ce qui permet de comparer la valeur GapSize'd StallDetector avec votre MagnetSize – ajs410

+0

Ohhhhh qui a du sens! Merci pour l'exp. – PICyourBrain

1

-t-HandleStallEvent() « regarder » StallDetector dans l'ISR ou déclenche-t-il quelque chose sur la boucle principale? Si c'est sur la boucle principale, effacez-vous le bit d'interruption?

Ou regardez-vous StallDetector à partir d'un débogueur en dehors de l'ISR? Ensuite, une interruption redéclenchée utiliserait la valeur correcte à chaque fois, mais exécuterait trop de fois, et vous ne verriez que la valeur finale, gonflée. À la réflexion, il est plus probable que vous n'ayez pas à effacer un registre de génération d'interruptions, mais que la broche d'interruption reste activée par le capteur. Vous devez ignorer l'interruption après qu'elle a été traitée pour la première fois jusqu'à ce que la ligne se désactive, par exemple en désactivant l'ISR d'origine et en le réinstallant dans un deuxième ISR qui gère la transition 1-> 0.

Vous devrez peut-être également ajouter du matériel anti-rebond ou l'ajuster si vous l'avez.

+0

Je regarde StallDetector en utilisant mon débogueur IDE. Je place un point d'arrêt sur HandleStallEvent et quand il le frappe je le regarde – PICyourBrain

+0

@Jordan: Dépassement de pile ou non, si 'StallDetector ++' est la première ligne et que vous le cassez, il devrait compter par un chaque fois que vous tombez dans le débogueur. Si ce n'est pas le cas, le débogueur ne vous montre pas toute l'histoire. Essayez de déboguer en dehors de l'ISR, par exemple en écrivant la valeur de StallDetector dans un tampon circulaire et/ou en définissant un indicateur qui déclenche un point d'arrêt de boucle principale. – Potatoswatter

+0

Il compte par un à chaque fois. Je ne peux pas sembler attraper ce qu'il fait juste avant que l'erreur se produise, car il faut généralement environ 5 minutes de fonctionnement à vitesse normale avant que le "décrochage" ne soit déclenché. – PICyourBrain

1

Il ne s'agit certainement pas d'un débordement de pile. Si vous avez soufflé la pile (débordé), votre application se bloque simplement. Cela ressemble plus à quelque chose que nous appelions la mémoire piétinant dans mes jours C++. Vous ne pouvez pas accéder à l'emplacement de mémoire que la valeur StallDetector occupe via la variable StallDetector seule. Il se peut qu'il y ait une autre partie de votre code "piétinant" cet emplacement de mémoire particulier par erreur.

Malheureusement, ce type de problème est très difficile à localiser.A propos de la seule chose que vous pourriez faire est d'isoler systématiquement (retirer de l'exécution) des morceaux de votre code jusqu'à ce que vous affinez et trouvez le bug.

+0

ouais c'est ce dont j'ai peur. – PICyourBrain

1

Avez-vous des ISR de nid sur votre système? Pourrait être quelque chose dans le sens de démarrer votre ISR et incrémenter votre compte, puis l'interrompre et le faire à nouveau. Faites cela assez souvent et votre pile d'interruption peut déborder. Cela pourrait également expliquer une variable de compteur aussi élevée.

1

Vérifiez vos types de paramètres. Si vous avez défini les paramètres d'une manière différente de celle attendue par l'appelant, l'appel de votre méthode pourrait écraser l'espace dans lequel cette variable est stockée. (Par exemple, si vous avez écrit la fonction en attendant un int, mais en enfonçant un long.)

1

Vous pouvez voir les options supplémentaires prises en charge par votre débogueur. Dans Visual Studio, par exemple, il est possible de définir un "point d'arrêt de données", où vous cassez quand un emplacement de mémoire change (ou est défini sur une certaine valeur, ou au-dessus d'un seuil, ...).

Si quelque chose comme ceci est possible dans votre cas, vous pouvez voir où les données sont modifiées et si quelqu'un d'autre écrit dans la mémoire par erreur.