logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[BASCOM] Nieprzewidywalne zachowanie programu, stosy?

aleexander 04 Lis 2010 21:05 2760 19
  • #1 8703211
    aleexander
    Poziom 15  
    Witam!
    Jestem na etapie programowania dość dużego urządzania, program liczy w tej chwili ponad kilka tysięcy linii kodu i do pewnego czasu wszystko szło ok.
    Całość działa w oparciu o Atmega2561.
    Teraz, kiedy dodaję kolejne funkcje, program zaczyna zachowywać się w sposób nieprzewidywalny.
    Przykładowo:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Instrukcje Print #2 wstawiłem w celu znalezienia problemu, wysyłają one jak widać słowo "TARGET" a następnie zawartość zmiennej Target. Samo "Target" jest aliasem do Ubuf(1).
    Co się dzieje: kiedy linia
    Kod: text
    Zaloguj się, aby zobaczyć kod

    jest zakomentowana, działa poprawnie (w miarę).
    W terminalu otrzymuję zawartość zmiennej Ubuf(1) (czyli Target).
    Kiedy linię odkomentuję - w terminalu dostaje mnóstwo spacji (mnóstwo to znaczy tyle, że otrzymuje je przez kilkanaście sekund, przy transmisji 115200 bps), później trochę śmieci i na końcu zawartość zmiennej.
    Nie potrafię dojść, dlaczego tak się dzieje.

    Druga sprawa, to sama zawartość zmiennej Ubuf(1) (czyli Target).
    Mam tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Disk_psu_node to stała o wartości 3.
    Wysłanie jej wartości poprzez
    Kod: text
    Zaloguj się, aby zobaczyć kod

    potwierdza, że ma wartość 3.
    Jak widać w kodzie, wpisuję ją do zmiennej Target, czyli w zmiennej Ubuf(1) powinno być 3. Wysyłam przez UART, otrzymuję 2 (jeśli dodatkowo wysyłam słowo "TARGET" to dostaję również wyżej opisane śmieci).
    Nie potrafię dojść dlaczego zmienna ma inną wartość niż powinna mieć.
    W innym miejscu kodu, gdzie stosuję identyczną konstrukcję, wszystko działa. Np.:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Moje podejrzenia leżą w stosach.
    Deklaruje ich rozmiar w taki sposób (trochę na wyrost):
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Niekiedy, w zależności od kompilacji lub dopisania czegokolwiek, pojawia się również problem w wywoływaniu podprocedury wyświetlającej tekst na LCD. Kontroler się zawiesza lub zapętla (w podprocedurze nie ma pętli które mogłyby się zapętlić, jedynie pętle For).
    W urządzeniu mam LCD na sterowniku SED1330 i do niego własne procedury wyświetlania. Działały przez długi czas i nic w nich nie zmieniałem, dlatego nie szukałbym w nich samych problemu.

    Problem jest zawiły i nie bardzo wiem za co się chwycić. Staram się nie zagnieżdżać sub-ów, najgłębiej wchodzi do drugiego poziomu:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Przerwania są dwa, jedno z RTC (ustawia jedynie flagę), drugie z klawiatury (również tylko ustawia flagę).

    Będę bardzo wdzięczny za jakiekolwiek podpowiedzi które pomogą w diagnozie problemu.
    Jeśli będą potrzebne dalsze informacje to proszę pisać. Cały kod jest niestety za długi i słabo okomentowany, dlatego raczej mija się z celem umieszczanie go tu w całości.

    Pozdrawiam serdecznie,
    aleexander
  • #2 8703301
    Jaca
    Poziom 31  
    Masz w programie procedury obsługi przerwań ?
  • #3 8703381
    xury
    Specjalista automatyka domowa
    Uuuu kolego. Piszesz, że kod ma kilka k linii podajesz jakieś fragmenty i chcesz abyśmy wywróżyli co jest nie tak ?
    Co można zrobić ? - Najpierw przeanalizować plik rpt po kompilacji.
    A jeśli nie pomoże to debugger tylko.
    Pomocne też mogą być: symulator, funkcja stcheck i analiza stosu itd.
    Policzyć na piechotę wykorzystanie SRAM, bo być może przedobrzyłeś z wielkością stosów i jest za mało pamięci na zmienne.
    Ja jeszcze takiego kodu nie napisałem wiec to tyle co mogę doradzić. :)
  • #4 8703817
    aleexander
    Poziom 15  
    Tak, w programie zawarte są dwie procedury obsługi przerwania, obydwie od przerwań zewnętrznych:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    oraz

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Rozumiem, że bez całego kodu analiza może być ciężka. Jednak sytuacja w uproszczeniu wygląda w ten sposób, że kod:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    daje w wyniku inną wartość niż 3.
    Dlatego podejrzewam problem ze stosem i/lub alokacją zmiennych w pamięci. Czy jest możliwość, aby w trakcie działania programu sprawdzić jaki w danej chwili rozmiary mają stosy?

    Wolnej pamięci na pewno wystarcza. Zmienne łącznie zajmują max 2kB, do tego stosy 3 x 1024B, daje razem okolo 5kB. Atmega2561 ma 8kB pamięci, więc to nie to. Część pamięci zajmują również bufory wejściowe dwóch UART'ów, jeden ma 36B, drugi 254B. Mimo to pamięci zostaje sporo.

    Niestety symulacja odpada, zasymulowanie warunków w jakich występuje błąd jest niemożliwe - za dużo plików $include dla symulacji, a poza tym układ komunikuje się z innym uC obsługującym klawiaturę, czego nie da rady zasymulować.
  • #5 8703901
    mirekk36
    Poziom 42  
    Jest takie powiedzenie:

    Jeśli w programie zostanie przekroczona pewna ilość IF'ów to program zaczyna żyć własnym życiem ;)

    W przypadku Bascoma to już bez żartów można powiedzieć, że często:

    Jeśli program zaczyna mieć kilka tys lub więcej linii kodu to zaczyna żyć własnym życiem.

    Jest pewien kres wytrzymałości - bo pisanie kilku tysięcy linii kodu w jednym pliku to wręcz masochizm ;) .... a zapanowanie nad aż 3 rodzajami stosów w Bascomie w takim przypadku to już kosmos ....

    Z tych mniej więcej powodów przychodzi kiedyś czas, żeby się na poważnie zastanowić nad przejściem na język C. Wystarczy tylko tracony czas na szukanie błędów w takim MEGA długim pliku przeznaczyć na naukę C .... i wyjdzie lepiej.

    Ja już dawno tak zrobiłem i dlatego gorąco to polecam. A wiem z własnego doświadczenia gdy kiedyś moje programy w Bascomie zaczęły być masochistycznie długie i nadziane wstawkami asemblerowymi jak dobra kasza skwarkami ;)
  • #6 8703966
    adambehnke
    Poziom 24  
    Mam dokładnie takie same problemy i zostałem zmuszony do wielkiego ograniczenia rozmiaru kodu. Na dodatek mam problemy ze stworzeniem kodu >128k i jego poprawnym wgraniu do procesora. Zatem tak jak pisze Mirek - TYLKO C. Ja już zacząłem i z tego co widzę nie jest to takie straszne.
  • #7 8704543
    Jaca
    Poziom 31  
    1. Czy wraz z Print a dostajesz "śmieci"+wartość a ?
    2. Czy gdzieś w programie używasz Str(), Mid(), Left(), Right() ?
    3. Jaka to wersja BASCOM'a ?
    4. Prześledź skoki Gosub-Return
    5. Sprawdź, czy bufory nie nachodzą na stosy, obszar zmiennych, itp
    6. Sprawdź, czy np zmienne String nie otrzymują ciągów dłuższych niż zadeklarowana długość.

    Zmniejsz $hw..., $sw... a zwiększ $frame...
  • #8 8704696
    aleexander
    Poziom 15  
    Ad. 1
    Przykład z a był nieco poglądowy, sytuacja tak się dla mnie przedstawia. Program wygląda tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    W momencie wysyłania słowa TARGET w terminalu przychodzą śmieci, a po pewnym czasie wartość zmiennej Target, która równa się dwa, mimo, że wpisałem 3.

    Ad. 2 & 6
    Sporadycznie w programie używam funkcji Str() oraz Mid(), głównie w powiązaniu z wyświetlaniem tekstu na LCD. Funkcji Mid() używam do wycinania jednego znaku ze stringa i wysłaniu jego wartości ASCII do LCD, więc funkcja leci w pętli.
    String ma rozmiar 32, bo tyle znaków maksymalnie mieści się na LCD w poziomie. Jednak nigdy nie wysyłam nawet tyle, zawsze jest to mniej. W kilku miejscach używam Str() do konwersji zmiennej np. godzin na tekst i wysyłam to do LCD. Na końcu raportu znajduje się sporo ostrzeżeń, że nie wiadomo, czy tekst zmieści się w stringu, prześledziłem teksty jakie tam wpisuje i żaden nie jest dłuższy.

    Ad. 3
    Wersja BASCOM'a 1.11.9.5

    Ad. 4
    Jak pisałem, staram się nie zagnieżdżać skoków i podprocedur, zresztą na drodze do opisywanej sytuacji nie ma ich wiele. Są jedynie procedury odczytujące RTC oraz wyświetlające tekst, każda ma odpowiedni return.

    Ad. 5
    Sprawdzałem w raporcie kompilacji pozycje stosów i zmiennych. Obszar zmiennych kończy się sporo wcześniej nim zaczynają stosy. Jedynie nie mogłem dojść gdzie umieszczone są bufory wejściowe (te konfigurowane w Config Serialin) UARTów.
    Załączam raport kompilacji.
    Zmniejszyłem HWSTACK i SWSTACK na 256B, FRAMESPACE ustawiłem 2560.
    Problem występuje nadal.
  • #9 8704796
    Jaca
    Poziom 31  
    Możemy spróbować kompilacji na pełnej wersji BASCOM'a 2.0.1.0. Podeślij źródło a ja wyślę Ci wynikowy. Sprawdzimy, czy to wina kompilatora.
  • #10 8704865
    aleexander
    Poziom 15  
    W załączniku kompletny listing.
    Do skompilowania jedynie plik main.bas, reszta jako pliki include nie wymagające kompilacji.

    Struktura katalogów powinna być taka jak w archiwum.

    PS. Jest już Bascom AVR 2.0??
  • #12 8705064
    aleexander
    Poziom 15  
    Zdaje sie, że to to. Ubuf(1) przyjmuje odpowiednią wartość.
    Jeśli mógłbym prosić o skompilowanie jeszcze tego, odkomentowałem linię wysyłającą słowo "TARGET".
  • #14 8705132
    aleexander
    Poziom 15  
    Więc jednak dalej coś jest nie tak.
    W momencie wysłania słowa "TARGET" dalej dostaje śmieci, ale przynajmniej zmienna Ubuf(1) do której wpisuję 3 po odczytaniu zawiera 3.

    Mimo to, muszę zainteresować się nowszą wersją kompilatora.
  • Pomocny post
    #15 8705171
    Jaca
    Poziom 31  
    Spróbuj zmniejszyć prędkość ze 115200bps na 57600bps.
  • #16 8705304
    aleexander
    Poziom 15  
    Zmniejszyłem prędkość na 57600bps, dopisałem aby wysyłał zawartość 10 elementów z tablicy Ubuf(), oraz aby ponownie wysłał zawartość tej tablicy pod koniec procedury transmit, czyli tuż przed wysłaniem danych do magistrali RS485.
    W terminalu dostaję:
    TARGET
    7
    3
    2
    10
    0
    26
    0
    37
    0
    0
    SENDING
    7
    2
    3
    10
    0
    22
    0
    37
    0
    0

    Piwerwsza liczba zaraz po słowie "TARGET" lub "SENDING" to zmienna Ubuf(1). Tutaj ma wartość 7, a wpisywałem 6. Kiedy wpisałem 4 było 5, a kiedy wpisałem 3 było 2.
    Przywróciłem prędkość 115200bps i dalej działa, poza wartością Ubuf(1). Reszta elementów tej tablicy przyjmuje odpowiednie wartości, np. Ubuf(3) który ustawiam w nastepnej linijce po Ubuf(1).

    Na końcu procedury Transmit jest obliczanie sumy kontrolnej, i jest ona poprawna, z uwzględnieniem wartości zmiennej Ubuf(1). Nie bardzo wiem co o tym myśleć.

    Po tym UARCIE mam również bootloader oraz transmisje danych na i z karty pamięci SD - nie ma żadnych błędów, więc nie są to raczej przekłamania transmisji. Kwarc przyjazny transmisjom szeregowym, 7,3728MHz.
  • #17 8705376
    rpal
    Poziom 27  
    zapanuj nad zmiennymi a potem się zastanawiaj nad stosem. Może zbież je w jedną "kupę" choćby strukturę i w ten sposób odzyskaj nad nimi kontrolę.Ale to już raczej nie w bascom. Może masz zainicjowane przerwanie i brak do niego obsługi ? Poza tym skąd pewność że stos jest winien ? Jak porobisz sensowne pułapki w programie to bład dość szybko namierzysz ale też nie sadzę aby bascom byl tu pomocny. Tak czy siak chyba czeka ciebie przesiadka na inny jezyk.
  • #18 8706821
    aleexander
    Poziom 15  
    Przesiadka na inny język niż Bascom zbliża się do mnie, ale staram się odwlec ten moment. Mam za dużo napisane, żeby teraz to przepisywać na C, dlatego usiłuję każdy problem rozwiązać.

    Udało mi się ustalić przyczynę problemów z zawartością Ubuf().
    Winny okazał się kompilator - u mnie na wersji 1.11.9.5 problem występuje, natomiast u kolegi Jaca na wersji 2.0.1.0 tego nie było. Do rzeczy:

    Operacja typu:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    powoduje, że zmienia się bit 0 ale dla zmiennej Ubuf(1), czyli dla 1 elementu tablicy a nie piątego.

    Dlatego wpisując 3 było 2, a wpisując 4 było 5.
    Ominąłem ten problem togglując bit dodatkowej zmiennej i przepisując cały bajt do tablicy.

    Problem śmieci i "kosmosu" przy wysyłaniu stringa pozostał i wygląda w tej chwili tak, że raz jest, a raz go nie ma. Zależności nie udało mi się ustalić. Jak dopisze jakąś linijkę w kodzie przed felernym poleceniem, to się kaszani. Dopisze coś innego, albo w innym miejscu, to się przestaje kaszanić, albo nie. Wygląda to również na błąd kompilatora. Jeśli uda mi się to rozwiązać, dam znać.

    Dziękuję za pomoc i zainteresowanie,
    pozdrawiam, aleexander
  • #19 8706921
    Jaca
    Poziom 31  
    Pozbądź się RS'owej transmisji buforowej i innych komend typu Ischarwaiting(), Inkey() na rzecz przerwania od URXCx i wtedy sprawdź działanie programu.
  • #20 9307386
    aleexander
    Poziom 15  
    Po dłuższej walce i braku jednoznacznej identyfikacji problemu z wyświetlaniem stringów i transmisją po rs zdecydowałem się na przepisanie całego programu na język C. Jak na razie wszystko idzie sprawnie.

    Pozdrawiam serdecznie,
    aleexander
REKLAMA