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

[ARM7][Eclipse c++] obsługa wyjątku Abort

17 Lut 2011 16:06 1772 9
  • Poziom 11  
    Czy może ktos wie jak napisać poprawnie obsługe wyjątków abort w C (Eclipse).
    Mam dosyc robudowany program do pomiaru czasu w zawodach sportowych okolo 400kB. Czasem program sie zacina gdy przerwanie (FIQ) przerywa procedurę autozapisu danych na karte MMC przez SPI. Na czas zapisu nie mogę wyłączyć przerwań gdyż jest to funkcja krytyczna czasowo (impuls z fotoceli musi byc zarejestrowany bez wzgledu na wszystko w momencie gdy wystąpi). Przerwanie czasem (bardzo rzadko) powoduje jakis błąd którego nie moge zloklalizować.
    Czy ktos wie jak napisać obsługe w C wyjątku abort tak aby wyświetlał on informacje w która instrukcja spowodowała błąd (w wyniku np złego adresowani cz tp)

    Dotychczas wyczytałem ze funkcje wyjątkow inicjalizuje sie jakos tak:

    Code:

    void PAbt_Handler (void)  __attribute__ ((interrupt("ABORT")));
    void DAbt_Handler (void)  __attribute__ ((interrupt("ABORT")));

    nie znalazlem przykładow z obsluga funkcji ale potrzebne jest mi cos takiego:
    Code:

    void PAbt_Handler(){
       (*pfn_lcd_clear)(); //zeruj wyswietlacz
       (*pfn_lcd_str)("BLAD P-ABORT"); //wyswietlamy komunikat jaki rodzaj wyjatku
    //nastepnie trzeba by jakos wyznaczyc ktora instrukcja spowodowala wyjatek i wyswietlic jej adres
     void (*pfn_lcd_unlicz)(adres);//ta funkcja miala by wyswietlic adres funkcji ktora spowodowala wyjatek
      while (1);
    }

    void DAbt_Handler(){
       (*pfn_lcd_clear)(); //zeruj wyswietlacz
       (*pfn_lcd_str)("BLAD D-ABORT");//wyswietlamy komunikat jaki rodzaj wyjatku
    //nastepnie trzeba by jakos wyznaczyc ktora instrukcja spowodowala wyjatek i wyswietlic jej adres
     void (*pfn_lcd_unlicz)(adres);//ta funkcja miala by wyswietlic adres funkcji ktora spowodowala wyjatek
      while (1);
    }

    wyjasnienie: instrukcje do wyswietlacza sa wskaznikami do instrukcji (instrukcje sa napisane w C++) dlatego tu sa zastosowane wskazniki

    Testowałem tak napisane funkcje (bez obliczania adresu instrukcji bledu-nie wiem jak to zrobic) i nie dzialaja. Kompilator wszystko kompiluje nie zglasza zadnych bledow. Podczas testow specjalnie probuje wpisac np do jakies komorki pamieci poza obszarem adresowym jakas wartosc. Program sie zawiesza ale wyjatek nie jest zgłaszany a przynajmniej nie wyswietla sie zadna informacja na wyswietlaczu. Instrukcje wyswietlacza na pewno sa poprawne.


    Jesli ktos wie jak to uruchomic prosze o pomoc. Z góry dziekuje.

    Proszę kod umieścić w znacznikach code.
    Robak
  • Computer ControlsComputer Controls
  • Poziom 11  
    Funkcje nazywaja sie tak samo jak w tablicy wektorow.
    Jak w takim razie zasymulowac ich wywolanie czy wystarczy np sprobowac cos wpisac pod adres powyzej 40KB pamieci dla procesora 2148?
  • Computer ControlsComputer Controls
  • Pomocny post
    Poziom 12  
    Luźne przemyślenia pod rozwagę:
    -procesor wchodząc do obsługi przerwania stanu ABORT (tryb ARM) podstawia shadow-registers w tym r13 który jest wskaźnikiem stosu używanym w czasie obsługi tego typu wyjątku. W twoim przypadku skoro chcesz wywoływać w procedurze obsługi funkcje do obsługi LCD prawie na pewno trzeba zarezerwować specjalny obszar stosu dla obsługi ABORT. Inicjalizację tego stosu wykonuje zazwyczaj kod startowy (crt.S ?)
    -o ile mnie pamięć nie myli ARM 7 nie pozwala na przerywanie procedur obsługi przerwań o tym samym priorytecie, ale IRQ może być przerwane przez FIQ, dlatego wskazane jest zablokowanie wszelkich przerwań na czas wykonywania obsługi ABORT. Po prostu żeby nic nie przeszkadzało.
    -adres miejsca w którym nastąpił błąd jest wrzucany do rejestru r14_abt. Skoro chcesz wywoływać w procedurze obsługi inne funkcje r14_abt zostanie jako link_register a tym samym zostanie zniszczona jego oryginalna zawartość. Dlatego z jedną z pierwszych czynności procedury obsługi przerwania będzie zachowanie r14_abt, potem można robić co się podoba, na końcu przywraca się stan rejestru r14_abt i tak jak zaleca ARM kończy się procedurę obsługi przerwania przez SUBS PC,R14_abt,#4 (czy ponowną próbą wykonania zdefektowanej instrukcji).
    -podejrzewam zatem, że procedura obsługi przerwania nie moze byc napisana prosto w C, chyba że kompilator zostanie jawnie poinstruowany jakiego typu przerwanie będzie obsługiwane i wygeneruje odpowiedni kod wejścia i wyjścia z takiego przerwania. Jeśli kompilator tego nie zrobi trzeba napisać to samemu. Minimalnie ma to być ochrona r14, wywołanie funkcji obsługi w C i powrót przez
    SUBS PC,R14_abt,#4
  • Użytkownik usunął konto  
  • Poziom 11  
    mam JTAGa ale nie mialem jeszcze do czynienia z debuggerem. Potestuje program pod katem przytoczonych uwag mysle ze moze powodem byl za maly stos dla trybu abort. Obsluga wyswietlacza w przerwaniu FIQ i IRQ na pewno działa ale tam mialem wieksze stosy. Jutro napisze czy cos z tego wyszlo.
  • Poziom 11  
    udało mi sie poprawnie uruchomić wyjątek DAbt_Handler:
    wyjatek jest wywolywany gdy probuje wpisac jakas wartosc poza dostepny obszar adresowy.
    Mam pytanie kiedy zostanie wywolany wyjatek PAbt_Handler? (czy jest to wyjatek zlego adresu instrukcji kodu?)

    Aby poprawnie dzialaly wyjatki musialem zmienic nazwe wektorow z standardowych na jakies inne w pliku boot.S:

    Code:
    Reset_Addr:     .word   Reset_Handler
    
    Undef_Addr:     .word   Undef_Handler
    SWI_Addr:       .word   SWI_Handler
    PAbt_Addr:      .word   PAbt_Handler
    DAbt_Addr:      .word   DAbt_Handler
                    .word   0                      /* Reserved Address */
    IRQ_Addr:       .word   IRQ_Handler
    FIQ_Addr:       .word   FIQ_Handler

    Undef_Handler:  B       Undef_Handler
    SWI_Handler:    B       SWI_Handler
    PAbt_Handler:   B       ABORT_PAbt_Handler //<- tu dodalem przykladowo przedrostek ABORT
    DAbt_Handler:   B       ABORT_DAbt_Handler//<- tu dodalem przykladowo przedrostek ABORT
    IRQ_Handler:    B       IRQ_Handler
    FIQ_Handler:    B       FiqTimerHandler

    deklaracje funkcji wyjatku wyglada wtedy tak:

    void ABORT_DAbt_Handler (void)  __attribute__ ((interrupt("ABORT")));

    i odpowiednio definicja:

    void ABORT_DAbt_Handler(void){
       (*pfn_lcd_clear)(); //zeruj wyswietlacz
       (*pfn_lcd_str)("BLAD D-ABORT");
      while (1);
    }

    obslugi wyswietlania adresu instrukcji ktora spowodowala blad jeszcze nie napisalem

    mam pytanie jeszcze odnosnie wpisu w pliku boot.S

    Vectors:        LDR     PC, Reset_Addr         
                    LDR     PC, Undef_Addr
                    LDR     PC, SWI_Addr
                    LDR     PC, PAbt_Addr
                    LDR     PC, DAbt_Addr
                    NOP                            /* Reserved Vector */
     //               LDR     PC, IRQ_Addr
                    LDR     PC, [PC, #-0x0FF0]     /* Vector from VicVectAddr */
                    LDR     PC, FIQ_Addr

    dlaczego instrukcja: LDR     PC, IRQ_Addr jest w komentarzu usuniecie komentarza powoduje ze program nie dzialo (nie rozumiem tego fragmentu pliku)

    [size=9][color=#999999]Dodano po 3 [godziny] 55 [minuty]:[/color][/size]

     Funkcja ABORT_PAbt_Handler dziala poprawnie:
    void ABORT_PAbt_Handler(void){
       unsigned int CrashSite;
       asm ("STR    R14,%0" : "=m"(CrashSite) );
       (*pfn_lcd_clear)(); //zeruj wyswietlacz
       (*pfn_lcd_str)("BLAD P-ABORT");
       (*pfn_lcd_pos)(1,2);
       (*pfn_lcd_unlicz)(CrashSite-8);
      while (1);
    }
    wyswietla poprawnie (u mnie w kodzie dziesietnym ) adres instrukcji ktora spowodowala blad

    druga funkcja chyba tez dziala poprawnie ale nie umiem jej przetestowac
    Jak wywolac instrukcje poza obszarem adresowym ??

    void ABORT_DAbt_Handler(void){
       unsigned int CrashSite;
       asm ("STR    R14,%0" : "=m"(CrashSite) );
       (*pfn_lcd_clear)(); //zeruj wyswietlacz
       (*pfn_lcd_str)("BLAD D-ABORT");
       (*pfn_lcd_pos)(1,2);
       (*pfn_lcd_unlicz)(CrashSite-8);
      while (1);
    }
  • Poziom 12  
    LD PC, [PC, #-0x0ff0] oznacza, że do PC zostanie załadowana zwartość komórki pamięc spod adresu PC - 0x0ff0. Ponieważ owa instrukcja leży na początku pamięci odjęcie od PC -0x0FF0 spowoduje ze powstanie "ujemny" w postaci 0xfffffxxx. Jeśli LDR PC ... będzie leżalo na adresie 0xF0 po odjeciu 0xff0 wyjedzie wynik 0xfffff100 czyli adres początku tablicy wektorów kontrolera przerwań skąd zostanie ściągnięty adres procedury przerwania i załadowany do PC.
    W ten dość wariacki sposób następuje pobranie wektora przerwania z tablicy na samej górze pamięci. Nie znam szczegółów działania 2148, ale to o co pytasz dotyczy właśnie VIC i pobierania adresu. Położenie instrukcji LDR PC jest krytyczne dla działania proca, nie wolno tam niczego dodawać, niczego usuwać LDR PC musi lezec dokladnie na ustalonym miejscu w stosunku do początku programu.

    Stan "Prefetch abort" wywołuje pobranie rozkazu spod niepoprawnego adresu. Błąd występuje już w momencie pobierania rozkazu. "Unknown instruction" powstaje jeśli instrukcja została pobrana z dopuszczalnego adresu ale np. zamiast kodu wykonano skok w pole danych i nie ma tam poprawnych instrukcji. Wtedy nie ma błędu prefetch ale jest błąd interpretacji instrukcji.

    Błąd pobierania danych powinno się dać sprowokować przez odczyt np. 32 bitowej zmiennej spod adresu niepodzielnego przez 4 (non-alignment error).

    Przykład:

    {

    // Inicjalizacja wskaźnika. Adres podzielny przez 4.
    // Adres należy dobrać tak aby wskazywał w obszar RAM w celu uniknięcia
    // fetch error
    U32* adres=(U32*)0x1000;

    // Ten zapis przejdzie bez problemu.
    *adres = 0x55555555;

    // Ponowna inicjalizacja wskażnika, adres niepodzielny przez 4
    // Uwaga.
    // Istnieje mozliwość, że kompilator podstawi tutaj kod który zagwarantuje
    // że dwa ostatnie bity zmiennej adres zostaną obcięte. Wtedy nie dojdzie do
    // błędu. Możliwe jest także, że sam ARM zignoruje najmłodsze dwa bity
    // mimo jawnego wpisania tam ustawionych bitów. To zależy od implementacji
    // zwracam tylko uwagę że proc moze automatycznie wyrównywac i do bledu
    // nie dojdzie (co nie znaczy, że odczytane dane będą sensowne).
    adres = (U32*)0x1002;

    // Powinien wystąpić Data abort - zapis 32 bitowej zmiennej pod adres niepodzielny przez 4 (alignment errror).
    *adres = 0xaaaaaaaa;
    }

    ARMy serii Cortex nie mają z tym problemu i potrafią wykonywać 32 bitowe zapisy pod niewyrównane adresy. ARM7TDMI może się pluć i to jest normalne gdyż prostota proca nie pozwala na automatyczną zamiane jednej operacji 32 bit na serie operacji 8 bit nawet kosztem wydajności (BTW proce Intela podobnie jak Cortex potrafią sobie poradzić w przypadku zapisów non-aligned).
  • Poziom 43  
    Nosferatu napisał:
    dlaczego instrukcja: LDR PC, IRQ_Addr jest w komentarzu usuniecie komentarza powoduje ze program nie dzialo (nie rozumiem tego fragmentu pliku)

    Wyjaśnię to o wiele prościej niż kolega wyżej :D
    Ta instrukcja:
    Code:
    LDR PC, [PC, #-0x0FF0]

    to jest wersja tego czegoś:
    Code:
    LDR     PC, IRQ_Addr

    dla procesorów LPCxxxx.
    Chodzi o to że prawie wszystkie przerwania muszą leżeć pod konkretnym adresem, natomiast IRQ jest wektoryzowane rejestrami kontrolera VIC i adres może być różny zależnie od tego jakie przerwanie wykryje kontroler VIC (co przy okazji umożliwia zmienianie tych adresów w trakcie działania programu).
    Dlatego też nie można wbudowywać stałej wartości (adresu) w to miejsce. Dlatego ta linijka jest zakomentowana. A dodana jest druga która właśnie ładuje adres pobierając go z rejestru w kontrolerze VIC.
    A co do komentowania to oczywiście tak jak kolega wyżej napisał: położenie tego i pozostałych 7-miu fragmentów kodu jest krytyczne. Więc nie można tego przesuwać czy komentować. Po zakometowaniu którejś linii przestanie działać nie tylko przerwanie którego dana linia dotyczy ale i wszystkie inne przerwania których adresy są w dalszych liniach (a dokładniej mówiąc skoki będą pod niewłaściwe adresy).
  • Poziom 11  
    No po tym wyjasnieniu wydaje sie to takie proste i logiczne:) Z tymi adresami przerwań niby o tym wszystkim wiedzialem ale jakos moja mozgownica tego ze soba nie powiazala;)

    Moderowany przez _Robak_:

    Proszę poprawić poprzednie posty!