Mikrodenetleyicilerin RAM'i biterse ne olur?


12

Bu sadece bir tesadüf olabilir, ancak kullandığım mikrodenetleyicilerin RAM'leri bittiğinde yeniden başlattıklarını fark ettim (donanıma özgü ise Atmega 328). Mikrodenetleyiciler hafızası bittiğinde böyle yapar mı? Değilse, ne olur?

Neden nasıl? Yığın işaretçisi kesinlikle körü körüne ayrılmamış bir bellek aralığına yükseltilir (veya devredilir), ancak o zaman ne olur: yeniden başlatmasını sağlayan bir tür koruma var mı veya (diğer efektlerin yanı sıra) veri (hangi ben doğrudan flash çalıştırmak olduğunu düşünüyorum kod farklı varsayalım)?

Bunun burada veya Yığın Taşması üzerinde olması gerektiğinden emin değilim, lütfen donanımın bir rolü olduğundan emin olduğum halde bunun taşınması gerekip gerekmediğini bana bildirin.

Güncelleme

Özellikle bellek bozulmasının arkasındaki gerçek mekanizma ile ilgilendiğimi belirtmeliyim (SP'nin devrilmesinin bir sonucu mu -> bu uC'nin bellek haritalamasına bağlı mı?)?


8
Geçersiz adreslere erişmeye çalışırsanız bazı mikrolar sıfırlanır. Donanımda uygulanan değerli bir özellik. Diğer zamanlarda, mimari bir izin verirse kod yerine verileri yürütmek ve belki de bekçi köpeğinin onu ortaya çıkardığı bir döngüye takılmak, keyfi bir yere atlayabilir (bir ISR için dönüş adresini tıkadığınızı varsayalım). nın-nin.
Spehro Pefhany

2
İşlemcinin RAM'i bitemez, RAM'in tükenmesini sağlayacak bir talimat yoktur. RAM'in bitmesi tamamen bir yazılım konseptidir.
user253751

Yanıtlar:


14

Genel olarak yığın ve yığın birbirine çarpıyor. Bu noktada her şey dağınık hale geliyor.

MCU'ya bağlı olarak birkaç şeyden biri olabilir (veya olacaktır).

  1. Değişkenler bozulur
  2. Yığın bozulur
  3. Program bozulur

1 olduğunda tuhaf davranışlar kazanmaya başlarsınız - işler yapmaları gerekeni yapmazlar. 2 olduğunda her türlü cehennem gevşer. Yığındaki dönüş adresi (varsa) bozuksa, geçerli aramanın geri döneceği yer kimsenin tahminidir. O zaman temelde MCU rastgele şeyler yapmaya başlayacaktır. 3 tekrar olduğunda, ne olacağını kim bilir. Bu yalnızca kodu RAM dışında yürüttüğünüzde olur.

Genel olarak yığın bozulduğunda her şey biter. Sadece olan şey MCU'ya bağlıdır.

Belleği ilk etapta ayırmaya çalışmak başarısızlık olabilir, bu nedenle yolsuzluk olmaz. Bu durumda MCU bir istisna oluşturabilir. Yüklü bir istisna işleyicisi yoksa, çoğu zaman MCU durur (buna eşdeğer while (1);. Yüklü bir işleyici varsa, temiz bir şekilde yeniden başlatılabilir.

Bellek ayırma devam ederse veya denenirse, başarısız olursa ve bellek ayrılmadan devam ederse, "kim bilir?" Âlemlerine girersiniz. MCU, doğru olay kombinasyonuyla kendini yeniden başlatabilir (sonuçta çipin sıfırlanmasına neden olan kesintiler vb.), Ancak bunun gerçekleşeceğine dair bir garanti yoktur.

Genellikle, etkin olma olasılığı yüksek olan, gerçekleşme olasılığı yüksek olan iç izleme zamanlayıcısı (eğer varsa) zaman aşımına uğrar ve çipi yeniden başlatır. Program bu tür bir çökme boyunca tamamen AWOL'a girdiğinde, zamanlayıcıyı sıfırlama talimatları genellikle çalışmaz, bu nedenle zaman aşımına uğrar ve sıfırlanır.


Cevabınız için teşekkürler, etkilerin mükemmel bir özeti. Belki de ben bu bozulmaların gerçek mekanizması hakkında daha fazla ayrıntı istiyorum olsa belirtmeliydim: tüm RAM yığını ve yığın için tahsis, böylece yığın işaretçisi yuvarlanır ve önceki değişkenler / adresler üzerine yazılır? Yoksa bu her mikro bellek hafızasına daha mı az bağımlı? İsteğe bağlı olarak (muhtemelen kendi içinde bir konudur), bu donanım işleyicilerinin nasıl uygulandığını öğrenmek isterim.
Bay Mystère

1
Çoğunlukla derleyiciye ve kullanılan standart C kütüphanesine bağlıdır. Bazen derleyicinin nasıl yapılandırıldığına da bağlıdır (bağlayıcı komut dosyaları, vb.).
Majenko

Bunu belki birkaç örnekle genişletebilir misiniz?
Bay Mystère

Gerçekten değil, hayır. Bazı sistemler farklı segmentler için sonlu alan ayırır, bazıları ise ayırmaz. Bazıları segmentleri tanımlamak için bağlayıcı komut dosyaları kullanır, bazıları kullanmaz. Sizi ilgilendiren bir mikrodenetleyici seçin ve bellek tahsislerinin nasıl çalıştığı hakkında biraz araştırma yapın.,
Majenko

12

Alternatif bir görüş: Mikrodenetleyicilerin belleği kalmaz.

En azından doğru programlandığında değil. Mikrodenetleyiciyi programlamak genel amaçlı programlamaya tam olarak benzemez, düzgün bir şekilde yapabilmek için kısıtlamalarının farkında olmanız ve buna göre programlamanız gerekir. Bunu sağlamaya yardımcı olacak araçlar var. Bunları araştırın ve öğrenin - en azından bağlayıcı komut dosyalarını ve uyarılarını nasıl okuyacağınızı.

Ancak Majenko ve diğerlerinin söylediği gibi, kötü programlanmış bir mikro denetleyicinin belleği tükenebilir ve daha sonra sonsuz döngü de dahil olmak üzere herhangi bir şey yapabilir (en azından bekçi zamanlayıcısına bunu sıfırlama şansı verir. )

Mikrodenetleyiciler için ortak programlama kuralları bundan kaçınır: örneğin, tüm bellek ya yığına ayrılır ya da statik olarak (global olarak) ayrılır; "yeni" veya "malloc" yasaktır. Özyineleme de öyle, böylece altyordam iç içe geçirmenin maksimum derinliği analiz edilebilir ve mevcut yığına sığacak şekilde gösterilebilir.

Bu nedenle, program derlendiğinde veya bağlandığında gereken maksimum depolama alanı hesaplanabilir ve hedeflediğiniz belirli işlemci için bellek boyutu (genellikle bağlayıcı komut dosyasında kodlanır) ile karşılaştırılabilir.

Daha sonra mikro denetleyicinin belleği bitmeyebilir, ancak programınız olabilir. Ve bu durumda,

  • yeniden yaz, daha küçük veya
  • daha büyük bir işlemci seçin (genellikle farklı bellek boyutlarında mevcuttur).

Mikrodenetleyici programlama için yaygın bir kural kümesi , motor endüstrisi tarafından kabul edilen MISRA-C'dir .

Bana göre en iyi uygulama Ada'nın SPARK-2014 alt kümesini kullanmaktır . Ada aslında AVR, MSP430 ve ARM Cortex gibi küçük kontrolörleri makul bir şekilde iyi hedefliyor ve doğal olarak mikrodenetleyici programlama için C'den daha iyi bir model sağlıyor.

Şimdi SPARK araçları, bu ek açıklamalar dahil olmak üzere programı analiz edecek ve onunla ilgili özellikleri kanıtlayacak (veya potansiyel hataları bildirecektir). Hatalı bellek erişimi veya tamsayı taşması ile ilgili zaman veya kod alanı harcamak zorunda değilsiniz çünkü bunların asla gerçekleşmediği kanıtlanmıştır.

SPARK ile ilgili daha fazla ön çalışma olmasına rağmen, deneyim, bir ürüne daha hızlı ve daha ucuza ulaşabileceğini gösteriyor çünkü gizemli yeniden başlatmaları ve diğer garip davranışları kovalamak için zaman harcamıyorsunuz.

MISRA-C ve SPARK karşılaştırması


3
+ 1'leyin. AVR'ye malloc()(ve C ++ arkadaşı new) taşımak, arduino halkının yapabileceği en kötü şeylerden biridir ve hem forumlarında hem de arduino yığın değişiminde bozuk kodlu birçok çok karışık programcıya yol açmıştır. mallocATmega'ya sahip olmanın faydalı olduğu çok ama çok az durum vardır .
Connor Wolf

3
Felsefe için +1, gerçekçilik için -1. İşler düzgün bir şekilde programlanırsa, bu soruya ihtiyaç olmazdı. Soru, mikrodenetleyicilerin belleği dolduğunda ne olacağıydı. Belleğin tükenmesinin nasıl önleneceği başka bir sorudur. Bir başka not, tekrarlama problemleri çözmek için hem güçlü aracıdır ve yığının azalıyor.
PkP

2
@Brian, aptal olmadığım için sana açıkça katılıyorum. Sadece ters bakış açısıyla düşünmeyi seviyorum - umarım, hafızanın (yığın) tükenmesinin korkunç sonuçlarını fark ettiğinizde, bunun olmasını önlemenin yollarını arayacaksınız. Bu şekilde, sadece iyi programlama tavsiyelerine uymak yerine iyi programlama uygulamaları bulmak için gerçek bir itirafınız olur ... ve bellek bariyerine bastığınızda, iyi uygulamaları kolaylık pahasına bile uygulamanız daha olasıdır. Bu sadece bir bakış açısı ...
PkP

2
@PkP: yüksek sesle ve net duyun. Bunu alternatif bir görüş olarak etiketledim - çünkü aslında soruyu cevaplamıyor!
Brian Drummond

2
@ MisterMystère: Mikrodenetleyicilerin belleği genellikle bitmez. İlk kez açıldığında 4096 bayt RAM'e sahip bir mikro denetleyicide 4096 bayt daha fazla olacaktır. Kodun yanlışlıkla var olmayan adreslere erişmeye çalışması veya iki farklı hesaplama adresi yönteminin kullanmadığında farklı belleğe erişmesini beklemesi mümkündür, ancak denetleyicinin kendisi sadece verilen talimatları uygulayacaktır.
Supercat

6

Majenko'nun cevabını gerçekten çok beğendim ve kendim + 1'ledi. Ama bunu keskin bir noktaya açıklığa kavuşturmak istiyorum:

Bir mikro denetleyicinin belleği dolduğunda her şey olabilir.

Gerçekte hiçbir şeye güvenemezsiniz. Makinede yığın bellek bittiğinde, yığın büyük olasılıkla bozulur. Ve bu olduğunda, her şey olabilir. Değişken değerler, dökülmeler, geçici kayıtlar, hepsi bozulur ve program akışlarını bozar. / Then / elses yanlış değerlendirebilirse. Dönüş adresleri bozuk, program rastgele adreslere atlamak. Programda yazdığınız kodlar çalıştırılabilir. ("İf [koşul] sonra {fire_all_missiles ();}" gibi kodu düşünün). Ayrıca talimatlar bir sürü değil çekirdek bir bağlantısız hafıza konuma atlar zaman yürütebilirsiniz yazılı. Bütün bahisler kapalı.


2
Zeyilname için teşekkürler, özellikle fire_all_missiles () satırını beğendim.
Bay Mystère

1

AVR sıfır adresinde vektörü sıfırladı. Rastgele çöp ile yığının üzerine yazdığınızda, sonunda dönecek ve bazı dönüş adreslerinin üzerine yazacaksınız ve "hiçbir yere" işaret etmeyecektir; bir alt programdan başka bir yere geri döndüğünüzde, yürütme genellikle sıfırlama işleyicisinin atlandığı bir adres olan 0 adresine dönecektir.

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.