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

[atmega32] - RTC, przerwania Timer2, maksymalna częstotliwość 32768Hz

grzegorz-00 02 Sty 2015 23:00 1323 19
  • #1 14284296
    grzegorz-00
    Poziom 13  
    Witam

    Mam problem z RTC w atmega32. Podłączyłem kwarc 32,768kHz jak datasheet nakazuje. Jeśli Timer2 skonfiguruje następująco:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To przerwanie
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Wykona się tylko 8192 razy na sekundę zamiast 32768.

    Natomiast jak timer2 inicjuje:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To przerwanie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Wykonuje się 16384 razy, ale jak wywołam jednorazowo inne przerwanie i w nim dam jakiś delay (wiem, że tak się nie robi) to częstotliwość spada do 8192Hz. Ktoś zna przyczynę dlaczego tak jest? Ogólnie chodzi mi o jak największą częstotliwość wywołania przerwania.

    Pozdrawiam
  • #2 14284418
    grzegorz-00
    Poziom 13  
    Chodziło mi o max częstotliwość uzyskaną z kwarca zegarkowego.
  • #3 14284426
    dasej
    Poziom 32  
    Witam,

    A zegar atmegi?

    Czas potrzebny na wykonanie 32768 przerwań to 1 sekunda co daje czas na jedno przerwanie 30.5 mikrosekundy.

    Sprawdź w dokumentacji ile at8 zużywa taktów zegarowych na wykonanie jednego przerwania.
    Należy pamiętać że przy pisaniu w C nie masz kontroli na tym co robi kompilator.
    Zapisanie rejestrów na stosie przy wejściu w przerwanie też pochłania czas o który się bijesz.

    krótki temat i taktach zegarowych i czasach
    https://www.elektroda.pl/rtvforum/topic815177.html#4182879
  • #4 14284521
    grzegorz-00
    Poziom 13  
    Atmega jest taktowana zewnętrznym kwarcem 16mHz. Dzieląc 16Mhz przez 32kHz wychodzi mi około 488 cylki. Poza tym nie ma znaczenia czy kod w przerwaniu zajmuje 3 linijki czy 100. Przerwanie wykonuje się dokładnie tyle razy. Zegar na tym zrobiony ma błąd mniejszy niż 1 sec na dobę więc nie ma mowy, że uC nie wyrabia.
  • #5 14284566
    dasej
    Poziom 32  
    grzegorz-00 napisał:
    Poza tym nie ma znaczenia czy kod w przerwaniu zajmuje 3 linijki czy 100.


    Ciekawe stwierdzenie. Przerwanie jest wykonywane do końca. Kolejne nie zostanie obsłużone do puki nie skończy się poprzednie.
  • #6 14284579
    dondu
    Moderator na urlopie...
    grzegorz-00 napisał:
    Wykonuje się 16384 razy, ale jak wywołam jednorazowo inne przerwanie i w nim dam jakiś delay (wiem, że tak się nie robi) to częstotliwość spada do 8192Hz. Ktoś zna przyczynę dlaczego tak jest?

    Nie podajesz jaki delay taki efekt generuje. Zapewne jest tak, że przerwania gubione są przez fakt, iż flaga przerwań nie jest buforowana. Jeśli więc wystąpi jedno przerwanie, które od razu po wejściu w funkcję przerwania blokuje globalne przerwania (bo tak stosujesz w swoim kodzie), a w nim jest delay, to inne przerwanie może występować kilka razy w tym czasie, ale jego flaga jest tylko jedna. Stąd po zakończeniu pierwszego z przerwań drugie wykona się tylko raz, pomimo, że było zgłaszane np. 3 razy.

    a opisane jest to tak:

    Cytat:
    The I-bit is cleared by hardware after an interrupt has occurred, and is set by the RETI instruction to enable subsequent interrupts.
  • #7 14284583
    grzegorz-00
    Poziom 13  
    dasej napisał:
    Ciekawe stwierdzenie. Przerwanie jest wykonywane do końca. Kolejne nie zostanie obsłużone do puki nie skończy się poprzednie.


    Owszem. Może źle się wyraziłem. Chodziło mi, że jak w moim programie wyrzucę wszystko z przerwania ( no dobra, nie 100 a 70 linijek) to nie ma żadnej różnicy, stąd wniosek, że to nie problem z wyrabianiem procesora.

    dondu napisał:
    [...] Stąd po zakończeniu pierwszego z przerwań drugie wykona się tylko raz, pomimo, że było zgłaszane np. 3 razy.


    Tak. Ale napisałem, że przerwanie z delayem np 10ms wykonuję tylko jeden raz. Powiedzmy, że w tym czasie przyszły np. 4 zgłoszenia. Wykona się tylko jedno ale potem już powinny lecieć w takim samym odstępie jak wcześniej a lecą z 2x większym odstępem.
  • #9 14284626
    zumek
    Poziom 39  
    grzegorz-00 napisał:
    Natomiast jak timer2 inicjuje:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To przerwanie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Wykonuje się 16384 razy...

    I prawidłowo, ponieważ 32768/Preskaler/(OCR+1)=16384.
    Zastanawiam się, po co Ci przerwanie co 1 takt Timera2 napędzanego kwarcem zegarkowym :?:
  • #11 14284642
    grzegorz-00
    Poziom 13  
    zumek napisał:
    grzegorz-00 napisał:

    Wykonuje się 16384 razy...

    I prawidłowo, ponieważ 32768/Preskaler/(OCR+1)=16384.
    Zastanawiam się, po co Ci przerwanie co 1 takt Timera2 napędzanego kwarcem zegarkowym :?:


    Racja. Gdyby się to jeszcze nie zacinało, było by fajnie. Timerem2 mierzę długość trwania impulsów.

    Ogólnie to problem pojawił się jak wysyłałem inf. przez rs232 do atmegi. Kod mam tak napisany, że każdy odebrany znak jest automatycznie wysyłany. O ile odbiór mam zrobiony na przerwaniach to nadawanie jest zrobione klasycznie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    I kiedy zapodam na raz za dużo znaków, timer2 zaczyna fiksować. Doszedłem do tego, że jak zamiast tej funkcji dam _delay_ms(1); to dzieje się tak samo. Pewnie jak bym zrobił wysyłanie na przerwaniach to wszystko by działało, ale nurtuje mnie dlaczego tak się dzieje, co jest tego przyczyną.
  • #13 14284680
    grzegorz-00
    Poziom 13  
    dondu napisał:
    Może opisz dokładnie co chcesz osiągnąć, a wtedy podpowiemy rozwiązanie.


    Potrzebny jest mi blok kodu wykonywany co najmniej 16 tys razy na sekundę z dość dużą dokładnością.
  • #14 14284684
    piotrva
    VIP Zasłużony dla elektroda
    Ale w jakim celu?
    W sensie podaj nam opis problemu jaki chcesz rozwiązać - może jest inne rozwiązanie, nie wymagające tak karkołomnych operacji ;)
  • #15 14284695
    dondu
    Moderator na urlopie...
    grzegorz-00 napisał:
    dondu napisał:
    Może opisz dokładnie co chcesz osiągnąć, a wtedy podpowiemy rozwiązanie.

    Potrzebny jest mi blok kodu wykonywany co najmniej 16 tys razy na sekundę z dość dużą dokładnością.

    Nadal za mało napisałeś ... 16 tys/sek, to mało i dużo jednocześnie.
    Wszystko zależy co ten blok będzie wykonywał i czy mikrokontroler będzie w stanie się wyrobić.

    Poza tym, co oznacza: "... z dość dużą dokładnością"
    Elektronika to dziedzina ścisła .... baaaaaardzo. :)
  • #16 14284697
    grzegorz-00
    Poziom 13  
    Robię komputer pokładowy do starego samochodu. Wyżej wspomniany blok kodu odpowiada za pomiar długości impulsu wtrysku, odstęp między impulsami od cewki silnika i odstęp między impulsami od czujnika halla, odpowiedzialnego za mierzenie prędkości kół. W poprzedniej wersji pętla wykonywałą się właśnie 8192 razy na sekundę. Teraz chciałem podwoić dokładność. Już wszystko ładnie działa, mierzy co trzeba i wysyła po rs232 tylko problem jest jak ja coś wyślę do uC.

    Przy 16k/sec mikrokontroler napewno się wyrabia. W przerwaniu jest inkrementowana zmienna. Jak przekroczy 16383 to jest zerowana, a zmienna przechowująca sekundy jest inkrementowana. Jak pisałem wcześniej, błąd jest mniejszy niż sec. na dobę więc nie gubi żadnych przerwań.
  • #18 14284749
    grzegorz-00
    Poziom 13  
    Tak, słyszałem o tym. Problem w tym, że ja mam 3 takie sygnały. Zmieniłem źródło taktowania timera2 na kwarc taktujący cały proc (16Mhz). Najpierw dałem preskaler 1024 co daje częstotliwość ok. 15khz. Wszystko działa bez zająknięcia. Potem ustawiłem preskaler na 256 co daje częstotliwość ok. 62khz. Wszystko dalej śmiga jak należy więc problem z niewyrabianiem uC się na 100% nie pojawia.

    W tym przypadku nawet jak dam _delay_ms(100) to uc na chwilę się zawiesza ale potem idzie normalnie.
  • #19 14284774
    dondu
    Moderator na urlopie...
    grzegorz-00 napisał:
    Tak, słyszałem o tym. Problem w tym, że ja mam 3 takie sygnały.

    Skoro to silnik, to ma stałe kąty. Wystarczy więc mierzyć tylko jeden sygnał, a pozostałe kąty odmierzać timerem i przerwaniem. Tak? Czy to jakiś specyficzny przypadek?

    To rozwiązanie, które próbujesz zrobić jest ryzykowne.
    Przemyśl sprawę - a ja śmigam spać.
  • #20 14284813
    grzegorz-00
    Poziom 13  
    Ehhh. Sprawa się poniekąd wyjaśniła. Ma być TCCR2 = 0b00001001 zamiast TCCR2 = 0b01000001. WGM21 pomyliło mi się z WGM20. Zamiast CTC był tryb PWM Phase Correct. Teraz wszystko działa bez zacinania. Dalej nie wiem czego w trybie Normal dzieli sygnał przez 4 ale może jakoś przeżyję.

    Przepraszam za niepotrzebne zamieszanie.

    Pozdrawiam

    EDIT:

    dondu napisał:
    Wystarczy więc mierzyć tylko jeden sygnał, a pozostałe kąty odmierzać timerem i przerwaniem. Tak? Czy to jakiś specyficzny przypadek?


    Chyba tak się nie da. Jeden sygnał to podobnie jak tam obroty silnika. Ale kolejny to już sygnał wtrysku, gdzie mierzymy tylko długość impulsu. A 3 sygnał pochodzi z kół i już nic nie ma wspólnego z silnikiem.

    Wg. mnie koncepcja robienia wszystkiego na przerwaniu jest ok. Co prawda kod w przerwaniu na kilkadziesiąt linijek, ale w tym przypadku w niczym to nie przeszkadza. Byle tylko kolejne przerwania nie zachodziły na siebie. Jak ktoś jest zaciekawiony projektem/pomysłem to odsyłam na stronę:
    http://stm32.eu/node/275
    Jest to jedna z poprzednich wersji, którą robiłem na stm32 będąc jeszcze w liceum dlatego kod jest masakryczny ale działa a idea mierzenia sygnałów nie zmieniła się dużo od tamtego czasu ;)
REKLAMA