Gömülü bir program tamamlandığında ne olur?


29

Gömülü bir işlemcide yürütme bu son returnifadeye ulaştığında ne olur Her şey olduğu gibi donuyor; gökyüzünde bir uzun sonsuz NOP ile güç tüketimi vb? veya NOP'lar sürekli yürütülüyor mu, yoksa bir işlemci tamamen kapanacak mı?

Sormamın bir nedeni, bir işlemcinin işlem tamamlanmadan önce gücü kesmesi gerekip gerekmediğini ve elden önce elektrik kesildiyse işlemin bitip bitmediğini merak ediyorum.


22
İnançlarına bağlı. Bazıları onun tekrar doğacağını söylüyor.
Telaclavo

9
Bir füze için mi?
Lee Kowalkowski

6
bazı sistemler HCF (Halt ve Catch Fire) talimatını destekler. :)
Stefan Paul Noack

1
kendi kendini imha etme rutinine

Yanıtlar:


41

Bu, babamın hep bana sorduğu bir soru. “ Neden sadece tüm talimatları yerine getirmiyor ve sonunda bitmiyor?

Patolojik bir örneğe bakalım. Aşağıdaki kod, PIC18 için Microchip'in C18 derleyicisinde derlendi:

void main(void)
{

}

Aşağıdaki assembler çıktısını üretir:

addr    opco     instruction
----    ----     -----------
0000    EF63     GOTO 0xc6
0002    F000     NOP
0004    0012     RETURN 0
.
. some instructions removed for brevity
.
00C6    EE15     LFSR 0x1, 0x500
00C8    F000     NOP
00CA    EE25     LFSR 0x2, 0x500
00CC    F000     NOP
.
. some instructions removed for brevity
.
00D6    EC72     CALL 0xe4, 0            // Call the initialisation code
00D8    F000     NOP                     //  
00DA    EC71     CALL 0xe2, 0            // Here we call main()
00DC    F000     NOP                     // 
00DE    D7FB     BRA 0xd6                // Jump back to address 00D6
.
. some instructions removed for brevity
.

00E2    0012     RETURN 0                // This is main()

00E4    0012     RETURN 0                // This is the initialisation code

Gördüğünüz gibi main () denir ve sonunda bir dönüş ifadesi içerir, ancak açıkça kendimiz koymadık. Ana döndüğünde, CPU kodun başına geri dönmek için sadece GOTO olan bir sonraki komutu çalıştırır. main () sadece tekrar tekrar denir.

Şimdi, bunu söyledikten sonra, bu insanların genellikle işleri yapma şekli değildir. Main () 'in böyle çıkmasına izin verecek herhangi bir gömülü kod yazmadım. Çoğunlukla, kodum şuna benzer:

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

Böylece normalde main () 'in çıkmasına asla izin vermem.

"Tamam tamam" diyorsun. Tüm bunlar, derleyicinin asla son bir dönüş beyanı olmadığından emin olmasını çok ilginç. Ama konuyu zorlarsak ne olur? El montajcımı kodladıysam ve en başa bir sıçrama yapmadıysa?

Belli ki CPU bir sonraki talimatları yerine getirmeye devam edecek. Şunun gibi bir şeye benzeyeceklerdi:

addr    opco     instruction
----    ----     -----------
00E6    FFFF     NOP
00E8    FFFF     NOP
00EA    FFFF     NOP
00EB    FFFF     NOP
.
. some instructions removed for brevity
.
7EE8    FFFF     NOP
7FFA    FFFF     NOP
7FFC    FFFF     NOP
7FFE    FFFF     NOP

Main () 'deki son komuttan sonra bir sonraki hafıza adresi boştur. FLASH belleğe sahip bir mikrodenetleyicide, boş bir komut 0xFFFF değerini içerir. En azından bir PIC'de, bu op kodu bir "hayır" veya "işlem yok" olarak yorumlanır. Bu sadece hiçbir şey yapmaz. CPU bu nops'ları bellekten sonuna kadar yürütmeye devam edecektir.

Bundan sonra ne var?

Son komutta, CPU'nun talimat göstericisi 0x7FFe'dir. CPU, komut göstergesine 2 eklediğinde, yalnızca 32k FLASH ile bir PIC'de taşma olarak kabul edilen 0x8000 değerini alır ve böylece 0x0000'e geri sarılır ve CPU mutlu bir şekilde kodun başlangıcında talimatları yerine getirmeye devam eder. , tıpkı sıfırlanmış gibi.


Ayrıca güç kapatmanın gerekliliği hakkında da sorular sordunuz. Temelde ne istersen yapabilirsin, ve bu uygulamana bağlı.

Açtıktan sonra yalnızca bir şeyi yapmanız gereken bir uygulamanız varsa ve sonra bir süre koyabileceğiniz başka bir şey yapmazsanız (1); main'in sonunda () CPU dikkat çeken bir şey yapmayı bırakır.

Uygulama CPU'nun kapanmasını gerektiriyorsa, CPU'ya bağlı olarak, muhtemelen çeşitli uyku modları olacaktır. Ancak, CPU'ların tekrar uyanma alışkanlığı vardır, bu nedenle uyku için zaman sınırı olmadığından ve Watch Dog Timer'ın aktif olmadığından emin olmalısınız.

İşlem tamamlandıktan sonra CPU'nun kendi gücünü tamamen kesmesini sağlayacak bazı harici devreler bile organize edebilirsiniz. Bu soruya bakın: Mandal açma açma / kapatma düğmesi olarak anlık bir buton kullanma .


20

Derlenmiş kod için derleyiciye bağlıdır. Kullandığım Rowley CrossWorks gcc ARM derleyicisi sonsuz döngüye sahip crt0.s dosyasında kodlamak için atlar. 16-bit dsPIC ve PIC24 cihazları için Microchip C30 derleyicisi (ayrıca gcc'ye dayalı) işlemciyi sıfırlar.

Tabii ki, çoğu gömülü yazılım asla bu şekilde sona ermez ve kodu bir döngü içinde sürekli olarak çalıştırır.


13

Burada yapılması gereken iki nokta var:

  • Gömülü bir program, kesinlikle konuşma, "bitiremez".
  • Bir süre gömülü bir program çalıştırmak ve daha sonra "bitirmek" için çok nadiren ihtiyaç vardır.

Bir program kapatma kavramı normalde gömülü bir ortamda yoktur. Düşük düzeyde bir CPU, yapabildiği sırada talimatları yürütür; “nihai geri dönüş bildirimi” diye bir şey yoktur. Bir kurtarılamaz hatayla karşılaşırsa veya açıkça durdurulursa (bir uyku kipine, düşük güç kipine vb. Takılırsa) bir CPU yürütmeyi durdurabilir; idam edilecek. Uyku modlarından uyanabilirsiniz (normal şekilde kullanılırlar) ve kilitli bir CPU bile hala bir NMI işleyicisi yürütebilir (Cortex-M için geçerlidir). Bir bekçi köpeği de çalışmaya devam edecek ve bazı mikroişlemcilerde etkinleştirildikten sonra onu devre dışı bırakamayabilirsiniz. Detaylar mimariler arasında büyük farklılıklar gösterir.

C veya C ++ gibi bir dilde yazılmış bellenim durumunda, main () çıkarsa ne olur başlangıç ​​kodu tarafından belirlenir. Örneğin, STM32 Standart Çevre Birimi Kütüphanesi'ndeki başlangıç ​​kodunun ilgili kısmı (GNU alet zinciri için, yorumlar benimdir):

Reset_Handler:  
  /*  ...  */
  bl  main    ; call main(), lr points to next instruction
  bx  lr      ; infinite loop

Bu kod sonsuz döngüye girer zaman main (), her ne kadar belli olmayan bir şekilde ( bl mainyükler lrkendisi etkili bir atlama sonraki talimat adresiyle birlikte). CPU'yu durdurmak veya düşük güç moduna sokmak için hiçbir girişimde bulunulmaz, vb. Uygulamanızın herhangi birine meşru bir gereksiniminiz varsa, bunu kendiniz yapmanız gerekecektir.

ARMv7-M ARM A2.3.1'de belirtildiği gibi, bağlantı kaydının sıfırlama sırasında 0xFFFFFFFF olarak ayarlandığını ve bu adresin bir dalın bir hata tetikleyeceğini unutmayın. Böylece Cortex-M tasarımcıları sıfırlama işleyicisinden dönüşü anormal olarak görmeye karar verdiler ve onlarla tartışmak zor.

Yazılım bittikten sonra işlemciyi durdurmak için meşru bir ihtiyaçtan bahsetmişken, cihazınızın güçsüzlüğüyle daha iyi hizmet edilemeyeceklerini hayal etmek zor. (İşlemcinizi "iyi" olarak devre dışı bırakırsanız, cihazınıza yapılabilecek tek şey bir güç döngüsü veya harici donanım sıfırlamasıdır.) DC / DC dönüştürücünüz için bir ENABLE sinyali atayabilir veya güç kaynağınızı kapatıp açabilirsiniz. başka bir şekilde, bir ATX PC gibi.


1
"Uyku modlarından uyanabilirsiniz (normalde bu şekilde kullanılırlar) ve kilitli bir CPU bile hala bir NMI işleyicisi yürütebilir (Cortex-M için böyledir)." Bir kitap veya film arsa. :)
Mark Allen

"Bl main", aşağıdaki talimatın adresiyle ("bx lr") "lr" yükleyecektir, değil mi? “Br” yürütülürken “lr” nin başka bir şey içermesini beklemenin bir nedeni var mı?
supercat,

@supercat: Tabii ki haklısın. Hatayı düzeltmek ve biraz genişletmek için cevabımı düzenledim. Bunu düşünerek, bu döngüyü uygulama şekilleri oldukça garip; kolayca yapabilirlerdi loop: b loop. Acaba geri dönüş yapmak istiyorlardı ama kurtarmayı unuttular mı merak ediyorum lr.
Thorn

Bu meraklı. Girişte tuttuğu değeri tutan LR ile çok sayıda ARM kodunun çıkmasını beklerdim, ancak bunun garantili olduğunu bilmiyordum. Böyle bir garanti çoğu zaman yararlı olmaz, ancak bunun yerine getirilmesi r14'ü başka bir sicile kopyalayan ve daha sonra başka bir rutin olarak adlandırılan rutinlere bir talimat eklenmesini gerektirir. İade edildiğinde "bilinmeyen" sayılırsa, kaydedilen kopyayı tutan kayıt "bx" olabilir. Bununla birlikte, belirtilen kodla çok garip davranışlara neden olacaktır.
supercat

Aslına bakılırsa, yaprak dışı fonksiyonların lr tasarrufu sağlaması bekleniyor. Bunlar genellikle prologdaki yığına lr basar ve kaydedilen değeri pc'ye sokarak geri döner. Bu, örneğin bir C veya C ++ main () 'in yapacağı şeydir, ancak söz konusu kütüphanenin geliştiricileri açıkça Reset_Handler'da böyle bir şey yapmadı.
Thorn,

9

Hakkında soru sorurken return, çok yüksek bir seviyede düşünüyorsun. C kodu makine koduna çevrilmiştir. Öyleyse, işlemciyi kör bir şekilde bellekten yönergeleri çıkartarak ve yürütmeyi düşünüyorsanız, hangisinin "son" olduğu hakkında hiçbir fikri yoktur.return . Bu nedenle, işlemcilerin doğal bir sonu yoktur, ancak bunun yerine, son durumu ele almak programlayıcıya bağlıdır. Leon'un cevabında işaret ettiği gibi, derleyiciler varsayılan bir davranış programlamışlardır, ancak çoğu zaman programcı kendi kapanma sırasını isteyebilir (düşük güç moduna girme ve durma ya da USB kablosunun takılmasını beklemek gibi çeşitli şeyler yaptım) içinde ve sonra yeniden başlatılıyor).

Pek çok mikroişlemci, işlemciyi perhiperalleri etkilemeden durduran talimatları durdurur. Diğer işlemciler sadece tekrar tekrar aynı adrese atlayarak "durma" ya güvenebilirler. Seçenekler olabilir, ancak bu programcıya bağlıdır, çünkü işlemci hafızanın talimat olmaya niyetli olmasa bile, sadece talimatları okumaya devam edecektir.


7

Sorun gömülü değil (gömülü bir sistem Linux ya da hatta Windows çalıştırabilir) ancak tek başına ya da çıplak metal: (derlenmiş) uygulama programı bilgisayarda çalışan tek şeydir (sorun olup olmadığı önemli değil) mikrodenetleyici veya mikroişlemci).

Çoğu dil için dil, 'main' sona erdiğinde ne olacağını ve geri dönecek bir işletim sistemi olmadığında ne olacağını tanımlamaz. C için başlangıç ​​dosyasındakilere (genellikle crt0.s) bağlıdır. Çoğu durumda, kullanıcı başlangıç ​​kodunu sağlayabilir (hatta gerekir), bu nedenle son cevap: yazdığınız her şey başlangıç ​​kodudur veya belirttiğiniz başlangıç ​​kodunda ne olur.

Uygulamada 3 yaklaşım vardır:

  • özel bir önlem alma. Ana geri dönüşler tanımsız olduğunda ne olur?

  • 0'a atlayın veya uygulamayı yeniden başlatmak için başka bir yol kullanın.

  • İşlemciyi sonsuza dek kilitleyen sıkı bir döngü (veya devre dışı bırakma ve durma komutunu uygulamadan devre dışı bırakma komutu) girin.

Uygun olan uygulamaya bağlıdır. Fur-elise tebrik kartı ve bir fren kontrol sistemi (sadece iki gömülü sistemden bahsetmek gerekir) muhtemelen yeniden başlatılmalıdır. Yeniden başlatmanın dezavantajı, sorunun farkedilmemesi olabilir.


5

Geçen gün demonte edilmiş bazı ATtiny45'lere bakıyordum (C ++ avr-gcc tarafından derlendi) ve geçen günün sonunda kodun sonunda 0x0000'e atlıyor. Temelde sıfırlama / yeniden başlatma yapıyor.

0x0000’e yapılan son atlama derleyici / assembler tarafından bırakılıyorsa, program belleğindeki tüm baytlar 'geçerli' makine kodu olarak yorumlanır ve program sayacı 0x0000’e kadar gelene kadar çalışır.

AVR'de bir 00 bayt (bir hücre boş olduğunda varsayılan değer) bir NOP = İşlem Yok. Bu yüzden gerçekten hızlı çalışır, hiçbir şey yapmaz, sadece biraz zaman alır.


1

Genel olarak derlenmiş mainkod daha sonra başlangıç ​​koduyla ilişkilendirilir (yonga satıcısı tarafından sağlanan, sizin tarafınızdan yazılmış vb. Araç zincirine entegre edilebilir).

Bağlayıcı daha sonra tüm uygulamaları ve başlangıç ​​kodlarını bellek parçalarına yerleştirir, bu nedenle size verilen soruların cevapları aşağıdakilere bağlıdır: 1. başlangıçtan itibaren gelen kod, örneğin:

  • "program sonu" ile benzer olacak, ancak daha önce etkin olan kesintiler ve çevre birimlerinin çalışmaya devam edeceği boş döngü ( bl lrveya b .) ile sona erecek,
  • programın başlangıcına atla (bitişi tamamen yeniden başlat veya jsut a main).
  • sadece maingeri dönüş çağrısından sonra "ne olacak" yoksayın .

    1. Üçüncü mermide, program sayacı maindavranıştan döndükten sonra basit bir şekilde artışın size bağlayıcınıza (ve / veya bağlanma sırasında kullanılan bağlayıcı komut dosyasına) bağlı olması gerekir.
  • Eğer sizden sonra başka bir fonksiyon / kod yerleştirilirse main, geçersiz / tanımsız argüman değerleri ile çalıştırılacaktır.

  • Eğer takip eden bellek hatalı komut istisnasıyla başlarsa çok az üretilir ve MCU sonunda sıfırlanır (istisna sıfırlama oluşturursa).

Bekçi uygulaması etkinse, içinde bulunduğunuz tüm sonsuz döngülere rağmen sonunda MCU'yu sıfırlar (tabii ki yeniden yüklenmezse).


-1

Gömülü bir cihazı durdurmanın en iyi yolu NOP talimatları ile sonsuza kadar beklemektir.

İkinci yol, cihazın kendisini kullanarak cihazı kapatmaktır. Eğer talimatları ile bir röle kontrol edebilirsiniz, sadece gömülü cihaz açılıyor ve anahtarı açabilirsiniz ha gömülü cihaz herhangi bir güç tüketimi ile gitti.


That really doesn't answer the question.
Matt Young

-4

It was clearly explained in the manual. Typically an general exception will be 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't need to manually turn it off.

Read the ACPI specification for more information.


3
-1 : the TS did not mention any specific CPU, so don't assume too much. Different systems handle this case in very different ways.
Wouter van Ooijen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.