Похоже ли это на переполнение стека? - PullRequest
3 голосов
/ 16 апреля 2010

Я думаю, что у меня может быть проблема переполнения стека или что-то подобное во встроенном коде прошивки. Я новый программист и никогда не имел дело с 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? И я не устанавливаю значение детектора остановки в другом месте в моем коде.

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

ISR выглядит так

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

Ответы [ 6 ]

2 голосов
/ 16 апреля 2010

Является ли 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 во время вашего кода вы не начинали тестировать новое значение.

1 голос
/ 16 апреля 2010

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

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

1 голос
/ 16 апреля 2010

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

1 голос
/ 16 апреля 2010

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

1 голос
/ 16 апреля 2010

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

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

1 голос
/ 16 апреля 2010

HandleStallEvent() "смотрит" на StallDetector в ISR или это вызывает что-то в основном цикле? Если это в главном цикле, вы очищаете бит прерывания?

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

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

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

...