Elektroda.pl
Elektroda.pl
X

Wyszukiwarki naszych partnerów

Wyszukaj w ofercie 200 tys. produktów TME
Europejski lider sprzedaży techniki i elektroniki.
Proszę, dodaj wyjątek elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[AVR GCC] - Błędy w kompilatorze?

djfarad02 12 Cze 2013 21:26 2568 21
  • #1 12 Cze 2013 21:26
    djfarad02
    Poziom 17  

    Witam,

    Już przy dwóch projektach zdarzyła mi się podobna sytuacja dlatego postanowiłem zapytać użytkowników elektrody czy być może spotkali się z takim problemem.

    Używam AVRStudio z AVR-GCC, zauważyłem niepoprawne zachowanie programu przy włączonej optymalizacji kodu. Nie jest to związane z błędną definicją zmiennych

    Uwaga - zarówno w jednym jak i drugim przypadku błąd usuwało lub zmieniało jego charakter dopisanie jakiegokowliek (!!!!!) kodu o dość dowolnej długości i we wmiarę dowolnym miejscu programu. Mogły to być instrukcje nie mające wpływu na działanie programu, np jakieś obliczenia na nieużywanych zmiennych, niepotrzebne wywołanie funkcji itp. Tak jakby miało to związek z umiejscowieniem poszczególnych fragmentów w pamięci flash.

    Przykład z praktyki: program nie działa z włączoną optymalizacją. Zachowuje się w nietypowy sposób - jedna ze zmiennych w pętli głównej "blokuje się" jeśli wywołam pewną funkcję i pozwolę jej dłużej pracować (funkcja nieblokująca na zasadzie maszyny stanu, wywoływana z każdym obrotem pętli).
    Zablokowanie zmiennej w pętli głównej polega na tym, że warunki przypisujące tej zmiennej określone wartości nie są w stanie jej modyfikować.
    Teraz dopisuję w głównej pętli np taką linijkę:

    itoa(testflag,temp,10);

    i w magiczny sposób program po skompilowaniu działa poprawnie, choć zmienna temp nie jest nigdzie używana. zmienna testflag przestaje się "blokować".

    To jeszcze nic, dopisuję LCD_Home() zamiast itoa i też program zaczyna działać normalnie. To samo dzieje się jak dopiszę kilka inkrementacji jakiejkolwiek zmiennej. Wszystko co zwiększa długość kodu magicznie leczy program.

    Czy ktoś się z tym spotkał? Mam drugi raz podobny przypadek. W innym projekcie z kolei chodziło o blokowanie losowymi wartościami jednej z komórek tablicy. Pomagało dopisanie kilku linijek dowolnego kodu bądź zwiększenie rozmiaru tablicy z 48 na 100 elementów, mimo że była to ostatnia definiowana tablica w RAMie. Tablica była statyczna globalna. Również w tym przypadku wyłączenie optymalizacji leczyło program.

  • #2 12 Cze 2013 21:43
    michalko12
    Specjalista - Mikrokontrolery

    Na 99,99999% przyczyną są błędy w Twoich programach. Napisz kawałek niedziałającego kodu i zamieść go tu, a wtedy zostaniesz oświecony.

  • #4 12 Cze 2013 21:59
    djfarad02
    Poziom 17  

    michcior - wiem, a w dodatku ta zmienna jest używana tylko i wyłacznie w głównej pętli w main

    michalko12 - oto kod:

    problem jest ze zmienną nrflag

    Kod: c
    Zaloguj się, aby zobaczyć kod

  • #6 12 Cze 2013 22:28
    djfarad02
    Poziom 17  

    Warningi są tylko dotyczące niezainicjalizowanych niektórych zmiennych (w main np stabCnt).
    Sypie się na wszystkich poziomach optymalizacji. Tylko przy O0 działa poprawnie.

    W dodatku, całość chodzi zawsze poprawnie do pewnego momentu (do chwili wykonania testów badajFiltryAuto() ). Jest to funkcja nieblokująca wykonująca pewne czynności na zasadzie maszyny stanu. podanie jej jako start=1 powoduje, że funkcja zaczyna działać i po odpowiedniej liczbie wywołań (kroków) przechodzi do stanu bezczynności. Kiedy już ta funkcja zrobi wszystko co miała to program jest wysypany - nie wisi ale zmienna nrflag jest jakimś cudem blokowana albo blokowane jest wykonywanie związanych z nią warunków. Objawia się to po prostu tym, że nie da się wybrać innego testu, choć można wykonać ponownie już wybrany. Przerwanie działania funkcji przez przekazanie jej start=2 powoduje brak komplikacji, choć nie do końca, ponieważ jeśli zrobi się to za późno problemy wystąpią.
    Jak dla mnie sytuacja jest absurdalna i bardzo bym się cieszył gdyby ktoś nakierował mnie na to, co może być przyczyną.

    Jeszcze raz nadmienię, że podobny problem miałem też w innym projekcie i również pomagało dopisanie niepotrzebnych linni kodu.

  • #7 12 Cze 2013 22:34
    BlueDraco
    Specjalista - Mikrokontrolery

    Sprawdz zajętość RAM. Twój program niepotrzebnie używa b. dużo miejsca na stosie, więc możesz dorzucić ze 200 bajtów do tego, co podaje kompilator.

  • #8 12 Cze 2013 22:38
    djfarad02
    Poziom 17  

    BlueDraco napisał:
    Sprawdz zajętość RAM. Twój program niepotrzebnie używa b. dużo miejsca na stosie, więc możesz dorzucić ze 200 bajtów do tego, co podaje kompilator.


    Kompilator podaje zajętość ramu około 20% procek ma 2048. Więc jest jeszcze kupa miejsca

  • #10 12 Cze 2013 23:23
    djfarad02
    Poziom 17  

    Spróbuję tak zrobić i prawdopodobnie to pomoże, tak samo jak pomaga dopisywanie linni. Choć dalej nie wyjaśni to problemu - a to mnie najbardziej nurtuje.

    Apropo sterty jeszcze - w innym projekcie miałem bardzo podobny problem ale dotyczył właśnie zmiennej globalnej. Była sobie globalna tablica:
    uint8_t RGB[48];
    w której podobne jaja zaczęły się robić z jedną jej komórką (46).
    Paradoksalnie oprócz wyłączenia optymalizacji pomagała też zmiana na:
    uint8_t RGB[100];
    Kompletnie tego nie rozumiem - zajęte więcej ramu, a problem ustępował. W dodatku ta tablica była definiowana jako ostatnia, więc chyba kompilator umieszczał ją na końcu sterty

    Wracając do problemu - co do globalizacji zmiennej jutro dam znać co wyszło, ponieważ nie mam pod ręką urządzenia.

  • Pomocny post
    #11 12 Cze 2013 23:38
    michcior
    Poziom 29  

    Ten przykład akurat da się wyjaśnić. Sterta układana jest od dołu w górę a stos odwrotnie (przynajmniej w większości). Jak zaczną zachodzić na siebie to tak może być. Ale regularność tej 46 komórki raczej wykazuje na błąd typu indeksowanie tablicy poza jej rozmiarem. Sporo by można scenariuszy snuć. Czasami takie kłopoty dobrze że wychodzą bo świadczą że coś jest nie tak, z doświadczania, żadne zamiatanie pod dywan nie chowa problemu na wieki, zawsze wylezie, zrobisz "fix" jakimś magicznym sposobem a kiedyś walnie w innym miejscu.

  • #12 12 Cze 2013 23:53
    djfarad02
    Poziom 17  

    Zgadzam się, poprawki metodą prób bez znania genezy problemu wcześniej czy później dadzą się we znaki.

    Wracając do tej tablicy - też tak kminiłem, że to błąd z indeksowaniem jakiejś innej tablicy będącej niżej w RAMie powoduje, że komórka jest nadpisywana, bądź stos na nią zachodzi. Tylko w takim razie, przepraszam za wyrażenie, dlaczego do ciężkiej cholery zwiększenie wymiaru tej tablicy nagle leczy tę komórkę z problemów? Poza tym, dlaczego leczyło też tamten program dopisanie kilku inkrementacji bylejakiej zmiennej, byleby kod wynikowy był nieco dłuższy? Nie muszę chyba dodawać, że wyłączenie optymalizacji również usuwało problem.

    Miło nam się gawędzi, mam nadzieję że odezwie się jeszcze ktoś kto miał podobne problemy, może coś wspólnie uradzimy.

  • Pomocny post
    #13 13 Cze 2013 08:01
    michalko12
    Specjalista - Mikrokontrolery

    Ja miewałem takie problemy i zawsze problem wynikał z mojej winy. Ja dysponuję debugerem więc ze zlokalizowaniem przyczyny nie miałem większego problemu. Przyczyn może być dużo, niezainicjowane wskaźniki, niewłaściwe indeksy, rzutowania, braki sufiksów na stałych, niewłaściwe wektory przerwań itp itd. Kod który przedstawiłeś nie jest cały to tylko funkcja main. Błędy mogą być w pozostałych plikach źródłowych. Może masz zły procesor zdefiniowany. Po za tym co ma wspólnego ten program z bascomem? Program pisany w C a tu zainkludowany plik bascom_typy.h? Po co?

  • #14 13 Cze 2013 11:18
    djfarad02
    Poziom 17  

    w bascom_typy.h zdefiniowane jest
    typedef uint16_t word;
    typedef uint8_t byte;
    z przyzwyczajenia wolę pisać word i byte zamiast uint16_t uint8_t

    Co do błędów w rzutowaniach i brakach sufiksów na stałych czy miałeś przypadki, że wpływało to na zamazanie pamięci w zupełnie innym obszarze? Nie rozumiem w jaki sposób to by się miało stać.

    Dzisiaj będę dalej walczył i dam znać wieczorem jak sytuacja.

  • #15 13 Cze 2013 11:48
    alagner
    Poziom 25  

    zrzutuj sobie wskaźnik 8bitowy na 16bitowy i sprawdzaj długość tablicy dla 8 bitów. To jest totalnie głupi błąd ale zdarza się czasem nawet najlepszym ;)

  • #16 13 Cze 2013 16:39
    djfarad02
    Poziom 17  

    Faktycznie. Choć w tym projekcie akurat nie ma takich wskaźników to może tak być. Co do głupich błędów to z mojej praktyki wynika, że głupie błędy stanowią z reguły większość istniejących błędów.

    Walczę dalej, dam znać co wynikło

    Dodano po 2 [godziny] 22 [minuty]:

    Dalsze próby na placu boju utwierdzają mnie coraz bardziej w przekonaniu o absurdalnym zachowaniu kompilatora. Wykomentowałem niektóre linnie i nagrałem film, w którym jest wyjaśnione co się dzieje:

    Załączam film (youtube może jeszcze przetwarzać bo przed chwilą wrzucony):

    Link


    Kod: ( zmieniana jest jedna linia z while(1); )

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Nadmienię, że przy innych teoretycznie nie mających wpływu zmianach program zachowuje się na jeszcze inne sposoby. Np. da się zmienić nrtestu tylko dwa razy po wykonaniu testu 9. Drugi przypadek to był w kółko wykonujący się bez końca test.

  • Pomocny post
    #17 13 Cze 2013 17:04
    szelus
    Specjalista - Mikrokontrolery

    Czy pozostałe (tzn poza main) funkcje korzystają z tablic lub wskaźników do czegokolwiek?
    Jeżeli tak, to zacząłbym od przyjrzenia się tym miejscom.

  • Pomocny post
    #18 13 Cze 2013 17:10
    michalko12
    Specjalista - Mikrokontrolery

    Szukaj błędu w innych swoich funkcjach. Otwórz plik .map zobacz jaka inna zmienna jest w okolicy feralnej zmiennej i sprawdź funkcje które operują na "sąsiadach".

  • #19 13 Cze 2013 18:20
    djfarad02
    Poziom 17  

    Dziękuję wszystkim za pomoc i za zainteresowanie, problem rozwiązany. Oczywiście powodem był głupi błąd, jak zwykle. Tablica w wywoływanej funkcji była o bajt za krótka i następowało zamazanie pamięci.
    Nauczyłem się dzięki temu jak daleko od źródła problemu mogą pojawić się jego efekty i w jak nieoczekiwany sposób porblemy mogą być tajemniczo maskowane.

    Jako ciekawostkę podam listing asemblerowy po komiplacji, o ile inaczej kompilator generuje kod podczas drobnych zmian w programie w zupełnie innych miejscach.

    Asm dla fragmentu, który nie był zmieniany a kompilator zmienił sposób kompilacji gdy komentowałem jedną linię w zupełnie innym miejscu:

    Kod: asm
    Zaloguj się, aby zobaczyć kod

  • #20 14 Cze 2013 10:14
    szelus
    Specjalista - Mikrokontrolery

    To, co tu się dzieje (na listingu) wynika z prostej rzeczy. Przy włączonej optymalizacji kompilator stara się trzymać zmienne robocze (przede wszystkim automatyczne) w rejestrach, zamiast na stosie. Jak zaczyna tych rejestrów brakować, to zmienne musi odłożyć na stos (drugi listing, użycie rejestru Y).
    Jeżeli faktycznie jedynym błędem była o bajt za krótka tablica na stosie, jak piszesz, to prawdopodobne jest (trzeba by podejrzeć dokładniej listing), że następowało nadpisywanie młodszego bajtu adresu powrotu z funkcji, lub odłożonego wskaźnika tzw. ramki (Y) itp. i w efekcie np. powrót nie w to miejsce co trzeba lub po powrocie niepoprawna lokalizacja zmiennych lokalnych itd.
    Ogólnie, to nadpisywanie stosu należy do złośliwych błędów - efekty mogą być bardzo dziwne. Dlatego zwykle (w programach na mikrokontrolery) raczej unika się deklarowania tablic, buforów itp. jako zmiennych automatycznych (na stosie).

  • #21 02 Sty 2014 11:46
    mr.Sławek
    Poziom 31  

    Witam
    Miałem podobny problem jak autor tematu. Nie byłem w stanie dojść co jest nie tak. Dopisanie linijki do kodu (nie ważne jakiej) choćby i nop-a zmieniało diametralnie działanie programu tak samo jak i zmiana kolejności linijek. Bez optymalizacji było dobrze- przy włączonej optymalizacji pojawiały się dziwne błędy.
    Program rysował wirujące sześciany na wyświetlaczu- z optymalizacją pojawiały się przerywane kreski w ich rogach i piksele w zależności od kąta obrotu których być tam nie powinno. Pamiętam, że nie szło dojść co się dzieje.

  • #22 02 Sty 2014 12:31
    djfarad02
    Poziom 17  

    Problem z tego wątku został już rozwiązany. Przyczyną był mój szkolny błąd - za mała tablica o 1bajt.

TME logo Szukaj w ofercie
Zamknij 
Wyszukaj w ofercie 200 tys. produktów TME
TME Logo