![](/img/trans.png)
[英]How can you do C++ when your embedded compiler doesn't have operator new or STL support?
[英]How do you control what your C compiler Optimizes?
我正在使用Silicon Labs IDE和SDCC編譯器在C語言中為嵌入式設備編寫固件。 器件架構基於8051系列。 有問題的功能如下所示。 該功能用於設置MCU上的端口以驅動步進電機。 它被一個中斷處理程序調用。 big switch語句只是將端口設置為下一個電機步驟的正確值。 該功能的底部部分查看來自霍爾效應傳感器的輸入和移動的多個步驟,以便檢測電機是否已停止。 問題是,由於某種原因,第二個IF語句看起來像這樣if (StallDetector > (GapSize + 20)) { HandleStallEvent(); }
if (StallDetector > (GapSize + 20)) { HandleStallEvent(); }
似乎總是得到優化了。 如果我嘗試在HandleStallEvent()
調用中設置斷點,則IDE會向我顯示一條消息,指出“此行號沒有地址關聯”。 我在閱讀匯編時並不是很擅長講述它正在做什么,但我已經從下面的asm輸出中粘貼了一個片段。 任何幫助將非常感激。
void OperateStepper(void)
{
//static bit LastHomeMagState = HomeSensor;
static bit LastPosMagState = PosSensor;
if(PulseMotor)
{
if(MoveDirection == 1) // Go clockwise
{
switch(STEPPER_POSITION)
{
case 'A':
STEPPER_POSITION = 'B';
P1 = 0xFD;
break;
case 'B':
STEPPER_POSITION = 'C';
P1 = 0xFF;
break;
case 'C':
STEPPER_POSITION = 'D';
P1 = 0xFE;
break;
case 'D':
STEPPER_POSITION = 'A';
P1 = 0xFC;
break;
default:
STEPPER_POSITION = 'A';
P1 = 0xFC;
} //end switch
}
else // Go CounterClockwise
{
switch(STEPPER_POSITION)
{
case 'A':
STEPPER_POSITION = 'D';
P1 = 0xFE;
break;
case 'B':
STEPPER_POSITION = 'A';
P1 = 0xFC;
break;
case 'C':
STEPPER_POSITION = 'B';
P1 = 0xFD;
break;
case 'D':
STEPPER_POSITION = 'C';
P1 = 0xFF;
break;
default:
STEPPER_POSITION = 'A';
P1 = 0xFE;
} //end switch
} //end else
MotorSteps++;
StallDetector++;
if(PosSensor != LastPosMagState)
{
StallDetector = 0;
LastPosMagState = PosSensor;
}
else
{
if (PosSensor == ON)
{
if (StallDetector > (MagnetSize + 20))
{
HandleStallEvent();
}
}
else if (PosSensor == OFF)
{
if (StallDetector > (GapSize + 20))
{
HandleStallEvent();
}
}
}
} //end if PulseMotor
}
...以及此函數底部的asm輸出...
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:653: if(PosSensor != LastPosMagState)
mov c,_P1_4
jb _OperateStepper_LastPosMagState_1_1,00158$
cpl c
00158$:
jc 00126$
C$MotionControl.c$655$3$7 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:655: StallDetector = 0;
clr a
mov _StallDetector,a
mov (_StallDetector + 1),a
C$MotionControl.c$657$3$7 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:657: LastPosMagState = PosSensor;
mov c,_P1_4
mov _OperateStepper_LastPosMagState_1_1,c
ret
00126$:
C$MotionControl.c$661$2$8 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:661: if (PosSensor == ON)
jb _P1_4,00123$
C$MotionControl.c$663$4$9 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:663: if (StallDetector > (MagnetSize + 20))
mov a,_MagnetSize
mov r2,a
rlc a
subb a,acc
mov r3,a
mov a,#0x14
add a,r2
mov r2,a
clr a
addc a,r3
mov r3,a
clr c
mov a,r2
subb a,_StallDetector
mov a,r3
subb a,(_StallDetector + 1)
jnc 00130$
C$MotionControl.c$665$5$10 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:665: HandleStallEvent();
ljmp _HandleStallEvent
00123$:
C$MotionControl.c$668$2$8 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:668: else if (PosSensor == OFF)
jnb _P1_4,00130$
C$MotionControl.c$670$4$11 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
mov a,#0x14
add a,_GapSize
mov r2,a
clr a
addc a,(_GapSize + 1)
mov r3,a
clr c
mov a,r2
subb a,_StallDetector
mov a,r3
subb a,(_StallDetector + 1)
jnc 00130$
C$MotionControl.c$672$5$12 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:672: HandleStallEvent();
C$MotionControl.c$678$2$1 ==.
XG$OperateStepper$0$0 ==.
ljmp _HandleStallEvent
00130$:
ret
在我看來,編譯器並沒有從asm的外觀中優化掉第二個if語句但是如果是這樣的話為什么IDE不允許我在那里設置斷點? 也許這只是一個愚蠢的IDE!
它被稱為“尾調用優化”。
在調用HandleStallEvent()之后,OperateStepper()沒有做任何事情,因此返回它沒有意義。 你只是對RET做一個RET,這是浪費指令和堆棧槽。
閱讀“Lambda:The Ultimate ...”MIT AI Lab備忘錄了解更多詳情。
在HandleStallEvent()例程中設置斷點,而不是調用。
IF語句未被優化。 這是它的代碼。
C$MotionControl.c$670$4$11 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
mov a,#0x14 ; r2,r3 = 20 + GapSize
add a,_GapSize ; (adding a 16-bit number in two 8-bit steps)
mov r2,a
clr a
addc a,(_GapSize + 1)
mov r3,a
clr c
mov a,r2 ; subtracting in two 8-bit steps
subb a,_StallDetector
mov a,r3
subb a,(_StallDetector + 1)
jnc 00130$ ; jump if carry not set (fall through if carry set)
C$MotionControl.c$672$5$12 ==.
; C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:672: HandleStallEvent();
C$MotionControl.c$678$2$1 ==.
XG$OperateStepper$0$0 ==.
ljmp _HandleStallEvent ; it knows HandleStallEvent does not return!
00130$: ; or rather, it knows this handler cannot return, so there's no need to call.
ret
我注意到在第三到最后一行,發生了一些有趣的事情。 它沒有對HandleStallEvent
進行函數調用。 它正在進行長跳轉,所以它顯然知道HandleStallEvent
無法返回。 我還看到,在上面的兩行中,它定義了將行號與跳轉指令相關聯的匯編符號。 因此,它具有第678行的符號。如果IDE不允許您在第678行設置斷點,也許您可以獲取第678行的十六進制地址,並將其設置為十六進制地址。 您可能嘗試的另一件事可能是在該行之前插入一個局部變量定義,如int breakhere = 1
,並查看是否為您提供了一些可以解決的指令。
順便說一句,你可以看到CPU以8位數字的形式思考,所以如果你可以使用char而不是short,它將保存指令。 節省的時間是否值得,取決於機器在此代碼中的時間百分比。
BTW2,如果你想從這只小狗中擠出性能,我在做嵌入式工作時所依賴的是隨機停止IDE(或英特爾“藍盒子”ICE)。 這是關於這一點的。
您通常可以使用#pragma語句調整優化程序。 我不知道編譯器的確切語法,但您應該能夠在編譯器/ ide附帶的文檔中找到它。
像這樣的東西
#pragma optimize( "", off )
//now the function which should not be optimized
#pragma optimize( "", on )
可以如何配置優化是依賴於編譯器的。 SDCC 手冊的優化選項列在第3.28節。 您可以在源代碼級別使用命令行選項或編譯指示。 嘗試全局禁用優化以查看是否獲得相同的效果。 通常在禁用優化的情況下逐步調試調試器中的代碼將消除無法設置斷點的問題。 如果這樣可以正常工作,您可以嘗試使用編譯指示在函數級別禁用可疑優化,以查看哪個可能導致問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.