Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATMega16] Odczytywanie pamięci programu - dziwne zachowanie

04 Kwi 2011 19:27 1224 8
  • Poziom 11  
    Witam,

    straciłem dzień na uporanie się z niesamowicie dziwnym zachowaniem programu. Otóż w pamięci programu mam zapisaną tablicę melodia[500][3] przechowującą w każdym wierszu odpowiednio częstotliwość tonu długość tonu i odstęp czasowy od następnego tonu.

    Procedura odegrajMelodie() ma za zadanie wywołać dla każdego wiersza procedurę generującą ton o częstotliwości i czasie trwania odczytanej z pamięci programu. I teraz co dziwne: podczas debugowania, do poszczególnych (poniższych) zmiennych, ładowane są prawidłowe wartości:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Skupmy się na zmiennej frequency i pierwszym tonie jaki generuje układ (zaraz na początku) - ton 660Hz. Gdy uruchomię powyższy kod, to pomimo wczytywania prawidłowej wartości do zmiennej (sprawdzałem prawidłowość wczytanej wartości przez debugger i poprzez warunek IF), generowany ton jest dużo niższy niż gdybym uruchomił taki kod:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dlaczego tak się dzieje? Jaka może być tego przyczyna. W obu wypadkach do funkcji generujTon wchodzi jako pierwszy parametr liczba 660, a wyniki są różne w zależności od tego skąd ta liczba pochodzi (wpisana ręcznie czy odczytana z pamięci programu). Funkcja odegrajMelodie() jest wywoływana tylko raz. Nie dzieje się tak przy wyłączonych optymalizacjach kompilatora, ale wtedy znowu źle działają funkcje opóźniające _delay_**.

    Z góry serdecznie dziękuję za jakąś podpowiedź.
  • Moderator Mikrokontrolery Projektowanie
    Witaj,
    1. Pokaż jak masz zdefiniowane parametry w funkcji generujTon().
    2. Możesz wymusić na zmiennych unsigned ponieważ pgm_read_word() zwraca unsigned int ?
    3. Pokaż początek tablicy z danymi.
    4. Jaką masz włączoną optymalizację?
  • Poziom 11  
    Dzień dobry, dziękuję za zainteresowanie. Problem jest sporą zagadką dla mnie.
    Muszę się przyznać, że wprowadziłem niechcąco kolegów w błąd. Otóż - przy wyłączonych optymalizacjach jednak się tak nie dzieje, ale nie działają wtedy poprawnie procedury opóźniające _delay_** (co jest normalne).


    Odnośnie pkt. 1:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Odnośnie pkt. 2:
    co ciekawe, jeśli przestawie we wszystkich miejscach w programie "unsigned long int" na "unsigned int", to pomimo, że liczby nigdzie nie wychodzą poza 65535 (nie ma też liczb ujemnych) - wszystko się knoci jeszcze bardziej. A przecież odczytuje z tablicy WORD, czyli uint_16_t.

    Odnośnie pkt. 3:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Odnośnie pkt. 4:
    Próbuję kompilować cyklicznie na różnych optymalizacjach (O1, O2, O3, Os) - muszę ich używać ze względu na korzystanie z procedur _delay_**.

    Cóż.. wygląda na to, że to wina optymalizacji - czy coś można poradzić? Może volatile?

    Dodano po 1 [godziny] 45 [minuty]:

    Problem rozwiązany. Użycie volatile w deklaracji zmiennych spowolniło program, ale zagwarantowało poprawne działanie. Prawdopodobnie, w ramach optymalizacji, gdy kompilator zauważył, że do zmiennej podstawiona jest stała wartość, wprowadzał ją we wszystkich miejscach jako rozwinięcie "inline", co przyspieszało znacząco obliczenia (umożliwiając obliczenie wyniku już w trakcie kompilacji) - stąd dźwięk był wyższy gdy wartość zmiennej wprowadzałem ręcznie, a inny gdy wartość pobierana była z pamięci programu (choć w obu przypadkach była to ta sama wartość).

    Tak jak napisałem, użycie volatile rozwiązuje problem. Stracone półtora dnia, ale czegoś się dowiedziałem przynajmniej.

    Chciałem jeszcze coś dodać, mniej lub bardziej oczywistego, mianowicie: należy pamiętać, aby zmienna podawana jako argument funkcji _delay_** NIE była volatile, ponieważ w przeciwnym wypadku cała funkcja _delay_** nie będzie optymalizowana, tak więc nie będzie poprawnie działała (optymalizacja jest konieczna do prawidłowego działania funkcji _delay_**).

    Pozdrawiam serdecznie.
  • Moderator Mikrokontrolery Projektowanie
    Hmm, mam wrażenie, że volatile nie rozwiązało prawidłowo Twojego problemu.
    Przekazujesz parametry poprzez argumenty funkcji i volatile nie jest Ci potrzebne, aczkolwiek nie znam zawartości funkcji generujTon().
    Na których zmiennych dałeś volatile?
  • Poziom 11  
    Witam,
    wydaje mi się, że problem został jednak rozwiązany. Modyfikator volatile postawiłem przy zmiennych frequency, duration, pause oraz w prototypie funkcji generujTon(). I wszystko "gra" - dosłownie :-) Nie zmienia to faktu, że bardzo nie lubię GCC.

    Pozdrawiam serdecznie,
  • Pomocny post
    Moderator Mikrokontrolery Projektowanie
    elektronik_hobbysta napisał:
    Modyfikator volatile postawiłem przy zmiennych frequency, duration, pause oraz w prototypie funkcji generujTon().

    Tak sądziłem. Moim zdaniem volatile w tym wypadku jest niepotrzebne.

    Spróbuj tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    a z definicji generujTon(...) usuń volatile.
  • Poziom 11  
    Usunąłem volatile, tak jak Pan sugerował. Działa. Nie bardzo rozumiem w czym tkwił prawdziwy błąd? Czy w deklarowanie zmiennych wewnątrz pętli absorbuje tutaj za każdym razem nowy obszar pamięci, nie zwalniając poprzedniego?
  • Moderator Mikrokontrolery Projektowanie
    elektronik_hobbysta napisał:
    Usunąłem volatile, tak jak Pan sugerował.

    Śmiało pisz per Ty - nawet jeżeli jestem dużo starszy :)

    elektronik_hobbysta napisał:
    Czy w deklarowanie zmiennych wewnątrz pętli absorbuje tutaj za każdym razem nowy obszar pamięci, nie zwalniając poprzedniego?

    Na 100% pewien nie jestem, ale tak właśnie sądzę.
  • Poziom 11  
    dondu napisał:
    Śmiało pisz per Ty - nawet jeżeli jestem dużo starszy :)

    OK :)

    Klikam "pomógł" i dziękuję Ci za czas.