[英]Does this sound like a stack overflow?
我想我的嵌入式固件代碼中可能存在堆棧溢出問題或類似問題。 我是一個新的程序員,從來沒有處理過SO所以我不確定這是不是發生了什么。
固件控制帶有輪子的設備,輪子周圍均勻分布磁鐵,並且板上有一個霍爾效應傳感器,可以檢測磁鐵何時在其上方。 我的固件操作步進器並在監控磁鐵傳感器時計算步數,以檢測車輪是否已停轉。
我在芯片上使用定時器中斷(8位,8057 acrh。)來設置輸出端口以控制電機和失速檢測。 失速檢測代碼看起來像這樣......
// 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
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();
}
}
}
您應該在執行StallDetector ++之后立即緩存PosSensor的值一次,以便在代碼期間PosSensor更改時,您不會開始測試新值。
HandleStallEvent()
“查看”ISR中的StallDetector
還是在主循環上觸發了什么? 如果它在主循環上,你清除中斷位嗎?
或者您是從ISR之外的調試器查看StallDetector
? 然后,重新觸發的中斷每次都會使用正確的值,但執行次數過多,您只能看到最終的膨脹值。
再想一想,您更有可能不必清除產生中斷的寄存器,而是由傳感器保持斷言中斷引腳。 您需要在第一次處理之后忽略該中斷,直到線路無效為止,例如讓原始ISR自行禁用,然后在處理1-> 0轉換的第二個ISR中重新安裝。
然后,您可能還需要添加去抖硬件或調整它(如果有的話)。
這絕對不是堆棧溢出。 如果你吹掉堆棧(溢出它)你的應用程序就會崩潰。 這聽起來更像是我在C ++時代稱之為內存踩踏的東西。 您可能無法僅通過StallDetector變量訪問StallDetector值占用的內存位置。 您的代碼中可能有另一部分錯誤地“踩踏”此特定內存位置。
不幸的是,這類問題很難追查。 關於你唯一能做的就是系統地隔離(刪除執行)你的代碼塊,直到你縮小范圍並找到bug。
你的系統上有嵌套ISR嗎? 可能是啟動你的ISR並增加你的計數,然后中斷它並再次執行的東西。 這樣做足夠多,中斷堆棧可能會溢出。 它也可以解釋這么高的計數器變量。
檢查參數類型。 如果您以不同於調用者期望的方式定義參數,則調用您的方法可能會覆蓋存儲變量的空間。(例如,如果您編寫的函數需要一個int,但它會將一個long推入堆棧。)
您可以看到調試器支持的其他選項。 例如,在Visual Studio中,可以設置“數據斷點”,在內存位置更改(或設置為某個值或高於閾值,......)時中斷。
如果在您的情況下可能出現類似的情況,您可以看到數據的更改位置以及是否有其他人錯誤地寫入內存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.