2010-04-16 3 views
3

Я думаю, что у меня может возникнуть проблема с переполнением стека или что-то подобное в моем встроенном коде прошивки. Я новый программист и никогда не занимаюсь SO, поэтому я не уверен, что это то, что происходит или нет.Это звучит как переполнение стека?

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

Я использую прерывание таймера на своей микросхеме (8 бит, 8057 акров.), Чтобы установить выходные порты для управления двигателем и для обнаружения останова. Код обнаружения останова выглядит следующим образом:

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

Этот код вызывается каждый раз, когда ISR запускается. PosSensor - это магнитный датчик. MagnetSize - это количество шаговых шагов, которые требуется для прохождения поля магнита. GapSize - это количество шагов между двумя магнитами. Поэтому я хочу определить, зацикливается ли колесо с датчиком над магнитом или не над магнитом.

Это работает отлично в течение длительного времени, но через некоторое время первое событие срыва произойдет, потому что «StallDetector> (MagnetSize + 10)», но когда я смотрю на значение StallDetector, это всегда около 220! Это не имеет смысла, потому что MagnetSize всегда около 35. Таким образом, событие стойла должно было срабатывать как 46, но каким-то образом оно доходило до 220? И я не устанавливаю значение детектора останова в другом месте в моем коде.

У вас есть какие-либо советы о том, как я могу отследить корень этой проблемы?

ИСР выглядит следующим образом

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

HandleStallEvent просто устанавливает несколько переменных назад к их значениям по умолчанию, так что он может попытаться еще один шаг ...

#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 

ответ

2

Является ли PosSensor неустойчивым? То есть, вы когда-то обновляете PosSensor или напрямую читаете GPIO?

Я предполагаю, что GapSize довольно большой (> 220?) Звучит так, как будто у вас может быть состояние гонки.

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

Вы должны кэшировать значение PosSensor один раз, сразу же после того, как делать StallDetector ++, так что в изменениях PosSensor событий во время вашего кода, вы не начать тестирование нового значения.

+0

Похоже, что это решило проблему. Я до сих пор не знаю, как StallDetector смог получить до 200+, но я добавил одну строку кода, которая кэширует значение PosSensor в начале этой функции, изменила пару имен переменных и теперь работает более 1500 последовательных ходов без проблем! – PICyourBrain

+0

PosSensor и LastPosMagState были выключены. Это позволило StallDetector приблизиться к значению (GapSize + 10). Тогда состояние гонки поражает; PosSensor включается после if (PosSensor! = LastPosMagState), но раньше, если (PosSensor == ON), поэтому StallDetector не получает значение 0, если это должно было быть, что позволяет сравнить значение GapSize'd StallDetector с вашим MagnetSize – ajs410

+0

Охххх, это имеет смысл! Спасибо за exp. – PICyourBrain

1

ли HandleStallEvent() «смотреть на» StallDetector внутри ISR или он вызывает что-то в главном цикле? Если он находится в основном цикле, вы очищаете бит прерывания?

Или вы смотрите на StallDetector от отладчика вне ISR? Затем перезапущенное прерывание будет использовать правильное значение каждый раз, но выполнять слишком много раз, и вы увидите только конечное, завышенное значение.

С другой стороны, более вероятно, что вам не нужно очищать регистр, генерирующий прерывание, но прерывание прерывания остается подтвержденным датчиком. Вы должны игнорировать прерывание после его первой обработки до тех пор, пока линия не будет отменена, например, если исходный ISR отключится и переустановит его во втором ISR, который обрабатывает переход 1> 0.

Возможно, вам также понадобится добавить оборудование для debouncing или настроить его, если он у вас есть.

+0

Я смотрю StallDetector, используя мой отладчик IDE. Я устанавливаю точку останова на HandleStallEvent, и когда она попадает в нее, я смотрю на нее – PICyourBrain

+0

@Jordan: переполнение стека или нет, если 'StallDetector ++' является первой строкой, и вы ломаете ее, она должна подсчитываться по одному при каждом входе в отладчик. Если это не так, отладчик не покажет вам всю историю. Попробуйте отладить вне ISR, например, записав значение «StallDetector» в круговой буфер и/или установив флаг, который запускает контрольную точку mainloop. – Potatoswatter

+0

Он подсчитывает каждый раз каждый раз. Я не могу понять, что он делает прямо перед тем, как произойдет ошибка, потому что обычно перед тем, как «срыв» запускается, обычно требуется около 5 минут работы на нормальной скорости. – PICyourBrain

1

Это, безусловно, не переполнение стека. Если вы взорвали стек (переполнили его), ваше приложение просто сработало бы. Это больше похоже на то, что мы называли памятью топать в мои дни C++. Возможно, вы не можете получить доступ к ячейке памяти, которую значение StallDetector занимает только через переменную StallDetector. Возможно, другая часть вашего кода «топает» эту конкретную ячейку памяти ошибочно.

К сожалению, такого рода проблемы очень трудно отследить.Единственное, что вы можете сделать - это систематически изолировать (удалить из исполнения) фрагменты вашего кода, пока вы не сузите и не найдете ошибку.

+0

Да, это то, чего я боюсь. – PICyourBrain

1

У вас есть гнезда ISR на вашей системе? Может быть что-то вроде начала вашего ISR и увеличивать ваш счет, а затем прерывать его и делать это снова. Сделайте это достаточно времени, и ваш стек прерывания может переполняться. Это также может объяснить такую ​​высокую счетную переменную.

1

Проверьте типы параметров. Если вы определили параметры таким образом, который отличается от ожидающего, вызывающий ваш метод может переписать пространство, в котором хранится эта переменная. (Например, если вы написали функцию, ожидающую int, но она нажимает длинную на стек.)

1

Вы можете увидеть, какие дополнительные параметры поддерживает ваш отладчик. Например, в Visual Studio можно установить «точку останова данных», где вы разбиваетесь, когда ячейка памяти изменяется (или установлена ​​на определенное значение, или выше порога, ...).

Если в вашем случае возможно что-то подобное, вы можете увидеть, где данные были изменены, и если кто-то еще ошибочно записывает в память.

Смежные вопросы