Co się stanie, gdy w mikrokontrolerach skończy się pamięć RAM?

12

To może być tylko zbieg okoliczności, ale zauważyłem, że mikrokontrolery, których użyłem, uruchomiły się ponownie, gdy zabrakło pamięci RAM (Atmega 328, jeśli jest specyficzna dla sprzętu). Czy to właśnie robią mikrokontrolery, gdy zabraknie im pamięci? Jeśli nie, co się wtedy stanie?

Dlaczego / jak Wskaźnik stosu jest z pewnością ślepo zwiększony do nieprzydzielonego zakresu pamięci (lub przywrócony), ale co się wtedy dzieje: czy istnieje jakiś rodzaj ochrony, który powoduje, że restartuje się, czy jest to (między innymi efektem) wynik zastąpienia krytycznego dane (które, jak zakładam, różnią się od kodu, który moim zdaniem jest uruchamiany bezpośrednio z pamięci flash)?

Nie jestem pewien, czy powinno to być tutaj, czy w przypadku przepełnienia stosu, daj mi znać, czy powinno to zostać przeniesione, chociaż jestem pewien, że sprzęt ma w tym rolę.

Aktualizacja

Powinienem zwrócić uwagę, że jestem szczególnie zainteresowany faktycznym mechanizmem powodującym uszkodzenie pamięci (czy jest to wynikiem przewracania się SP -> czy to zależy od mapowania pamięci uC itp.)?

Pan Mystère
źródło
8
Niektóre mikrosy zostaną zresetowane, jeśli spróbujesz uzyskać dostęp do nieprawidłowych adresów. Jest to cenna funkcja zaimplementowana w sprzęcie. Innym razem może skończyć się przeskakiwaniem do dowolnego miejsca (powiedzmy, że zablokowałeś adres zwrotny dla ISR), być może wykonując dane, a nie kod, jeśli architektura na to pozwala, i być może złapany w pętlę, którą organ nadzorujący wyprowadza z niego z.
Spehro Pefhany
2
Procesorowi nie może zabraknąć pamięci RAM, nie ma instrukcji, która sprawi, że zabraknie pamięci RAM. Brak pamięci RAM jest całkowicie koncepcją oprogramowania.
user253751,

Odpowiedzi:

14

Ogólnie stos i sterty zderzają się ze sobą. W tym momencie robi się bałagan.

W zależności od MCU może się zdarzyć jedna z kilku rzeczy.

  1. Zmienne ulegają uszkodzeniu
  2. Stos zostanie uszkodzony
  3. Program ulega uszkodzeniu

Kiedy 1 zdarza się, zaczynasz zachowywać się dziwnie - rzeczy nie robią tego, co powinny. Kiedy zdarza się 2, piekło się rozprasza. Jeśli adres zwrotny na stosie (jeśli taki istnieje) jest uszkodzony, to miejsce, do którego wróci bieżące połączenie, jest zgadywaniem. W tym czasie zasadniczo MCU zacznie robić losowe rzeczy. Kiedy 3 powtórzy się, kto wie, co by się stało. Dzieje się tak tylko wtedy, gdy kod jest wykonywany poza pamięcią RAM.

Zasadniczo, gdy stos ulega uszkodzeniu, wszystko się kończy. To, co się dzieje, zależy od MCU.

Może się zdarzyć, że próba alokacji pamięci nie powiedzie się, więc nie nastąpi uszkodzenie. W takim przypadku MCU może zgłosić wyjątek. Jeśli nie ma zainstalowanego modułu obsługi wyjątków, to najczęściej MCU po prostu zatrzymuje się (odpowiednik while (1);. Jeśli zainstalowany jest moduł obsługi, to może zostać ponownie uruchomiony ponownie.

Jeśli alokacja pamięci będzie postępować, lub jeśli spróbuje, nie powiedzie się, a po prostu będzie kontynuowana bez przydzielonej pamięci, to przejdziesz do sfery „kto wie?”. MCU może się zrestartować przez odpowiednią kombinację zdarzeń (przerwania spowodowały zresetowanie układu itp.), Ale nie ma gwarancji, że tak się stanie.

To, co zwykle może mieć duże prawdopodobieństwo, to jednak, jeśli jest włączone, wewnętrzny licznik czasu watchdoga (jeśli taki istnieje) odlicza limit czasu i restartuje układ. Kiedy program przechodzi całkowicie w stan AWOL przez tego rodzaju awarię, instrukcje resetowania timera na ogół nie zostaną uruchomione, więc upłynie limit czasu i nastąpi reset.

Majenko
źródło
Dzięki za odpowiedź, jest to doskonałe podsumowanie efektów. Być może powinienem był jednak sprecyzować, że chciałbym uzyskać więcej szczegółów na temat faktycznego mechanizmu tych zepsuć: czy cała pamięć RAM jest przeznaczona na stos i stos, tak że wskaźnik stosu przewraca się i zastępuje wcześniejsze zmienne / adresy? A może jest to mniej zależne od mapowania pamięci każdej mikro? Opcjonalnie (prawdopodobnie jest to sam w sobie temat), chciałbym dowiedzieć się, jak zaimplementowano te procedury obsługi sprzętu.
Mister Mystère,
1
Jest to głównie zależne od kompilatora i używanej standardowej biblioteki C. Czasami zależy to również od konfiguracji kompilatora (skrypty linkera itp.).
Majenko,
Czy mógłbyś rozwinąć tę kwestię, być może z kilkoma przykładami?
Mister Mystère,
Nie, naprawdę nie. Niektóre systemy przydzielają skończone miejsce dla różnych segmentów, niektóre nie. Niektórzy używają skryptów linkera do definiowania segmentów, inni nie. Wybierz interesujący Cię mikrokontroler i
zbadaj,
12

Alternatywny widok: w mikrokontrolerach nie brakuje pamięci.

Przynajmniej nie po prawidłowym zaprogramowaniu. Programowanie mikrokontrolera nie jest dokładnie tak samo jak programowanie ogólnego przeznaczenia, aby zrobić to poprawnie, musisz być świadomy jego ograniczeń i odpowiednio programować. Istnieją narzędzia, które pomogą to zapewnić. Wyszukaj je i naucz się - przynajmniej jak czytać skrypty linkera i ostrzeżenia.

Jednak, jak mówią Majenko i inni, źle zaprogramowanemu mikrokontrolerowi może zabraknąć pamięci, a następnie zrobić cokolwiek, w tym nieskończoną pętlę (co przynajmniej daje zegarowi nadzorującemu szansę na jego zresetowanie. Włączyłeś zegar nadzoru, prawda? )

Wspólne reguły programowania mikrokontrolerów unikają tego: na przykład cała pamięć jest albo przydzielana na stosie, albo statycznie (globalnie) przydzielana; „nowe” lub „malloc” są zabronione. Podobnie jest z rekurencją, aby maksymalna głębokość zagnieżdżenia podprogramu mogła zostać przeanalizowana i pokazana, aby pasowała do dostępnego stosu.

Zatem maksymalną wymaganą pamięć można obliczyć, gdy program jest kompilowany lub połączony, i porównać z wielkością pamięci (często zakodowaną w skrypcie linkera) dla konkretnego procesora, na który celujesz.

Wtedy mikrokontroler może nie zabraknąć pamięci, ale twój program może. I w takim przypadku dojdziesz do

  • przepisz to, mniejsze lub
  • wybierz większy procesor (często są one dostępne z różnymi rozmiarami pamięci).

Jednym wspólnym zestawem zasad programowania mikrokontrolerów jest MISRA-C , przyjęty przez przemysł motoryzacyjny.

Moim zdaniem najlepszą praktyką jest korzystanie z podzestawu Ady SPARK-2014 . Ada faktycznie atakuje stosunkowo małe kontrolery, takie jak AVR, MSP430 i ARM Cortex, i z natury zapewnia lepszy model programowania mikrokontrolera niż C. Jednak SPARK dodaje do programu adnotacje w formie komentarzy, które opisują jego działanie.

Teraz narzędzia SPARK przeanalizują program, w tym te adnotacje, i udowodnią jego właściwości (lub zgłoszą potencjalne błędy). Nie musisz marnować czasu ani miejsca na kod, zajmując się błędnym dostępem do pamięci lub przepełnieniem liczb całkowitych, ponieważ udowodniono, że nigdy się nie zdarzają.

Chociaż SPARK wymaga więcej pracy z góry, doświadczenie pokazuje, że może dostać się do produktu szybciej i taniej, ponieważ nie spędzasz czasu na tajemniczych restartach i innych dziwnych zachowaniach.

Porównanie MISRA-C i SPARK

Brian Drummond
źródło
3
+1 to. Przeniesienie malloc()(i towarzyszącego mu C ++ new) do AVR jest jedną z najgorszych rzeczy, które ludzie arduino mogliby zrobić, i doprowadziło do wielu, wielu bardzo zdezorientowanych programistów ze złamanym kodem zarówno na forum, jak i wymianie stosu arduino. Jest bardzo, bardzo niewiele sytuacji, w których posiadanie mallocATmega jest korzystne.
Connor Wolf,
3
+1 za filozofię, -1 za realizm. Jeśli rzeczy byłyby odpowiednio zaprogramowane, to pytanie nie byłoby potrzebne. Pytanie brzmiało, co się stanie, gdy w mikrokontrolerach zabraknie pamięci. Jak zapobiec wyczerpaniu się pamięci, to kolejne pytanie. Z drugiej strony rekurencja jest potężnym narzędziem, zarówno do rozwiązywania problemów, jak i do wyczerpania stosu.
PkP
2
@Brian, ponieważ jestem nie idiotą I oczywiście zgadzam się z tobą. Po prostu lubię o tym myśleć w odwrotnym kierunku - mam nadzieję, że kiedy zdasz sobie sprawę z okropnych konsekwencji braku pamięci (stosu), będziesz szukał sposobów, aby temu zapobiec. W ten sposób masz prawdziwy bodziec do znalezienia dobrych praktyk programistycznych zamiast po prostu postępować zgodnie z dobrymi radami programistycznymi ... a kiedy trafisz na barierę pamięci, bardziej prawdopodobne jest egzekwowanie dobrych praktyk, nawet kosztem wygody. To tylko punkt widzenia ...
PkP
2
@PkP: usłysz głośno i wyraźnie. Oznacziłem to jako alternatywny pogląd - ponieważ tak naprawdę nie odpowiada na pytanie!
Brian Drummond
2
@ MisterMystère: Mikrokontrolerom na ogół nie brakuje pamięci. Mikrokontroler, który ma 4096 bajtów pamięci RAM przy pierwszym włączeniu, będzie miał na zawsze 4096 bajtów. Możliwe, że kod błędnie spróbuje uzyskać dostęp do adresów, które nie istnieją, lub oczekiwać, że dwie różne metody obliczania adresów uzyskają dostęp do innej pamięci, gdy nie będą, ale sam kontroler po prostu wykona podane instrukcje.
supercat
6

Naprawdę podoba mi się odpowiedź Majenko i dałam jej +1. Ale chcę to wyjaśnić do pewnego stopnia:

Wszystko może się zdarzyć, gdy w mikrokontrolerze zabraknie pamięci.

Naprawdę nie można na niczym polegać, kiedy to się dzieje. Kiedy w urządzeniu zabraknie pamięci stosu, stos najprawdopodobniej zostanie uszkodzony. I tak się dzieje, wszystko może się zdarzyć. Zmienne wartości, wycieki, rejestry temp. Zostają uszkodzone, co zakłóca przepływ programu. Jeśli / to / elses może niepoprawnie ocenić. Adresy zwrotne są zniekształcone, co powoduje, że program przeskakuje na adresy losowe. Każdy kod napisany w programie może zostać wykonany. (Rozważ kod typu: „jeśli [warunek], to {fire_all_missiles ();}”). Również cała gama instrukcji, których nie napisałeś, może zostać wykonana, gdy rdzeń przeskoczy do niepołączonej lokalizacji pamięci. Wszystkie zakłady są wyłączone.

PkP
źródło
2
Dzięki za uzupełnienie, szczególnie podobała mi się linia fire_all_missiles ().
Mister Mystère,
1

AVR zresetował wektor pod adresem zero. Kiedy nadpiszesz stos losowymi śmieciami, w końcu zapętlisz się i nadpisujesz adres zwrotny i wskaże on „nigdzie”; wtedy, gdy wrócisz z podprogramu do tego miejsca, wykonanie zapętli się wokół adresu 0, gdzie zwykle jest skok do resetowania procedury obsługi.

Ilia
źródło