这听起来像是堆栈溢出吗?
我认为我的嵌入式固件代码中可能存在堆栈溢出问题或类似问题。我是一名新程序员,从未处理过 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
I think I might be having a stack overflow problem or something similar in my embedded firmware code. I am a new programmer and have never dealt with a SO so I'm not sure if that is what's happening or not.
The firmware controls a device with a wheel that has magnets evenly spaced around it and the board has a hall effect sensor that senses when magnet is over it. My firmware operates the stepper and also count steps while monitoring the magnet sensor in order to detect if the wheel has stalled.
I am using a timer interrupt on my chip (8 bit, 8057 acrh.) to set output ports to control the motor and for the stall detection. The stall detection code looks like this...
// 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();
}
}
}
this code is called every time the ISR is triggered. PosSensor is the magnet sensor. MagnetSize is the number of stepper steps that it takes to get through the magnet field. GapSize is the number of steps between two magnets. So I want to detect if the wheel gets stuck either with the sensor over a magnet or not over a magnet.
This works great for a long time but then after a while the first stall event will occur because 'StallDetector > (MagnetSize + 10)' but when I look at the value of StallDetector it is always around 220! This doesn't make sense because MagnetSize is always around 35. So the stall event should have been triggered at like 46 but somehow it got all the way up to 220? And I don't set the value of stall detector anywhere else in my code.
Do you have any advice on how I can track down the root of this problem?
The ISR looks like this
void Timer3_ISR(void) interrupt 14
{
OperateStepper(); // This is the function shown above
TMR3CN &= ~0x80; // Clear Timer3 interrupt flag
}
HandleStallEvent
just sets a few variable back to their default values so that it can attempt another move...
#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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
PosSensor 不稳定吗?也就是说,你是在某个地方更新PosSensor,还是直接读取GPIO?
我认为 GapSize 相当大(> 220?)在我看来,您可能存在竞争条件。
您应该在执行 StallDetector++ 之后立即缓存 PosSensor 的值一次,以便在代码期间 PosSensor 发生更改时,您不会开始测试新值。
Is PosSensor volatile? That is, do you update PosSensor somewhere, or is it directly reading a GPIO?
I assume GapSize is rather large (> 220?) It sounds to me like you might have a race condition.
You should cache the value of PosSensor once, right after doing StallDetector++, so that in the event PosSensor changes during your code, you don't start testing the new value.
这绝对不是堆栈溢出。如果你破坏了堆栈(溢出),你的应用程序就会崩溃。这听起来更像是我们在 C++ 时代所说的内存踩踏。您可能无法单独通过 StallDetector 变量访问 StallDetector 值占用的内存位置。您的代码的另一部分可能错误地“踩踏”了这个特定的内存位置。
不幸的是,此类问题很难追踪。您唯一能做的就是系统地隔离(从执行中删除)代码块,直到缩小范围并找到错误。
This is definitely not stack overflow. If you blew the stack (overflowed it) your application would simply crash. This sounds more like something we used to call memory stomping in my C++ days. You may not be accessing the memory location that the StallDetector value occupies via StallDetector variable alone. There may be another part of your code "stomping" this particular memory location erroneously.
Unfortunately, this kind of issue is very hard to track down. About the only thing you could do is systematically isolate (remove from execution) chunks of your code until you narrow down and find the bug.
您的系统上有嵌套 ISR 吗?可能是启动 ISR 并增加计数,然后中断它并再次执行。执行此操作足够多次,中断堆栈可能会溢出。它也可以解释如此高的计数器变量。
Do you have nest ISRs on your system? Could be something along the lines of start your ISR and increment your count, then interrupt it and do it again. Do this enough times and your interrupt stack can overflow. It could also explain such a high counter variable as well.
HandleStallEvent()
是否“查看”ISR 中的StallDetector
还是它会在主循环上触发某些内容?如果它在主循环上,您是否清除中断位?或者您是否从 ISR 外部的调试器查看
StallDetector
?然后,重新触发的中断每次都会使用正确的值,但执行次数过多,您只能看到最终的膨胀值。再想一想,更有可能的是您不必清除中断生成寄存器,而是中断引脚仍由传感器断言。您需要在第一次处理中断后忽略该中断,直到该行取消断言为止,例如通过让原始 ISR 自行禁用并将其重新安装到处理 1->0 转换的第二个 ISR 中。
然后,您可能还需要添加去抖硬件或对其进行调整(如果有的话)。
Does
HandleStallEvent()
"look at"StallDetector
within the ISR or does it trigger something on the main loop? If it's on the main loop, are you clearing the interrupt bit?Or are you looking at
StallDetector
from a debugger outside the ISR? Then a retriggered interrupt would use the correct value each time, but execute too many times, and you would only see the final, inflated value.On second thought, more likely you don't have to clear an interrupt-generating register, but rather the interrupt pin is remaining asserted by the sensor. You need to ignore the interrupt after it's first handled until the line deasserts, such as by having the original ISR disable itself and and reinstall it in a second ISR which handles the 1->0 transition.
You might then also need to add debouncing hardware or adjust it if you have it.
检查您的参数类型。如果您以不同于调用者期望的方式定义参数,那么调用您的方法可能会覆盖存储变量的空间。(例如,如果您编写的函数期望一个 int,但它正在将 long 压入堆栈。)
Check your parameter types. If you defined the parameters in a way different than the caller expects then calling your method could overwrite the space that variable is stored in. (For instance if you wrote the function expecting an int but it is pushing a long onto the stack.)
您可以看到调试器支持哪些附加选项。例如,在 Visual Studio 中,可以设置“数据断点”,当内存位置发生更改(或设置为某个值,或高于阈值,...)时,您将在该断点处中断。
如果您的情况可能发生类似的情况,您可以看到数据在哪里更改,以及是否有其他人错误地写入内存。
You could see what additional options your debugger supports. In Visual Studio, for example, it is possible to set a "data breakpoint", where you break when a memory location changes (or is set to a certain value, or above a threshold, ...).
If something like this is possible in your case, you could see where the data is changed and if there is someone else writing to the memory erroneously.