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

Jak wywołać programowe przerwanie w ATMEGA644 bez użycia wolnych pinów?

es2 17 Sty 2018 16:07 2256 51
  • #1 16968393
    es2
    Poziom 16  
    Szukam sposobu na wywołanie przerwania z programu. W ARM sprawa prosta, wpis do NVIC i mam dowolne przerwanie. W AVR rozwiązywałem to przez wolny pin GPIO. Ustawiałem jako PCINT, gdy potrzebowałem przerwania, ustawiałem GPIO w stan niski. W przerwaniu PCINT przywracałem poziom wysoki. Niestety nie mam wolnych pinów. Jest w AVR rozkaz BRK generujący przerwanie, ale to wszystko co o nim wiem. Szukałem czegoś na ten temat, i jak pamiętam służy do debugowania ale reszta informacji jest tajna.
    Jest jakiś sposób aby generować takie przerwanie?
  • Pomocny post
    #2 16968406
    BlueDraco
    Specjalista - Mikrokontrolery
    Ustaw znacznik gotowości w jakimś nieużywanym peryferialu albo załaduj timer wartością sprzed końca okresu i go włącz.
  • #3 16968420
    es2
    Poziom 16  
    BlueDraco napisał:
    Ustaw znacznik gotowości w jakimś nieużywanym peryferialu albo załaduj timer wartością sprzed końca okresu i go włącz.

    Sposób z timeram odpada, wszystkie używane.
    A jak ustawić znacznik gotowości jakiegoś peryferia? SPI i I2C jest używane, USART też. Powiedzmy, że mam nieużywany SPI, flagi przerwania w nim nie ustawię, bo zapis flagi kasuje ją. Z USARTEM (niestety używam) udało by się bo TXE jest ustawiony.
  • #4 16968469
    Rasel
    Poziom 22  
    Czy dobrze rozumiem, że chcesz z jednego przerwania (nazwijmy je IntA) , którego obsługa ma trwać jak najkrócej, wywołać jakąś funkcję (nazwijmy ją FunB), której obsługa może trwać dowolnie długo, a przerwanie IntA może być w tym czasie wywoływane ponownie?
  • #5 16968523
    BlueDraco
    Specjalista - Mikrokontrolery
    I tu dochodzimy do sedna sprawy: na AVR to nie ma sensu, bo system przerwań jest jednopoziomowy. Zmień mikrokontroler.
  • #6 16968542
    es2
    Poziom 16  
    Pewne funkcje są wykonywane zarówno w przerwaniu jak i w programie głównym, konkretnie komunikacja po SPI. Aby między sobą się nie gryzły (te w głównym i te w przerwaniu) i aby w programie głównym nie używać ATOMIC_BLOCK, dzięki czemu działają inne przerwania, chciałem wykonywać pewne operacje w sztucznym przerwaniu. Mogę oczywiście blokować w programie głównym te przerwania, które by przeszkadzały.

    W urządzeniu było mało USART, został użyty układ SC16IS760IPW. Teraz musze dodać kolejny SC16IS762IPW czyli dwa USART. Procek z USARTEM komunikuje się po SPI. Komunikacja to wysłanie adresu rejestru i zapis/odczyt danej. Teraz wszystko odbywa sie w pętli głównej, muszę jednak odbiór przenieść na przerwania. Jak sie łatwo domyśleć, nie może byc tak, że program główny wysłał np adres rejestru a nastąpii przerwanie odbiorcze, które wyśle adres rejestru, który to układ potraktuje jako daną i wszystko sie wysypie.

    Na razie widzę to tak:
    1) w programie głównym blokuję przerwania (linia INTx połączona z SC16IS760IPW i SC16IS762IPW) wykonuje operację zapisu/odczytu i odblokowuje INT
    2) jak w PC z czasu DOS, ustawiam adres rejestru, wpisuję daną i wywołuję programowe przerwanie. W tym przerwaniu nie mogą byc wykonywane inne, więc kolizji nie będzie)

    Może jakieś inne pomysły?
    Te SC16IS760IPW to takie 16C55x tylko bardziej zaawansowane i komunikacja z nimi odbywa sie po SPI lub IIC.

    Dodano po 53 [sekundy]:

    BlueDraco napisał:
    I tu dochodzimy do sedna sprawy: na AVR to nie ma sensu, bo system przerwań jest jednopoziomowy. Zmień mikrokontroler.

    Powiedz to konstruktorowi urządzenia 10 lat temu.
  • #7 16968561
    BlueDraco
    Specjalista - Mikrokontrolery
    Co za różnica, czy dodasz nowy układ, czy zmienisz procesor? Płytka i tak musi być nowa. Skoro w urządzeniu brakuje UARTów to zamiast czepiać kolejne protezy wystarczy wziąć uC, który ma ich tyle, ile trzeba.
    Zwykle tego typu problemy programowe daje się rozwiązać przez skasowanie/opróżnienie pętli głównej. Wrzucamy wszystko do przerwań i po kłopocie, tylko jeśli w systemie jest coś wolnego i bez przerwań, to bez wielopoziomowego systemu przerwań tego się nie da zrobić.
    Czasem rozwiązaniem jest wrzucenie większej funkcjonalności w periodyczne przerwanie timera.
  • #8 16968579
    es2
    Poziom 16  
    BlueDraco napisał:
    Co za różnica, czy dodasz nowy układ, czy zmienisz procesor? Płytka i tak musi być nowa. Skoro w urządzeniu brakuje UARTów to zamiast czepiać kolejne protezy wystarczy wziąć uC, który ma ich tyle, ile trzeba.

    Plenum ustaliło, że ma byc proteza. Sytuacji nie ratuje Mega1280 bo ma cztery USART;y a potrzeba 5. Gdy dam ARM, to sporo czasu zajmie przeniesienie programu a jak zwykle ma byc na wczoraj.Pewnie ruszą równoległe prace na nową wersja z ARM, na dzień dobry jeden USART odpada, bo tu robi za mostek USB.

    Na razie rozpatruję obsługę dodatkowego układu w pętli głównej przez blokowanie przerwania od USART albo przeniosę także nadawanie na przerwania i kolizji nie będzie.
  • #9 16968584
    Rasel
    Poziom 22  
    Można to zrobić w następujący sposób. Podczas wywołania przerwania IntA na stos jest odkładany adres pod jaki procesor ma powrócić po zakończeniu obsługi tego przerwania. Jeżeli na końcu obsługi przerwania IntA na stos odłożymy adres początkowy funkcji FunB i wykonamy rozkaz powrotu z przerwania RETI, to procesor zakończy obsługę przerwania IntA, ale skoczy pod adres początkowy funkcji FunB. W tym momencie na stosie pozostaje jeszcze adres powrotu odłożony podczas wywołania przerwania IntA, ale procesor nie jest już w trybie obsługi przerwań, więc po zakończeniu obsługi funkcji FunB należy wykonać rozkaz RET, aby procesor powrócił do miejsca, z którego pierwotnie zostało wywołane przerwanie IntA.
  • #10 16968601
    es2
    Poziom 16  
    Rasel napisał:
    Można to zrobić w następujący sposób. Podczas wywołania przerwania IntA

    Ale w jaki sposób wywołać to przerwanie?
  • #11 16969150
    Rasel
    Poziom 22  
    O które przerwanie pytasz: sprzętowe IntA czy programowe FunB?
  • #12 16969170
    es2
    Poziom 16  
    Rasel napisał:
    O które przerwanie pytasz: sprzętowe IntA czy programowe FunB?

    W programie głównym chcę wywołać przerwanie przez np zapis jakiegoś rejestru.
  • #13 16969257
    Rasel
    Poziom 22  
    Nie za bardzo Cię rozumiem. Dlaczego chcesz wywołać przerwanie z pętli głównej? Czy to nie może być wywołanie funkcji?
  • #14 16969334
    es2
    Poziom 16  
    Rasel napisał:
    Nie za bardzo Cię rozumiem. Dlaczego chcesz wywołać przerwanie z pętli głównej? Czy to nie może być wywołanie funkcji?

    Funkcja to nie przerwanie. To akurat nie procek z trybem nadzorcy bo wtedy różnice są duże. Zasadniczo chodzi o to, aby funkcja, której używam zarówno w przerwaniu, jak i w programie głównym nie była przerwana przez samą siebie. Opisałem jak wygląda dostęp do rejestrów usarta po spi. Problem jest tym większy, że przerwanie od takiego zewnętrznego usart musi być wyzwalane poziomem a musze pozwolić na wykonywanie sie innego przerwania w czasie obsługi zewnętrznego usarta. To oznacza, że nie mam wyjścia, jak w przerwaniu od usart, blokować wejście przerwania zewnętrznego. Skoro muszę to robić w przerwaniu, to i w pętli głównej mogę. Na tą chwilę zrobię to banalnie prosto. W funkcji (właściwie macro) aktywującej linię CS ustara dodam blokowanie wejścia INT, po dezaktywacji odblokuje INT.

    Nie zmienia to faktu, że ciekawi mnie jak wywołać programowo przerwanie. Wygląda na to, że trzeba do tego zaangażować jakiś układ peryferyjny lub pin GPIO, innego wyjścia nie ma.

    ARM jest bardziej elastyczny, takie sztuczki z wywoływaniem przerwania stosowałem przy obsłudze eeprom po I2C gdzie dostęp do niego miał program główny i przerwanie od timera.
  • #15 16969424
    Konto nie istnieje
    Poziom 1  
  • #16 16969454
    Rasel
    Poziom 22  
    To w takim razie to są dwie różne sprawy:

    1.
    Cytat:
    Zasadniczo chodzi o to, aby funkcja, której używam zarówno w przerwaniu, jak i w programie głównym nie była przerwana przez samą siebie.


    2.
    Cytat:
    ciekawi mnie jak wywołać programowo przerwanie. Wygląda na to, że trzeba do tego zaangażować jakiś układ peryferyjny lub pin GPIO, innego wyjścia nie ma.


    Zacznę od końca, czyli punktu nr 2: Nigdy tego nie próbowałem w AVR, ale rejestr EIFR można zapisywać i odczytywać, więc spróbuj ustawić w pętli głównej odpowiedni bit w rejestrze EIFR - powinno to spowodować wywołanie odpowiadającego mu przerwania.
  • #17 16969471
    es2
    Poziom 16  
    Marek_Skalski napisał:
    Zaprojektowanie nowej płytki i przeniesienie programu (napisanego w C), pewnie zajmie 2x mniej czasu niż pudrowanie trupa.

    Okazuje się, że płytki są i to zmontowana. Była opcja, która nigdy nie była wdrożona. W prototypie jest M644 ale w serii podobno montowano M1284. Program napisany w C.

    W kodzie znalazłem funkcje czytającą dane z zewnętrznego ustar w bloku. Rejestr jest adresowany raz i odczytywany np cały fifo czyli zamiast przesłać 128 bajtów (fifo ma 64) przesyłanych jest 65. Fifo nie jest zawsze czytane w całości. Najpierw sprawdzany jest rejestr, w którym znajduje się informacja ile bajtów znajduje sie w FIFO.

    Odczyt całego fifo, przy 14,74568MHz potrwa 1/(14745680/2)*65 ~8,8us. Myślę, że nie będzie problemu aby przenieść odbiór danych na przerwania.

    Dodano po 3 [minuty]:

    Rasel napisał:
    Nigdy tego nie próbowałem w AVR, ale rejestr EIFR można zapisywać i odczytywać, więc spróbuj ustawić w pętli głównej odpowiedni bit w rejestrze EIFR - powinno to spowodować wywołanie odpowiadającego mu przerwania.

    O tym juz pisałem wcześniej. Ustawienie na 1 flagi przerwania powoduje jego skasowanie.
  • #18 16969507
    Rasel
    Poziom 22  
    Cytat:
    Powiedzmy, że mam nieużywany SPI, flagi przerwania w nim nie ustawię, bo zapis flagi kasuje ją.
    .
    Flaga SPIF jest tylko do odczytu, dlatego nie możesz programowo zmienić jej stanu. Natomiast flagi w rejestrze EIFR można zapisywać i odczytywać, więc proponuję spróbować.
  • Pomocny post
    #19 16969513
    tmf
    VIP Zasłużony dla elektroda
    es2 napisał:
    W urządzeniu było mało USART, został użyty układ SC16IS760IPW. Teraz musze dodać kolejny SC16IS762IPW czyli dwa USART. Procek z USARTEM komunikuje się po SPI. Komunikacja to wysłanie adresu rejestru i zapis/odczyt danej. Teraz wszystko odbywa sie w pętli głównej, muszę jednak odbiór przenieść na przerwania. Jak sie łatwo domyśleć, nie może byc tak, że program główny wysłał np adres rejestru a nastąpii przerwanie odbiorcze, które wyśle adres rejestru, który to układ potraktuje jako daną i wszystko sie wysypie.


    Jak rozumiem masz sytuację, w której z jakiejś funkcji obsługi przerwania i pętli głównej wywołujesz funkcję transferu danych po SPI, które wykorzystujesz do komunikacji z zewnętrznym UARTem? Blokowanie przerwań to zły kierunek - musiałbyś je blokować na cały czas trwania transakcji (wysłanie adresu rejestru i danych), co jest raczej kiepskim pomysłem, szczególnie jeśli tych danych jest więcej (jeśli to pojedyncze bajty to z kolei blokowanie globalne przerwań może być bezproblemowe). Dodatkowo zakładam, że transmisja odbywa się w jakimś kontekście, który musi być zachowany. IMHO, to co powinieneś zrobić, to napisać dobry sterownik obsługujący SPI, z funkcjami, które będą mogły być wywoływane współbieżnie. Jedną z możliwości, jest transakcyjny dostęp do SPI. Dzięki temu program sterownika SPI po prostu kolejkuje kolejne transakcje i je po kolei wykonuje, umieszczając zwrotnie w przekazanej strukturze otrzymane dane. Tego typu przykłady możesz pobrać z darmowych przykładów do moich książek o XMEGA.
    Oczywiście prościej byłoby wybrać procesor posiadający odpowiednią liczbę UART - z AVR np. XMEGi mają nawet do 8 UARTów.
    BTW, pomysł z blokowaniem przerwań może być równie kiepski, niezależnie, czy jest to AVR, czy ARM. Szkoda, że koledzy zamiast wskazać sensowne rozwiązanie piszą "wybierz ARM i problemy magicznie znikną".
  • #20 16969520
    es2
    Poziom 16  
    Rasel napisał:
    Natomiast flagi w rejestrze EIFR można zapisywać i odczytywać, więc proponuję spróbować.

    W nocie wyraźnie napisali, że zapis bitu do EIFR kasuje flagę. Kasowane jest także w chwili wejścia w przerwanie. Kasowania EIFR przez zapis jedynki używałem gdy stan tej linii zmieniał się w czasie obsługi przerwania a nie chciałem aby było wywoływane ponownie.
  • Pomocny post
    #21 16969544
    michalko12
    Specjalista - Mikrokontrolery
    Nie wiem na ile jesteś w stanie ingerować w kod, ale...
    Cała obsługa transmisji po SPI powinna zostać przeniesiona do funkcji obsługi przerwania od SPI. Funkcje z pętli głównej powinny tylko przekazywać wskaźniki na struktury z danymi i callbackiem do "drivera" SPI. Driver SPI powinien atomowo zbierać te wskaźniki do swojego bufora i inicjować transmisję, jeśli SPI jest w stanie Idle. Jeśli na SPI trwała poprzednia transakcja, to po jej zakończeniu funkcja przerwania wywołuje callback ze wskaźnikiem na strukturę z danymi ( może być ta sama struktura, która do drivera SPI przekazała funkcja z pętli głównej) i sprawdza stan bufora, jeśli bufor nie jest pusty to rozpoczyna kolejną transakcję, albo kończy działanie blokując przerwanie.
  • #22 16969563
    es2
    Poziom 16  
    tmf napisał:
    Jak rozumiem masz sytuację, w której z jakiejś funkcji obsługi przerwania i pętli głównej wywołujesz funkcję transferu danych po SPI, które wykorzystujesz do komunikacji z zewnętrznym UARTem?

    Dokładnie.

    tmf napisał:

    jeśli to pojedyncze bajty to z kolei blokowanie globalne przerwań może być bezproblemowe

    Bywa, że wysyłane jest ponad 300 bajtów ale nie jest używane wysyłanie w bloku, tylko standardowo adres, dana, adres, dana. Blokowo jest realizowany tylko odczyt, ale to pewnie dlatego, że jest to robione w pętli głównej. Skoro wysyłanie to sekwencja:
    CS=L
    SPDR=adres rejestru usart
    SPDR=dana
    CS=H
    to wszystko trwa ok 300ns (jak kiedyś dostęp do wolnych pamięci eeprom) to chyba zrobie tak:
    CLI
    CS=L
    SPDR=adres rejestru usart
    SPDR=dana
    CS=H
    SEI
    i po problemie. Jeśli w miedzy czasie przyjdzie przerwanie odbiorcze, to po SEI wykona sie ono i odczyta dane z fifo ustara do ram AVR.
    to chyba najprostsze rozwiązanie. Musze jeszcze wybadać, jakie jeszcze przerwania sa wykonywane, czy moga poczekać, w najgorszym przypadku, te 8,8us na odczyt 64 bajtów z fifo. Ale tyle bajtów tam sie nie uzbiera, bo prędkość komunikacji tego usarta/spi to 115200 a tego co mam dołożyć, jednego 19200 a drugiego 9600.

    O kolejkowaniu też myślałem ale to sporo przebudowa programu.
  • Pomocny post
    #23 16969575
    Rasel
    Poziom 22  
    Cytat:
    W nocie wyraźnie napisali, że zapis bitu do EIFR kasuje flagę. Kasowane jest także w chwili wejścia w przerwanie. Kasowania EIFR przez zapis jedynki używałem gdy stan tej linii zmieniał się w czasie obsługi przerwania a nie chciałem aby było wywoływane ponownie.


    Zmusiłeś mnie do wysiłku i w nocie znalazłem to:

    "When an INT2:0 bit is written to one and the I-bit in the Status Register (SREG) is set (one), the
    corresponding external pin interrupt is enabled. The Interrupt Sense Control bits in the External
    Interrupt Control Register, EICRA, defines whether the external interrupt is activated on rising or
    falling edge or level sensed. Activity on any of these pins will trigger an interrupt request even if
    the pin is enabled as an output. This provides a way of generating a software interrupt.
    "
  • #24 16969579
    es2
    Poziom 16  
    michalko12 napisał:
    Cała obsługa transmisji po SPI powinna zostać przeniesiona do funkcji obsługi przerwania od SPI.

    Nie bardzo chcę to robić. SPI działa na max, czyli fcpu/2. Wysłanie bajtu to 16 cykli zegara. Wejście i wyjście z przerwania zajmie więcej niż transmisja bajtu. Używanie przerwań jest więc trochę bez sensu.
  • #25 16969589
    michalko12
    Specjalista - Mikrokontrolery
    es2 napisał:
    ie bardzo chcę to robić. SPI działa na max, czyli fcpu/2. Wysłanie bajtu to 16 cykli zegara. Wejście i wyjście z przerwania zajmie więcej niż transmisja bajtu. Używanie przerwań jest więc trochę bez sensu.

    Ok, przyzwyczajony jestem do FIFO i DMA. W tym przypadku i przy tym procesorze to rzeczywiście nie ma sensu.
  • #26 16969598
    tmf
    VIP Zasłużony dla elektroda
    es2 napisał:
    O kolejkowaniu też myślałem ale to sporo przebudowa programu.

    Tylko jeśli program jest koszmarnie napisany :)
    Kolejkowanie to jedyne sensowne rozwiązanie. W aplikacji sprowadzi się do prostej wymiany instrukcji odwołującej się do SPI na funkcję realizującą transakcję. Wkleiłbym ci kod, ale jest tego trochę, tak jak pisałem, ściągnij sobie przykady do moich książek o XMEGA - tam masz m.in. obsługe UART zrobioną na transakcjach, są też inne przykłady. Po kosmetycznych zmianach wprost przeniesiesz to na ATMega. W ten sposób elegancko rozwiążesz problem. Wywołanie przerwania nic ci nie da - wywołanie funkcji obsługi przerwania jest równoważne zablokowaniu globalnej flagi zezwolenia na przerwanie, czyli byłby to równoważnik ATOMIC_BLOCK. Dopiero w XMEGA masz 3-poziomowy kontroler przerwań, a i tak byłoby to rozwiązanie kiepskie.
  • #27 16969599
    es2
    Poziom 16  
    Rasel napisał:
    Cytat:
    W nocie wyraźnie napisali, że zapis bitu do EIFR kasuje flagę. Kasowane jest także w chwili wejścia w przerwanie. Kasowania EIFR przez zapis jedynki używałem gdy stan tej linii zmieniał się w czasie obsługi przerwania a nie chciałem aby było wywoływane ponownie.


    Zmusiłeś mnie do wysiłku i w nocie znalazłem to:

    "When an INT2:0 bit is written to one and the I-bit in the Status Register (SREG) is set (one), the
    corresponding external pin interrupt is enabled. The Interrupt Sense Control bits in the External
    Interrupt Control Register, EICRA, defines whether the external interrupt is activated on rising or
    falling edge or level sensed. Activity on any of these pins will trigger an interrupt request even if
    the pin is enabled as an output. This provides a way of generating a software interrupt.
    "


    O tym już pisałem. Jak użyje pinu GPIO i ustawię na nim przerwanie, to wszystko ok. Co gdy nie masz pinu do dyspozycji?
  • #28 16969615
    Rasel
    Poziom 22  
    Przyłączam się do kolegów tmf i michalko12, którzy piszą o konieczności uporządkowania całej obsługi SPI, czyli napisania tego porządnie. W przeciwnym razie stracisz tylko czas na pudrowanie nieboszczyka, tak jak napisał kolega Marek_Skalski. Natomiast jeżeli taki przypudrowany nieboszczyk zostanie wysłany do klientów, to straty mogą być znacznie większe, niż czas poświęcony na napisanie porządnej obsługi SPI.
  • #29 16969626
    tmf
    VIP Zasłużony dla elektroda
    es2 napisał:
    michalko12 napisał:
    Cała obsługa transmisji po SPI powinna zostać przeniesiona do funkcji obsługi przerwania od SPI.


    Nie bardzo chcę to robić. SPI działa na max, czyli fcpu/2. Wysłanie bajtu to 16 cykli zegara. Wejście i wyjście z przerwania zajmie więcej niż transmisja bajtu. Używanie przerwań jest więc trochę bez sensu.


    To zależy. Co prawda faktycznie obsługa przerwania może wyjśc dłużej niż nadawanie bajtu, ale..:
    1. Jeśli robisz to transakcyjnie, to możesz napisać ISR tak, aby w jednym przerwaniu nadać/odebrać cały pakiet danych związany z transakcję - wada - długi czas wykonywania ISR,
    2. Nadawać bajt po bajcie, koszt związany z obsługą ISR będzie, ale za to pomiędzy bajtami będą mogły być wykonywane inne przerwania i pętla główna programu. Strata tych cykli na obsługę ISR nie boli, bo program raczej nie wykorzystuje 100% czasu procesora, a przy niewielkiej liczbie transmitowanych danych dodatkowe obciążenie będzie niezauważalne.
    Mozesz sobie ustawić też dowolny balans pomiedzy rozwiązaniem 1. i 2.
  • #30 16969627
    Konto nie istnieje
    Poziom 1  
REKLAMA