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.

lpc2148 - Przerwania i zawieszanie się programu

09 Lis 2015 14:13 1080 10
  • Poziom 9  
    Witam!
    Na wstępie chciałem zaznaczyć, że od niedawna dopiero poznaję procesory z serii ARM.
    Bardzo dawno temu miałem styczność z 51- jedynką i keilem. Moje doświadczenie w programowaniu C też nie jest oszałamiające, natomiast asembler na ARM jak na razie jest przeze mnie mało zrozumiany. Proszę o wyrozumiałość przy pisaniu ewentualnych odpowiedzi, za co z góry dziękuję.
    Obecnie mój wybór padł na LPC2148 oraz keila 4 z Real View. Program, który staram się napisać i zrozumieć jego działanie powstał w celach edukacyjnych.
    Moje pytanie dotyczy przerwań oraz przerwań zagnieżdżonych.
    Czytałem trochę na ten temat, również na tym forum ale może źle szukałem bo jak na razie nie udało mi się rozwiązać problemu.
    Napisałem krótki program, w którym używam przerwań zewnętrznych od wejścia EINT1, na którym wisi przerwanie od PCF 8574 (4 klawisze) oraz przerwań od TIMER0, odliczającego 0,5 sekundy (T0MR0 = 7499999).
    Wydaje mi się, że w tym wypadku już można mówić o zagnieżdżeniu przerwań chyba, że się mylę ?
    Tak napisany program działa mimo tego, że nie stosuję żadnych wstawek asemblerowych typu IENABLE / IDISABLE, o których czytałem na forum ani wrapera.
    Klawisz trzymam więcej niż sekundę, zmieniam czas na krótszy (T0MR0 = 9999) i program się nie wykłada.
    Sytuacja zmienia się diametralnie, gdy w programie staram się użyć trzeciego przerwania od zmieniających się sekund zegara RTC. Wtedy program albo się w ogóle nie uruchamia lub zatrzymuje się po kilku sekundach (gdy T0MR0 = 99999) albo po kilku minutach (gdy T0MR0 = 7499999). Tutaj (według mnie) już na pewno występują przerwania zagnieżdżone, które powodują, że tak napisany program ucieka w las z powodu nadpisania adresu powrotu przerwania o niższym priorytecie.
    Moje pytanie dotyczy tego czy przy użyciu dwóch przerwań w programie już trzeba stosować wstawki asemblerowe lub wrapera i jak to zrobić z RealView bo jak na razie wszystko co czytałem było na Use GCC.
    Kiedy takie wstawki mają być stosowane i jak, gdy przerwań w programie używa się na przykład 10 ?
    Czy wtedy trzeba pisać osobnego wrapera dla każdego przerwania o niższym priorytecie?
    Oto fragment programu:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Dodam jeszcze, że odczyt stanu PCF8574 jest zrealizowany w trybie pojedynczego odpytania układu. Szyna I2C nie jest odczytywana z użyciem przerwań.
    Myślę, że nie trzeba tutaj przedstawiać całego kodu bo program jako taki działa i nic wielkiego nie robi. Pokazuje tylko na wyświetlaczu (LCD 2x16) zegarek w następujący sposób:
    printf(" %2d:%2d:%2d ",HOUR,MIN,SEC);
    Wszystko w miarę działa do póki są używane dwa przerwania.
    Po odblokowaniu przerwań od RTC zaczyna się kaszana.
    Pozdrawiam i czekam na odpowiedzi.
    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
  • Specjalista - Mikrokontrolery
    Po pierwsze, nie różnicuj priorytetów przerwań i nie zagnieżdżaj ich.
    Po drugie, nie używaj opóźnień w przerwaniach.

    Po trzecie, nie szyfruj stałych w programie - maski bitowe zapisuj binarnie lub szesnastkowo, a nie dziesiętnie.

    Po czwarte, używaj stałych symbolicznych z plików nagłówkowych.

    Po piąte, ARM7 jest ciut zdezaktualizowany, a jak już zauważyłeś, przerwania na nim są lekko koszmarne.

    Po szóste - nie potrzebujesz żadnych wstawek asemblerowych.
  • Poziom 9  
    Dziękuję BlueDraco za zainteresowanie się moim problemem oraz za uwagi, których do końca nie bardzo rozumiem.
    Program jest poskładany z przykładów, które są podane w literaturze, być może tam też są błędy, które ja nieświadomie powielam.
    Jeżeli chodzi o priorytety przerwań.
    Co masz na myśli pisząc, że różnicuję priorytety i doprowadzam do zagnieżdżania przerwań ?
    To jest jedna z moich wątpliwości czy w moim programie występuje zjawisko zagnieżdżania się przerwań (według mnie tak), czy nie ma takiej sytuacji, gdzie popełniam błąd?.
    Jak to zrobić, żeby przerwania się nie zagnieżdżały?
    Jeżeli nie potrzebuję wstawek asemblerowych to jak to zrobić ?
    Piszesz, że LPC2148 jest już zdezaktualizowany.
    Zdążyłem zauważyć, że te przerwania są lekko koszmarne, być może nie jest za późno i warto przestawić się na coś innego?
    Co radzisz w takim przypadku?
    Wiem jednak, że na tym procesorze są realizowane bardzo skomplikowane programy, które chodzą bez problemu.
    Mimo wszystko chciałbym wiedzieć gdzie popełniam błąd.
    Jeżeli chodzi o opóźnienia w moim programie to świadomie założyłem najniższy priorytet (15) dla EINT1 bo nie zależy mi aby to przerwanie było obsłużone bardzo szybko a trzeba zniwelować drgania od naciskanego i puszczanego klawisza klawiatury.
    W obsłudze przerwań, które mają wyższe priorytety nie ma żadnych opóźnień.
    Co do szyfrowania stałych w programie i używania stałych symbolicznych z plików nagłówkowych to muszę się przyznać, że nie bardzo rozumiem o czym piszesz.
    Poproszę o czystą łopatologię w tej kwestii.
    Pozdrawiam i dziękuję za odpowiedź
  • Specjalista - Mikrokontrolery
    Wszystkie przerwania powinny mieć taki sam priorytet - wtedy nie będzie żadnego zagnieżdżania. W żadnym nie powinno być oczekiwania, Każdy współczesny Cortex_M będzie łatwiejszy w programowaniu od ARM7. Jeśli jesteśmy przy NXP - weź np. LPC1768.

    Szyfrowaniem jest u Ciebie zapis stałych 253, 254, 247 - skąd wziąłeś ich wartości? Dlaczego zamiast 0 piszesz 0x00?
  • Poziom 9  
    Powiem, że bardzo cieszy mnie twoja odpowiedź jeżeli chodzi o LPC1768.
    To był pierwszy ARM jaki wpadł mi w ręce. Mam do niego wspaniałą płytę prototypową z dołączanymi peryferiami i kolorowym wyświetlaczem dotykowym o rozdzielczości 320x240. Uruchamiałem na nim demonstracyjne programy graficzne i byłem pod wrażeniem jego możliwości.
    Nieco później dostałem płytę prototypową z LPC2148 a do niej dwie książki w języku polskim i to głównie przesądziło o tym, że zostałem przy nim.
    Nie bez znaczenia jest również rozmiar samego procesora bo LPC1768 jest produkowany w obudowie 100-nóżkowej i BGA a ta druga odpada.
    Uznałem, że 1768 to kombajn i może później to będzie dobry wybór.
    Co do zapisu wartości w moim przykładowym programie to tak jak pisałem wcześniej przykłady zaczerpnięte są z literatury.
    Cytat:
    Szyfrowaniem jest u Ciebie zapis stałych 253, 254, 247 - skąd wziąłeś ich wartości? Dlaczego zamiast 0 piszesz 0x00?

    W książce pana Majewskiego są przykłady, w których zero jest wpisywane dwojako:
    czyli tak:
    VICVectAddr=0x00000000;
    oraz tak:
    VICVectAddr=0;
    jakby na to nie patrzeć to zawsze będzie zero. Myślę, że nie ma to większego znaczenia.
    Wartości 253,lub 254 to są wartości jakie może przyjąć zmienna x.
    w funkcji odczytu klawiatury.

    x=klaw_read(); //odczyt PCF8574 po I2C

    odczytując wartość x po prostu wiem, który klawisz został naciśnięty.
    Wydaje mi się, że nie podoba ci się zapis tej zmiennej w postaci dziesiętnej.
    Oczywiście można to robić w inny sposób na przykład badając poszczególne bity ale to również nie ma wpływu moim zdaniem na działanie programu, może wygląda trochę nieelegancko.
    Wezmę to pod uwagę.
    Najważniejszą sprawę zostawiłem na koniec.
    W Przedstawionym fragmencie programu używam przerwań wektorowych IRQ i myślę, że tutaj nie ma mowy o tym aby przerwania miały ten sam priorytet.
    Wydaje mi się, że sugerujesz (gdybym się mylił to wyprowadź mnie z błędu) aby w programie zamienić przerwania wektorowe IRQ na przerwania niewektorowe, które skaczą pod jeden z góry ustalony adres dla tego rodzaju przerwań, czyli VICDefVectAddr a następnie sam muszę się zatroszczyć o to aby sprawdzić jakie to przerwanie zostało zgłoszone, sprawdzając rejestr VICIRQStasus.
    Przyznam, że ma to sens i w moim przypadku było by to jakieś wyjście.
    Zapewne w czasie gdy jest obsługiwane jedno przerwanie drugie może być przyjęte dopiero po zakończeniu obsługi tego pierwszego????
    Stąd twoje uwagi o tym aby w procedurze obsługi przerwania nie stosować pętli opóźniających?
    Nie brałem wcześniej pod uwagę przerwań niewektorowych bo autorytety piszą, że używa się ich dopiero wtedy gdy zabraknie już przerwań wektorowych IRQ.
    Podałeś mi inny sposób rozwiązania mojego problemu i dzięki ci za to bo każdą uwagę staram się analizować.
    Powiem tak.
    Na dzień dzisiejszy sprawa poprawnej obsługi przerwań wektorowych w dalszym ciągu mnie nurtuje i chciałbym pociągnąć ten temat dalej mimo tego, że jak widzę zniechęca wiele osób.
    Proszę w dalszym ciągu o informacje na temat pisania i działania wraperów, które umożliwiają poprawną obsługę przerwań wektorowych IRQ.
    Pozdrawiam.
  • Specjalista - Mikrokontrolery
    Zamieniłeś nienajmłodzszy, ale jeszcze nie przestarzały LPC17xx na zabytkowy, głupszy i trudniejszy LPC21xx. Taki sobie pomysł... LPC17xx występują w obudowach 80- i 100nóżkowych LQFP, które łatwo lutuje się ręcznie.

    Stałe zapisuj sobie jak chcesz, tylko nie oczekuj potem, że ktoś będzie analizował Twoje szyfry. Tak napisany program nie daje się czytać.

    Z ARM7 skończyłem jakieś 7 lat temu i niewiele już pamiętam. Zdaje się, że domyślnie przerwania mają ten sam priorytet główny, czyli nie wywłaszczają się.
    Przerwania w Cortex są b. przejrzyste i łatwe w programowaniu.

    W przerwaniu nie należy NIGDY czekać (dłużej niż pojedyncze mikrosekundy), niezależnie od zagnieżdżania bądź niezagnieżdżania.
  • Poziom 9  
    Witam ponownie!
    Czy naprawdę nikt nie wie jak to zrobić?
  • Poziom 23  
    Wywal z obsługi przerwania EINT1_IRQ opóźnienia.
    LPC1768 też jest już całkiem stary ;) lecz jeszcze całkiem, całkiem. Jeśli nie potrzebujesz "kobyły" ale szybki uc to fajne są LPC134x np. w obudowie lqfp48, dobrym wyborem jest także LPC11U68 ale to cortex M0.
  • Poziom 9  
    Naprawdę rozumiem wasze uwagi ale nie mogę skakać między jednym a drugim procesorem bo nigdy do niczego nie dojdę, wybaczcie ale to nie jest odpowiedź na moje pytanie. Zresztą po bliższym zapoznaniu się z LPC1768 wiem , że bardzo źle działa zegar RTC, a czasem wogóle. Plik lpc17xx.h jest już opisany strukturami i to też jest na razie dla mnie problemem bo nie bardzo wiem jak z tego korzystać.
    Być może dam się namówić na inny procesor ale dopiero wtedy jak dowiem się jak rozwiązać ten problem.
    Pozdrawiam.
  • Poziom 23  
    Nie znam Arm7, ale wieszanie Twojego programu tłumaczę sobie tak:
    Wystąpiło przerwanie EINT1_IRQ i uc skoczył do jego obsługi odkładając pewnie na stos zawartość pewnych rejestrów, trwa jego obsługa i nadchodzi przerwanie TIMER0_IRQ należy ponownie na stos odłożyć kolejne dane i może kolejne przerwanie RTC_IRQ i ponownie zrzucić dane na stos i w tym miejscu następuje jego przepełnienie powodując zawieszenie programu. Dlatego obsługa EINT1_IRQ powinna trwać jak najkrócej.

    W jakim sensie źle działa RTC w LPC1768 ?
  • Poziom 9  
    Też tak myślałem ale tak się nie dzieje.
    Najwyższy priorytet ma przerwanie od Timera 0, potem przerwanie od sekund zegara RTC i na koniec dopiero przerwanie od EINT1.
    Program się uruchamia prawidłowo i zawiesza się tak jak pisałem wcześniej po kilku sekundach.
    Przerwań od EINT1 wogóle nie uruchamiam.
    Zapewne masz rację z tym, że adres powrotu jest zamazywany chyba wtedy gdy jest obsługiwane przerwanie od zegara RTC i wtedy dochodzi do obsługi przerwania o wyższym priorytecie czyli Timera 0.
    Żeby tego uniknąć jest napisana przez keila w asemblerze wstawka zwana wraperem. Moje pytanie dotyczy tego czy dla każdego przerwania o niższym priorytecie trzeba pisać takiego wrapera czy trzeba to jeszcze w inny sposób zrobić.
    Pozdrawiam i dziękuję za zainteresowanie.