Framesize – obliczamy zapotrzebowanie na SRAM dla programu.

4/5 - (1 vote)

Dosłownie temat ten dotyczy dyrektyw:
$framesize = z
$swstack = y
$hwstack = x
i omówienia podstawowych zasad w obliczaniu na zapotrzebowanie pamięci SRAM w MCU dla programu i zmiennych.

Dyrektywy dyrektywami jednymi z licznych, ale akurat te chyba najistotniejszymi dla programisty. Dotyczą stosów sprzętowego WHSTACK, programowego SWSTACK i bufora zmiennych FRAMESIZE. Złe gospodarowanie tymi wartościami spowoduje niemożliwość kompilacji bądź nieprawidłowe funkcjonowanie samego urządzenia finalnego, lub błędy występującymi w określonych sytuacjach, które mogą być uciążliwe do zdiagnozowania. Co z kolei skutkować może dalszymi głębszymi następstwami …

Każdego wcześniej czy później dopadnie potrzeba zgłębienia tego tematu. No chyba, że ktoś chce uprawiać sztukę „programowanie przez zgadywanie”. Są to sprawy o których warto wiedzieć bo naprawdę są pożytecznym kąskiem wiedzy. Tak samo jak zgłębienie środowiska IDE Bascom AVR. Program pokazuje bardzo dużo istotnych wiadomości ułatwiających życie. Trzeba tylko wiedzieć że są i gdzie są by móc swobodnie je interpretować.

Stos jest elementem rozrastającym i kurczącym się dynamicznie w trakcie pracy programu. Może dojść do sytuacji gdzie jeden zajmie przestrzeń zarezerwowaną dla drugiego (stack overleap) i kłopot gotowy. Dlatego na początku kodu deklaruje się ich rozmiary, które powinny być z grubsza (lub precyzyjnie) obliczone przez projektującego program.
Wartości automatycznie deklarowane przez BASCOM, wystarczają dla większości prostych programów, nie korzystających prawie wcale z procedur (SUB) i funkcji (FUNCTION). I nie muszą być prawidłowe dla każdego typu µC, szczególnie zważywszy na różnorodne pojemności ich pamięci SRAM.

W kwestii wspomnianych obliczeń to metoda szacowania rozmiarów poszczególnych stosów nie jest prosta i rzeczywiście wyniki zależą od treści programu, ilości i typów zmiennych itp.

Jak uzyskać informację o nieprawidłowości, że deklarowany stos jest zbyt mały?
Generalnie podczas kompilacji kodu taka adnotacja się nie ukaże. Ale możemy ją namacalnie określić (tylko) w trakcie symulacji programu.
Jeśli włączy się u góry w symulatorze zakładkę µP, to znajdziemy tam tam dwa checkbox-y: Frame Overflow oraz Stack Overflow. Jeśli któryś zostanie automatycznie zaznaczony w trakcie symulacji programu, to znak, że ten stos jest zbyt mały. Należy doświadczalnie zwiększyć wartość w odpowiednim polu – i ponownie uruchomić symulację.Symulator AVR
Tuż poniżej znajdziemy także pola Soft Stack, Soft Stack Min itd. Tam pokazywane są bieżące wartości adresów, początków stosów i ich końców. Śledząc te wartości można obliczyć (wystarczy odjąć odpowiednie wartości z każdej pary pól) ile bajtów z każdego stosu użył program.

Chociaż można skonfigurować wielkość ramki w menu Opcje, Compiler, Chip, dobrze jest umieszczać te wartości w każdym nowym kodzie. Najlepiej wyrobić sobie nawyk aby większość istotnych dyrektyw, instrukcji konfiguracji i deklaracji umieszczać w nagłówku kodu. Zaoszczędzi to w przyszłości czasu na odgadywanie konfiguracji oraz stwarza kod przejrzystym dla środowiska sprzętowego. Postępując w ten sposób sposób, plik cfg (konfiguracji) przestaje być niezbędny. Mnie dopadła sytuacja z tym związana gdy z szuflady wyjąłem ATtiny13. Przygotowałem stosowny nagłówek dla nowego kodu (bez deklaracji wielkości stosów), zadeklarowałem zmienne. Wtedy odruchowo klepnąłem klawisz eF7 by program zapisał na dysk zaczątek programu … Ku mojemu zaskoczeniu zobaczyłem komunikat Out off memory ;-D Myślę jakie licho przecież tu nic nie ma … Po chwili zadumy przypomniałem sobie o zaszytych w opcjach różnych deklaracjach …. w tym i wielkości stosów, które po zsumowaniu srogo przekraczały rozmiar pamięci tego µC.  :-p

Dyrektywa $framesize nadpisuje wartość z opcji IDE.

Ważne jest, aby dyrektywa framesize występowała w głównym pliku projektu. Nie może być zawarta w pliku dołączanym przez $include, tylko główny plik jest analizowany dla framesize. Dyrektywa framesize akceptuje tylko wartości liczbowe.

Funkcje takie jak PRINT, LCD, INPUT i procedury konwersji String wymagają  bufora w pamięci SRAM. Ze względu, że kompilator zawsze używa 24 bajtów w przestrzeni ramki, pierwsze 24 bajty na początku FRAME, działa jako bufor konwersji. Do FRAME lądują też wszystkie zmienne LOCAL. Natomiast adresy zmiennych LOCAL są przechowywane w Software Stack (jeśli ten jest zdefiniowany). Wyjątek stanowią zmienne typy BIT, ponieważ są dla systemu są zawsze globalne. Natomiast zmienne typy Array nie mogą być stosowane jako lokalne. Ale tablice mogą być przekazywane przez referencję (by ref) jako parametr do procedur (SUB) i funkcji (FUNCTIONS). Wtedy potrzeba zarezerwować dwa bajty w Software Stack na adres tablicy (Array).schemat mapy pamieciFRAME rośnie od dołu przestrzeni pamięci, za pamięcią zmiennych i ewentualnie pozostałą pustą przestrzenią. Od najmniejszego adresu, na początku przestrzeni FRAME, pierwsze 24 bajty stanowią bufor konwersji. Tu trzeba pamiętać również, że zbyt mała zadeklarowana przestrzeń $framesize powoduje niepożądane zastępowanie Software Stack i / lub Hardware Stack.

 Gdy nie ma wystarczająco dużo miejsca wewnątrz FRAME, zmienna ERR będzie ustawiona na jeden.

$SWSTACK

Software Stack można pominąć określając jego wartość na 0. Jednak zalecane jest by zawsze deklarować wartości dla wszystkich Stack i Frame! Aktualne są zalecenia jak dla $Framesize. Software Stack przechowuje adresy parametrów przekazywanych do podprogramów i adresy zmiennych typu LOCAL. Każda przekazywana zmienna i zmienna lokalna rezerwuje 2 bajty pamięci SwStack dla swojego adresu.

Podczas korzystania z procedur (SUB) lub funkcji (FUNCTION) dostępne są 3 sposoby dla przekazania parametrów:
użycie BYREF spowoduje przekazanie zmiennej przez wskazanie jej adresu (wskazuje na istniejącą zmiennej, która jest już w SRAM), dlatego zmienna będzie mogła zostać jawnie zmodyfikowana w podprogramie.
użycie BYVAL spowoduje wskazanie wartości przechowywanej w FRAME (podczas wykonywania procedur), więc wskazuje na adres w FRAME. Takie odwołanie do zmiennej powoduje prace na jej „kopii”. W punkcie wywołania (tylko) w tym przypadku można wpisać wartość zamiast nazwy zmiennej.
użycie BYLABEL spowoduje przekazanie adresu etykiety.

Gdy parametr nie jest określony wartość zostanie przekazana (domyślnie) przez ByRef.

Więc rozmiar stosu SOFTWARE STACK może być obliczony na podstawie maksymalnej liczby parametrów przekazanych do podprogramów SUB, dodając liczbę zmiennych lokalnych i mnożąc wynik przez 2 (adresy w SwStack są dwubajtowe). Aby być bezpiecznym, warto dodać 4 kolejne bajty dla używanych wewnętrznie zmiennych lokalnych.

Software Stack rośnie od góry w dół przestrzeni adresowej (patrz rysunek) i rozpoczyna się bezpośrednio za stosem Hardware Stack. Software Stack rośnie w kierunku FRAME.

$HWSTACK

 Stos Hardware Stack to powierzchnia w SRAM, niezbędna do funkcjonowania programu. Za każdym razem gdy wywołujemy procedurę (SUB) lub funkcję (FUNCTION), lub używamy podprogramu (GOSUB), procesor musi wiedzieć na jaki adres powrócić po jej zakończeniu. Również dla instrukcji RETURN po przerwaniu, adres ten jest wymagany przez program. W tym celu procesor zapisuje adres w Hardware Stack.

Podczas korzystania z etykiety GOSUB, mikroprocesor odkłada adres powrotu na Hardware Stack i użyje do tego celu 2 bajtów pamięci. Gdy użyjemy instrukcji powrotu RETURN, stos Hardware Stack jest przesuwany do tyłu i program może kontynuować pod odpowiednim adresem. Podczas zagnieżdżenia GOSUB, CALL lub funkcji, będzie zużyte więcej miejsca na stosie. Większość deklaracji używa sprzętowego stosu, ponieważ jest wywoływany algorytm języka maszynowego.
Hardware Stack rośnie z góry na dół. Rozpoczyna się pod najwyższym dostępnym adresem pamięci SRAM i dlatego znajduje się przed Software Stack i / lub FRAME.

W momencie gdy potrafimy już zapanować nad stosami i policzyć ich prawidłowy rozmiar, do pełni obrachunków należy zsumować ile miejsca w pamięci zajmują nasze zmienne według zadeklarowanych typów. Gdy już to uczynimy i dodamy wszystkie te wartości, suma nie może przekraczać  rozmiaru pamięci danego µC.

Ot cała magia.

Dodam jeszcze jedną wskazówkę, o której być może nie wszyscy wiedzą. Standardowo po kompilacji kodu (o ile ktoś nie wyłączył sobie tej funkcjonalności) tworzony jest międzyinnymi raport i zapisywany do pliku. Łatwo można go przeglądać posługując się kombinacją klawiszy Ctrl + W. Raport ten  zawiera między innymi adresy początkowe i końcowe stosów, ilość pozostałej wolnej pamięci SRAM, nazwy zadeklarowanych zmiennych, nie użytych w kodzie. To tylko kilka przykładowych informacji tam zawartych na pobudzenie apetytu ;-D


W dużej mierze artykuł został opracowany na podstawie avrhelp.mcselec.com

Warto pozaglądać również do artykułów o: Memory usage, i  $FRAMEPROTECT, oraz $HWCHECK, $FRAMECHECK, $SOFTCHECK

Otagowano , , , , , , , , , , .Dodaj do zakładek Link.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

16 − siedem =

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.