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

sei(); i cli(); szybkie pytanie

ravmar 09 Gru 2011 12:28 8505 25
REKLAMA
  • #1 10237339
    ravmar
    Poziom 22  
    Nie mogę sobie poradzić z przerwaniem na INT1. Piszę program do komunikacji
    dwustronnej z RFM12B. Urządzenie nasłuchuje (jest włączone przerwanie na INT1
    w przypadku pojawienia się stanu niskiego następuje uruchomienie przerwania i
    odebranie danych):

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


    w przypadku odbioru informacji przez uC ten chce chce coś nadać zwrotnego, w
    tym celu przechodzi do odpowiedniej funkcji która na samym początku "robi":

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

    wtedy transiver nadaje to co ma nadać (na PINie - INT1 w przypadku możliwości
    przesłania paczki (poprzednia wyszła) pojawia się stan niski, wtedy uC wie, że
    może nadać kolejną paczkę, w przypadku zajętości transivera stan wysoki)
    Funkcja wykonuje się bez żadnych przeszkód. Problem pojawia się kiedy chce
    włączyć obsługę przerwań komendą

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


    Automatycznie zostaje wrzucony w funkcję odpowiadającą za wykonanie
    przerwania, a to dlatego, że wykonuje ona zaległe przerwanie wynikające z
    wcześniejszej operacji wysyłania danych i zmiennych stanów na "INT1" a mi
    właśnie o to chodzi, żeby na czas wysyłania wyłączyć przerwania i po wykonaniu
    tej operacji włączyć je z powrotem i nie wskakiwać tam od razu tylko po
    przyjściu paczki
  • REKLAMA
  • Pomocny post
    #2 10237394
    snnaap
    Poziom 25  
    Po wykryciu stanu niskiego na INT1 zaraz po wejściu w obsługę przerwania wyłącz przerwanie od INT1 czyli:

    EIMSK &=~_BV(INT1); //wyłącz obsługę przerwań Int1

    a dokładniej tak po nowemu:

    EIMSK &=~(1<<INT1);

    następnie w zależności od potrzeb możesz wyłączyć pozostałe przerwania.

    Jeżeli używasz wyjścia nIRQ układu RFM12B zwróć uwagę na to że na wyjściu tm stan niski nie pojawia się jedynie przy odebranym "pakiecie" lecz może pojawiać się w innych sytuacjach.
    Należy pamiętać, aby po wysłaniu wyczyścić flagi przerwań w rejestrze statusu RFM12B.


    Dla własnego spokoju sprawdź jaki jest stan końcówki nIRQ po wysłaniu czegoś zwrotnego:D

    Mam nadzieje że napisałem to jakoś logicznie i ze zrozumieniem.

    Pozdrawiam.


    PS Jak już to powinno być:
    EIMSK |= _BV(INT1); //włącz obsługę przerwań Int1
  • Pomocny post
    #3 10237420
    Andrzej__S
    Poziom 28  
    Możesz wyzerować flagę przerwania INT1 przed instrukcją sei();:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    EDIT:
    snnaap napisał:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Obawiam się, że to nie uchroni przed ustawieniem przez mikrokontroler flagi INTF1, więc po ponownym włączeniu przerwania INT1 ( EIMSK |=_BV(INT1); ) i ustawieniu flagi globalnej ( sei(); ), program natychmiast wejdzie w procedurę obsługi tego przerwania. Wyzerowanie flagi i tak będzie konieczne.
  • #4 10238273
    ravmar
    Poziom 22  
    Panowie bardzo dużo pomogli duże plusy :)
    snnaap napisał:

    Jeżeli używasz wyjścia nIRQ układu RFM12B zwróć uwagę na to że na wyjściu tm
    stan niski nie pojawia się jedynie przy odebranym "pakiecie" lecz może pojawiać się
    w innych sytuacjach.


    Specyfikacja podaje, że nIRQ (praca jako odbiornik) będzie niskie jeżeli RFM12 coś
    odbierze do czasu wyzerowania przez użytkownika rejestru FIFO

    snnaap napisał:

    Należy pamiętać, aby po wysłaniu wyczyścić flagi przerwań w rejestrze statusu RFM12B.

    Możesz wytłumaczyć dokładniej?
  • Pomocny post
    #5 10239277
    snnaap
    Poziom 25  
    U mnie wyglądała to następująco:
    1. W obsłudze przerwania mam tak:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    gdzie:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    następnie sprawdzam flagę sRF jeżeli jest 1 odbieram dane przełączam RFM12B na nadajnik wysyłam ramkę i przełączam RFM12B z powrotem na odbiornik wysyłając do RFM12B następujące dane:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    // po wysłani do RFM12B powyższego końcówka nIRQ idzie u mnie do góry.

    Następnie ustawiam 0 na mojej fladze sRF i uwłaczam przerwanie od INT1
    Kod: text
    Zaloguj się, aby zobaczyć kod


    i u mnie tak to działa:D

    PS. uK to t2313
  • Pomocny post
    #6 10239426
    Andrzej__S
    Poziom 28  
    Kolega snaap nie napisał jeszcze, jak ma skonfigurowane przerwanie INT1. Ja podejrzewam, że ma wyzwalanie stanem niskim, a nie tak jak kolega ravmar (autor wątku) zboczem opadającym.
    Różnica między tymi dwoma typami przerwań polega na tym, że w tym pierwszym (wyzwalanym stanem niskim) flaga INTF1 jest zawsze zerowana, niezależnie od tego, czy przerwanie zostanie obsłużone, czy nie. Przerwanie wyzwalane zboczem z kolei ustawi flagę INTF1, która będzie ustawiona do momentu obsługi przerwania lub programowego jej wyzerowania.

    EDIT:
    Dodam jeszcze dla ścisłości, że maska przerwań nie blokuje ustawiania odpowiednich flag przerwań, ona tylko blokuje wejście w procedurę obsługi danego przerwania w przypadku, gdy jego flaga jest ustawiona.
  • Pomocny post
    #7 10239684
    snnaap
    Poziom 25  
    Andrzej__S napisał:
    Kolega snaap nie napisał jeszcze, jak ma skonfigurowane przerwanie INT1. Ja podejrzewam, że ma wyzwalanie stanem niskim, a nie tak jak kolega ravmar (autor wątku) zboczem opadającym.
    Różnica między tymi dwoma typami przerwań polega na tym, że w tym pierwszym (wyzwalanym stanem niskim) flaga INTF1 jest zawsze zerowana, niezależnie od tego, czy przerwanie zostanie obsłużone, czy nie. Przerwanie wyzwalane zboczem z kolei ustawi flagę INTF1, która będzie ustawiona do momentu obsługi przerwania lub programowego jej wyzerowania.

    EDIT:
    Dodam jeszcze dla ścisłości, że maska przerwań nie blokuje ustawiania odpowiednich flag przerwań, ona tylko blokuje wejście w procedurę obsługi danego przerwania w przypadku, gdy jego flaga jest ustawiona.




    Masz racje, obecnie przerwanie mam ustawione na stan niski bo tylko takie wybudza uK.

    Przy reakcji na zbocze odpadające należny przed włączeniem przerwania wyczyścić flagę INTF1.


    Pozdrawiam
  • Pomocny post
    #8 10239961
    aaadamw
    Poziom 16  
    snnaap napisał:

    Jeżeli używasz wyjścia nIRQ układu RFM12B zwróć uwagę na to że na wyjściu tm stan niski nie pojawia się jedynie przy odebranym "pakiecie" lecz może pojawiać się w innych sytuacjach.


    nIRQ reaguje tak:
    sei(); i cli(); szybkie pytanie

    snnaap napisał:

    Należy pamiętać, aby po wysłaniu wyczyścić flagi przerwań w rejestrze statusu RFM12B.

    to raczej nie będzie konieczne.
    jeżeli korzysta się z nIRQ, to nie trzeba korzystać z statusu.
  • REKLAMA
  • #9 10241495
    ravmar
    Poziom 22  
    Mój program realizuje to tak:

    W przypadku gdy ktoś inny nadaje, u mnie jest generowane przerwanie z nIRQ i
    odczytanie informacji z różnymi wariantami decyzji. Z tego co mi wiadomo
    program nie wykona innego przerwania będąc w jednym, ani nie rozpocznie
    wykonywania w połowie przerwania tegoż samego przerwania jeżeli ponownie
    dostanie stan niski/zbocze opadające. Wykona do końca owe przerwanie w
    zależności czy jest aktywne sei(); i jeżeli któraś z flag w rejestrach wskazuje na
    przerwanie będzie on wykonane jako następne. Dlatego na końcu funkcji
    przerwania od nIRQ czyszczę flagę przerwania EFIR INT1'(nIRQ)', ponieważ "nie
    wiem/nie obchodzi mnie" co się działo z linią nIRQ podczas obsługiwania
    przerwania. Jeżeli zmieniała swoje stany to po wyjściu z przerwania INT1 wróci
    tam z powrotem przez ustawioną flagę EFIR.

    Pytanie do Andrzej__S lepiej, zmienić wywołanie przerwania na stan niski, czy
    zostawić zbocze opadające ?

    I takie pytanie do znawców RFM12 tak delikatnie poza tematem :)
    Dla zwiększenia niezawodności układów przed nadawaniem wprowadzam taką oto
    funkcję:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    z myślą zrealizowania prymitywnego CSMA/AC co prawda program w swojej pracy
    nie wykazuje żadnych zmian, jak sądzicie ma to racje bytu ?

    writeCmd(0x0000) - zwraca 2 bajty statusowe
    RSSI - (moc przychodzącego sygnału) jest na pozycji 8 zwracanego statusu
  • REKLAMA
  • Pomocny post
    #10 10241672
    aaadamw
    Poziom 16  
    ravmar napisał:

    writeCmd(0x0000) - zwraca 2 bajty statusowe
    RSSI - (moc przychodzącego sygnału) jest na pozycji 8 zwracanego statusu


    ten bit nie zwraca mocy sygnału, tylko informuje czy moc jest powyżej ustawionego poziomu. Poziom ten ustawia się na ostatnich trzech birach rejestru 0x90XX.

    ogólnie nie wiem czy ma to sens...
  • #11 10241903
    ravmar
    Poziom 22  
    Jeżeli chodzi o zwiększenie niezawodności i możliwości wystąpienia kolizji pakietów to sens jakiś ma, aczkolwiek teraz przeglądam tą dokumentacje i jednak widzę, że dam sobie z tym spokój ;)
  • Pomocny post
    #12 10241928
    Andrzej__S
    Poziom 28  
    ravmar napisał:
    Pytanie do Andrzej__S lepiej, zmienić wywołanie przerwania na stan niski, czy
    zostawić zbocze opadające ?


    Kolega snaap skorzystał z wyzwalania stanem niskim ze względu na to, że miał potrzebę wybudzania mikrokontrolera ze stanu uśpienia. Dodatkowo w obsłudze przerwania ustawiał tylko odpowiednią flagę, a resztę operacji wykonywał w głównej pętli programu. Musiał więc zastosować opisaną przez niego taktykę blokowania przerwania na czas odbierania danych, ponieważ przerwanie wywoływane stanem niskim będzie wykonywało się "na okrągło", dopóki na pinie INT1 będzie występował stan niski. Utrudniłoby to znacznie lub nawet uniemożliwiło normalne wykonywanie programu.

    Gdyby istniała możliwość wykonania wszystkich operacji wewnątrz obsługi przerwania i pewność, że po zakończeniu obsługi pin INT1 jest w stanie wysokim, to można by to blokowanie pominąć, ponieważ globalna flaga zezwalająca na przerwania (I w SREG) jest wtedy wyzerowana na czas obsługi przerwania, a flaga przerwania wyzwalanego stanem niskim nie jest zapamiętywana - po prostu przerwanie jest wykonywane tylko wtedy, kiedy pin jest w stanie niskim, maska przerwań zezwala na to przerwanie i flaga I w SREG jest ustawiona. Jeśli więc po zakończeniu obsługi przerwania pin INT1 jest w stanie wysokim, to program nie wejdzie ponownie do obsługi tego przerwania niezależnie od tego, czy i ile razy w czasie obsługi tego przerwania był w stanie niskim.

    W przypadku wyzwalania zboczem flaga przerwania INTF1 w rejestrze EIFR zostaje zapamiętana do momentu wejścia w obsługę przerwania (mikrokontroler zeruje ją wtedy automatycznie) lub "ręcznego" programowego jej wyzerowania, kiedy ustawienie tej flagi w trakcie wykonywania jakiegoś fragmentu programu jest nieistotne lub niepożądane.

    Wszystko zależy więc od tego, jaką masz ogólną koncepcję całego programu, jaka długa jest procedura obsługi przerwania, jakie inne zadania ma do wykonania mikrokontroler, czy korzystasz z innych przerwań itp. itd.
  • #13 10243876
    ravmar
    Poziom 22  
    Rozumiem, mój program działa poprawnie i chyba zostanę przy zboczu opadającym.
    Dołożę jeszcze watchdoga dla zwiększenia niezawodności i kilka innych głupot:)

    Pozwolę sobie jeszcze nie zamykać tematu i zostawić możliwość zadania
    pochodnych pytań związanych z AVR i przerwaniami (chyba ze moderator
    zdecyduje inaczej)

    Andrzej__S i snnaap czysta przyjemność czytać wasze rady,
    zwłaszcza, że znacie się na rzeczy i potraficie ją wyjaśnić. Do mnie to dociera i to
    chwytam :)
  • #14 11468792
    ravmar
    Poziom 22  
    Miną rok i jak czytam swoje brednie to mało pod ziemię się nie zapadnę ze wstydu:) Za rok z tym postem będzie pewnie podobnie :)
    Reaktywacja projektu, wyższy stopień wtajemniczenia. Nie zakładam drugiego tematu ponieważ jest to zbyteczne.
    Pytanie dotyczy poniekąd sei(); i cli(); szybkie pytanie

    TIFR |= (1<<OCF0); Zerowanie flagi przerwań od komparatora
    , a jak wymusić wykonanie przerwania, coś w stylu on-demand
    puki co OCR0 = 255 i wpisuję w licznik wartość 254 ale to jest co najmniej śmieszne
  • Pomocny post
    #15 11468988
    tmf
    VIP Zasłużony dla elektroda
    Najprościej i zawsze skutecznie to po prostu wywołać dane ISR - przecież to zwykłe funkcje języka C - jedyna różnica jest taka, że mają atrybut interrupt oraz, że będą wywołane bez zmiany stanu przerwań (ich blokowania), co czasami może czynić różnicę.
  • #16 11469196
    Andrzej__S
    Poziom 28  
    ravmar napisał:
    ...a jak wymusić wykonanie przerwania...

    Programowe ustawianie flag przerwań jest w AVR niemożliwe.
    Można zrobić jak proponuje kolega tmf. Można też wywołać przerwanie np. wykorzystując następującą cechę przerwań zewnętrznych (będzie potrzebny jeden wolny pin):
    Atmel napisał:

    ATmega48A/48PA/88A/88PA/168A/168PA/328/328P
    ....
    The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins. Observe that, if enabled, the interrupts will trigger even if the INT0 and INT1 or PCINT23...0 pins are configured as outputs. This feature provides a way of generating a software interrupt.
    ....

    Można też kombinować na różne inne sposoby, tylko czy naprawdę jest Tobie to potrzebne?
    Ciekaw jestem po prostu do czego chciałbyś to wykorzystać, bo być może da się to rozwiązać inaczej.
  • #17 11469303
    ravmar
    Poziom 22  
    tmf napisał:
    Najprościej i zawsze skutecznie to po prostu wywołać dane ISR - przecież to zwykłe funkcje języka C - jedyna różnica jest taka, że mają atrybut interrupt oraz, że będą wywołane bez zmiany stanu przerwań (ich blokowania), co czasami może czynić różnicę.

    Ale uruchomione już w istniejącym przerwaniu zostaną wykonane bezzwłocznie, a mi zależy na wykonaniu tego przerwania po ukończeniu już trwającego

    Cytat:

    Można też kombinować na różne inne sposoby, tylko czy naprawdę jest Tobie to potrzebne?
    Ciekaw jestem po prostu do czego chciałbyś to wykorzystać, bo być może da się to rozwiązać inaczej.
    Nawet nie wiem czy dam rade opisać do czego to potrzebuje mogę rzucić kawałek kodu. Rozchodzi się o obsługę dalej RFM :)
  • Pomocny post
    #18 11469397
    tmf
    VIP Zasłużony dla elektroda
    ravmar napisał:
    tmf napisał:
    Najprościej i zawsze skutecznie to po prostu wywołać dane ISR - przecież to zwykłe funkcje języka C - jedyna różnica jest taka, że mają atrybut interrupt oraz, że będą wywołane bez zmiany stanu przerwań (ich blokowania), co czasami może czynić różnicę.

    Ale uruchomione już w istniejącym przerwaniu zostaną wykonane bezzwłocznie, a mi zależy na wykonaniu tego przerwania po ukończeniu już trwającego


    No to wywołaj ISR na końcu bieżącego, w czym problem? Chyba, że chcesz sekwencji ISR (ten który wywołuje kolejny), instrukcja kodu z main, ISR (wywoływany). Wtedy to pozostaje zmienić koncepcję :)
  • REKLAMA
  • #19 11469546
    ravmar
    Poziom 22  
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Niedawno zacząłem pisać więc dużo nie ma ale systematycznie uruchamiam bloki i sprawdzam ich działanie. Do tej pory działa wszystko bez zarzutu.
    Zależy mi na wykonaniu TIMER0_COMP_vect po ukończeniu INT1_vect.
    Po ludzku, a nie tworzenie zmiennej flag i sprawdzania jej statusu na końcu przerwania
  • Pomocny post
    #20 11470515
    tmf
    VIP Zasłużony dla elektroda
    Jeśli nie chcesz flag to stwórz kolejny blok if. Nie wiem dlaczego flagi nie są ok, skoro nawet gdyby się dało wywołać przerwanie w sposób jaki chcesz, to byłoby to nic innego jak ustawienie flagi, tyle, że w rejestrze IO. Ale jeśli to ci się nie podoba, to w gcc jest jeszcze jedna możliwość (rozszerzenie standardu) - po opuszczeniu danego bloku/zniszczeniu zmiennej automatycznej istnieje możliwość wywołania funkcji czyszczącej - atrybut cleanup (przykłady masz tu http://mikrokontrolery.blogspot.com/2011/03/gcc-wycieki-pamieci-sprzatanie.html.
  • #22 11973341
    ravmar
    Poziom 22  
    Powracam :)
    Tym razem z takim pytaniem
    Mam dwa kody
    1.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    2.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    W pierwszym przypadku program działa poprawnie. Jeżeli moduł radiowy otrzyma znak, generuje przerwanie, które jest obsługiwane przez uC. Niestety w drugim przypadku uC nie reaguje na przerwania, a w kodzie zamieniona jest tylko miejscami część dot. inicjalizacji diód i "mrygnięcia".

    Starałem się dostrzec jakąś różnice w plikach lss niestety bezskutecznie(mogę wstawić jak potrzebne). Traktuję to pytanie jako naukę dlaczego tak się dzieje. Jeżeli ktoś jest wstanie to wytłumaczyć będę wdzięczny.
  • Pomocny post
    #23 11973553
    dondu
    Moderator na urlopie...
    Nie pokazujesz co jest w funkcjach:

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

    więc trudno wnioskować.

    Poszukaj, czy nie ma konfliktu miedzy deklaracjami pinów dla LED, a pinów używanych przez RFM .
  • #24 11974826
    ravmar
    Poziom 22  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


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


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


    SPI dla modułu RMF12B jest realizowany programowo na pinach portu D natomiast diody są podpięte pod pod piny w porcie A, więc nie powinno to mieć różnicy co będzie pierwsze
  • #25 11975556
    Andrzej__S
    Poziom 28  
    Najwyraźniej problem nie polega na kolejności konfiguracji portów.
    Zauważ, że przestawiłeś również opóźnienia za funkcje RFM12B_portInit() i (co ważniejsze) RFM12B_init().
    W nocie na stronie 34 poczytaj o czymś, co nazywa się Power on Reset.
    Krótki cytat:
    Cytat:
    "The reset event can last up to 100ms supposing that the Vdd reaches 90% its final value within 1ms. During this period, the chip does not accept control commands via the serial control interface."
  • #26 11976028
    ravmar
    Poziom 22  
    Andrzej__S napisał:
    Najwyraźniej problem nie polega na kolejności konfiguracji portów.
    Zauważ, że przestawiłeś również opóźnienia za funkcje RFM12B_portInit() i (co ważniejsze) RFM12B_init().
    W nocie na stronie 34 poczytaj o czymś, co nazywa się Power on Reset.
    Krótki cytat:
    Cytat:
    "The reset event can last up to 100ms supposing that the Vdd reaches 90% its final value within 1ms. During this period, the chip does not accept control commands via the serial control interface."


    And the winner is Andrzej !:)

    Dziękuje bardzo za pomoc. Mam nadzieję, że kiedyś będę w stanie tak logicznie myśleć jak wy, a rozwiązanie problemów będzie łatwiejsze.
    Jeszcze raz wielka piątka dla was.

    Pozwolę sobie nie zamykać jeszcze tematu :)

    Jeszcze na marginesie dodam, żebyście nie myśleli, że idę na skróty i pierwszy lepszy problem walę na elektrodę. Dokumentacje z modułów przeczytałem starannie z dobre 8 razy i cały czas z niej korzystam... no ale niestety wpadki się zdarzają.

    Nowy problem, nowy temat. Zamykam.
    Dar.El
REKLAMA