題:
嵌入式程序完成後會發生什麼?
Toby
2012-04-27 23:10:03 UTC
view on stackexchange narkive permalink

What happens in an embedded processor when execution reaches that final return statementDoes everything just freeze as it is; power consumption etc, with one long eternal NOP in the sky? or are NOPs continuously executed, or will a processor shut down altogether?

Part of the reason I ask is I am wondering if a processor needs to power down before it finishes execution and if it does how does it ever finish execution if it has powered down before hand?

這取決於您的信念。有人說它將輪迴。
是導彈嗎?
某些系統支持[HCF(暫停並著火)](http://en.wikipedia.org/wiki/Halt_and_Catch_Fire)指令。 :)
它會分支到自我破壞的例行程序
九 答案:
Rocketmagnet
2012-04-28 01:46:59 UTC
view on stackexchange narkive permalink

這是我父親一直問我的問題。 “ 為什麼不只執行所有指令並在最後停下來?

我們來看一個病理示例。以下代碼是在Microchip的PIC18的C18編譯器中編譯的:

  void main(void){}  

它會產生以下彙編輸出:

  addr opco指令---- ---- ----------- 0000 EF63 GOTO 0xc60002 F000 NOP0004 0012返回0 ..為簡潔起見,刪除了一些指令.00C6 EE15 LFSR 0x1,0x50000C8 F000 NOP00CA EE25 LFSR 0x2,0x50000CC F000 NOP ..為簡潔起見刪除了一些指令.00D6 EC72 CALL 0xe4,0 //調用初始化代碼00D8 F000 NOP // 00DA EC71 CALL 0xe2,0 //在這裡我們稱為main() 00DC F000 NOP // // 00DE D7FB BRA 0xd6 //跳轉回地址00D6 ..為了簡潔起見刪除了一些指令.00E2 0012 RETURN 0 //這是main()00E4 0012 RETURN 0 //這是初始化代碼

如您所見,main()i稱為,最後包含一個return語句,儘管我們自己沒有明確地將它放在那裡。當main返回時,CPU執行下一條指令,即GOTO,返回到代碼的開頭。簡單地反複調用main()。

現在,儘管如此,這不是人們通常會做的事情。我從未寫過任何允許main()退出的嵌入式代碼。通常,我的代碼如下所示:

  void main(void){while(1){wait_timer(); do_some_task(); }}  

所以我通常不會讓main()退出。

您說“好吧好”。所有這些非常有趣,因為編譯器確保永遠不會有最後一個return語句。但是,如果我們強制執行該問題會怎樣?如果我手工編碼了我的彙編程序,但又沒有跳回開頭怎麼辦?

很明顯,CPU只會繼續執行下一條指令。看起來像這樣:

  addr opco指令---- ---- ----------- 00E6 FFFF NOP00E8 FFFF NOP00EA FFFF NOP00EB FFFF NOP ..為簡潔起見,刪除了一些指令。7EE8FFFF NOP7FFA FFFF NOP7FFC FFFF NOP7FFE FFFF NOP  

main()中最後一條指令之後的下一個內存地址為空。在具有閃存的微控制器上,空指令包含值0xFFFF。至少在PIC上,該操作碼被解釋為“ nop”或“ no operation”。它根本什麼也沒做。 CPU將從內存一直一直執行到所有末尾。

這之後是什麼?

在最後一條指令中,CPU的指令指針為0x7FFe。當CPU在其指令指針上加2時,它得到0x8000,這在只有32k FLASH的PIC上被認為是溢出,因此它迴繞回0x0000,CPU高興地在代碼開始處繼續執行指令,就像已將其重置一樣。


您還詢問了是否需要關機。基本上,您可以做任何您想做的事,這取決於您的應用程序。

如果您確實有一個應用程序,該應用程序在開機後只需要做一件事,然後什麼也不做,那麼您就可以放一會兒(1);在main()的末尾,以便CPU停止執行任何明顯的操作。

如果應用程序需要關閉CPU的電源,則取決於CPU,可能會有各種可用的睡眠模式。但是,CPU有重新喚醒的習慣,因此您必須確保睡眠沒有時間限制,也沒有看門狗定時器處於活動狀態,等等。

您甚至可以組織一些外部設備。電路完成後,將允許CPU完全切斷自身的電源。看到以下問題:使用瞬時按鈕作為閂鎖開關按鈕

Leon Heller
2012-04-27 23:22:29 UTC
view on stackexchange narkive permalink

對於已編譯的代碼,它取決於編譯器。我使用的Rowley CrossWorks gcc ARM編譯器跳轉到具有無限循環的crt0.s文件中進行編碼。用於16位dsPIC和PIC24器件(也基於gcc)的Microchip C30編譯器會復位處理器。 / p>

Thorn
2012-04-28 00:51:05 UTC
view on stackexchange narkive permalink

這裡有兩點要指出:

  • 嚴格來說,嵌入式程序無法“完成”。
  • 很少需要運行嵌入式程序運行一段時間,然後“完成”。

程序關閉的概念通常在嵌入式環境中不存在。在較低級別上,CPU將在可能的情況下執行指令。沒有“最終回報聲明”之類的東西。如果CPU遇到不可恢復的錯誤或被明確地暫停(進入睡眠模式,低功耗模式等),則可能會停止執行,但是請注意,即使是睡眠模式或不可恢復的錯誤也通常不能保證不再有代碼要執行被執行。您可以從睡眠模式中喚醒(這是它們通常的使用方式),甚至鎖定的CPU仍可以執行NMI處理程序(Cortex-M就是這種情況)。看門狗也仍將運行,並且一旦啟用,您可能無法在某些微控制器上將其禁用。架構之間的細節差異很大。如果要確保某些行為(請參閱下面的原因,無論如何都不應該嘗試這樣做),則需要非常仔細地閱讀相關手冊。

如果固件以諸如C或C ++,如果main()退出,將發生什麼情況由啟動代碼確定。例如,這是STM32標準外設庫中啟動代碼的相關部分(對於GNU工具鏈,註釋是我的):

  Reset_Handler:/ * ... * / bl main ;調用main(),lr指向下一條指令bx lr;無限循環 

該代碼將在main()返回時進入無限循環,儘管以一種非顯而易見的方式( bl main 加載 lr 代碼>,其中包含下一條指令的地址,該地址實際上是對自身的跳轉)。不會嘗試停止CPU或使其進入低功耗模式,等等。如果您在應用程序中有對此的合理需求,您將必須自己做。

請注意,如ARMv7-M ARM A2.3.1中所指定,在復位時,鏈接寄存器被設置為0xFFFFFFFF,並且分支到該地址將觸發故障。因此,Cortex-M的設計者決定將重置處理程序的返回視為異常,因此很難與他們爭論。

說到在固件完成後停止CPU的合法需求,這是很難想像通過關閉設備電源無法更好地解決任何問題。 (如果您確實永久禁用了CPU,則只能對設備執行以下操作:關機後再開機或外部硬件復位。)您可以取消DC / DC轉換器的ENABLE信號置為有效,或關閉電源就像ATX PC一樣。

“您可以從睡眠模式中喚醒(這是它們通常的使用方式),甚至被鎖定的CPU仍然可以執行NMI處理程序(Cortex-M就是這種情況。)“-聽起來像是一本書或電影情節。 :)
“ bl main”將使用以下指令的地址(“ bx lr”)加載“ lr”,不是嗎?執行“ bx lr”時,是否有任何理由期望“ lr”包含其他內容?
@supercat:當然是正確的。我編輯了答案,以消除錯誤並將其擴大一點。考慮到這一點,他們實現此循環的方式非常奇怪。他們可以很容易地完成“ loop:b loop”。我想知道他們是否真的打算退貨,卻忘記保存`lr`。
很好奇我希望很多ARM代碼會在LR保持與輸入時保持相同的值的情況下退出,但不知道這是可以保證的。這樣的保證通常不會有用,但是要堅持下去,則需要向例程添加一條指令,該例程將r14複製到其他寄存器,然後調用其他例程。如果lr在返回時被視為“未知”,則可以“ bx”保存已保存副本的寄存器。但是,這將導致所指示的代碼非常奇怪的行為。
實際上,我非常確定非葉函數可以節省lr。這些通常將lr推入序言中的堆棧,然後通過將保存的值彈出到pc中返回。這就是例如C或C ++ main()可以做到,但是有問題的庫的開發人員顯然沒有在Reset_Handler中做任何類似的事情。
@Thorn:我想知道方法返回的返回頻率等於返回地址的頻率是多少,如果方法使用STM來保存多個包含LR的寄存器,則最便宜的還原方法是使用PC而不是LR的LDM。
Klox
2012-04-28 00:18:09 UTC
view on stackexchange narkive permalink

When asking about return, you're thinking too high level. The C code is translated into machine code. So, if you instead think about the processor blindly pulling instructions out of memory and executing them, it has no idea which one is the "final" return. So, processors have no inherent end, but instead it's up to the programmer to handle the end case. As Leon points out in his answer, compilers have programmed a default behavior, but often times the programmer may want their own shutdown sequence (I have done various things like entering a low power mode and halting, or waiting for a USB cable to get plugged in and then rebooting).

Many microprocessors have halt instructions, which stops the processor without affecting perhiperals. Other processors may rely on "halting" by simply just jumping to the same address repeatedly. There are may options, but it's up to the programmer because the processor will simply keep reading instructions from meory, even if that memory wasn't intented to be instructions.

Wouter van Ooijen
2012-04-28 17:27:42 UTC
view on stackexchange narkive permalink

問題不是嵌入式的(嵌入式系統可以運行Linux甚至Windows),而是獨立的或裸機的:(已編譯的)應用程序是計算機上唯一運行的程序(是否

對於大多數語言,該語言都沒有定義當“ main”終止並且沒有操作系統可返回時發生的情況。對於C,它取決於啟動文件中的內容(通常為crt0.s)。在大多數情況下,用戶可以(甚至必須)提供啟動代碼,所以最終的答案是:無論您寫的是啟動代碼,還是指定的啟動代碼中發生的事情。

在練習有3種方法:

  • 不採取特殊措施。

  • 跳轉到0,或使用任何其他方式重新啟動應用程序。

  • 進入一個緊密的循環(或禁用中斷並執行暫停指令),永遠鎖定處理器。

合適的方法取決於應用程序。精美的賀卡和製動控制系統(僅提及兩個嵌入式系統)應該重新啟動。重新啟動的弊端是該問題可能未被注意到。

jippie
2012-04-28 01:13:54 UTC
view on stackexchange narkive permalink

前幾天,我正在看一些反彙編的ATtiny45代碼(由avr-gcc編譯的C ++),代碼末尾的代碼跳到0x0000。基本上是進行重置/重新啟動。

如果編譯器/彙編器忽略了最後一次跳轉到0x0000的操作,則程序存儲器中的所有字節均被解釋為“有效”機器代碼,並且一直運行直到程序計數器翻轉到0x0000。

在AVR上,一個00字節(單元格為空時的默認值)為NOP = No Operation。因此,它運行得非常快,只花了一些時間就什麼也不做。

kwesolowski
2014-08-09 02:16:51 UTC
view on stackexchange narkive permalink

通常將已編譯的 main 代碼與啟動代碼鏈接起來(它可能集成到工具鏈中,由芯片供應商提供,由您自己編寫,等等)。

鏈接器然後放置內存段中的所有應用程序和啟動代碼,因此對您的問題的答案取決於:1。啟動代碼,因為它可以例如:

  • 以空循環結尾( bl lr b。),這將類似到“程序結束”,但先前啟用的中斷和外圍設備仍然可以運行,
  • 以跳轉到程序開頭(完全重新運行啟動程序或jsut到 main )結束。
  • 在調用 main 返回後,只需忽略“下一步將是什麼”。

    1. 在第三個項目符號中,當程序計數器簡單時從 main 返回的行為後的增量取決於您的鏈接器(和/或鏈接期間使用的鏈接器腳本)。
    2. ol>
  • 如果使用其他功能/ code放在您的 main 之後,它將使用無效/未定義的參數值執行。

  • 如果後續存儲器以錯誤的指令異常開始,則可能會生成並且MCU將最終重置(如果異常產生了重置)。

如果啟用了看門狗,則儘管存在所有無窮循環,它仍將最終重置MCU。您已經進入了(當然不會重新加載)。

Enes Unal
2014-12-23 19:26:15 UTC
view on stackexchange narkive permalink

停止嵌入式設備的最佳方法是使用NOP指令永遠等待。

第二種方法是使用設備本身來關閉設備。如果您可以按照說明控制繼電器,則只需打開為嵌入式設備供電的開關,呵呵嵌入式設備就沒電了。

那真的不能回答問題。
Standard Sandun
2012-04-27 23:23:12 UTC
view on stackexchange narkive permalink

It was clearly explained in the manual. Typically an general exception willbe thrown by the CPU because it will access a memory location which is outside the stack segment. [ memory protection exception ].

What did you meant by the embedded system?Microprocessor or microcontroller ?Either ways , it's defined on the manual.

In x86 CPU we turn off the computer by sending the command to the ACIP controller.Entering the System Management Mode. So that controller is a I/O chip and you don'tneed to manually turn it off.

Read the ACPI specification for more information.

-1:TS沒有提及任何特定的CPU,因此不要承擔太多。不同的系統以非常不同的方式處理這種情況。


該問答將自動從英語翻譯而來。原始內容可在stackexchange上找到,我們感謝它分發的cc by-sa 3.0許可。
Loading...