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

[LPC2148][C] CPSR i przerwania

Zaquadnik 03 Kwi 2009 15:06 1683 3
  • #1 03 Kwi 2009 15:06
    Zaquadnik
    Poziom 27  

    Mam w zasadzie wie sprawy, ucząc się programować wspomniany w temacie procesor, pełen optymizmu i zapału, zabrałem się za rozgryzanie systemu przerwań. No i zaczęły się schody. Aha, przy nauce mocno wspomagam się książką p. Lucjana Bryndzy "LPC2000 - mikrokontrolery z rdzeniem ARM7". Ustawiając przerwania zacząłem od odpowiedniego przygotowania kontrolera VIC na tę okoliczność. Zrobiłem to tak, jak w przykładzie książkowym:

    Code:

       VICVectAddr1 = (unsigned int)INT0_IRQ_Handler;
       VICVectCntl1 = INT0_SLOT | SLOT_IRQ_EN;
       VICIntEnable |= INT0_IRQ_EN;


    Do tego odpowiednie definicje stałych:

    Code:

    #define INT0_SLOT 14
    #define INT0_IRQ_EN (1 << 14)

    #define SLOT_IRQ_EN  (1 << 4)


    I pojawił się pierwszy problem, jak można z poziomu C dobić się do rejestru CPSR aby zmienić flagi I i F ? P. Lucjan Bryndza robił to wstawką asemblerową. I tu stała się rzecz dziwna, jakimś cudem udało mi się wpisać coś dziwnego do CPSR (za pośrednictwem wstawki P. Lucjana), że JTAG (4R|\/|-JT4G by Freddie Chopin) za Chiny nie chciał się połączyć z LPC, cały czas w OpenOCD pojawiał się komunikat o błędnej wartości CPSR. Pomogło dopiero skasowanie flasha przez ISP (RS232 + Flash Magic). Spotkał się kiedyś ktoś z czymś takim ?

    Później przerwania uruchamiałem korzystając z biblioteki armint P. Lucjana i chodzi. I teraz mam pytanie, udaje mi się uruchomić przerwanie dla jednego źródła, pikuś... Ale zwróciłem uwagę na kilka szczegółów. Przerwanie konfigurowane jest jak w kodzie powyżej. Mam funkcję jego obsługi zdefiniowaną tak:

    Code:

    void INT0_IRQ_Handler(void) __attribute__((interrupt("IRQ")));


    I teraz w rozbiegówce (startup asemblerowy) przerwanie odpalę kiedy w kodzie mam:

    Code:

    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

    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   INT0_IRQ_Handler //i tu jest nazwa procedury obslugi
    FIQ_Addr:       .word   FIQ_Handler

    //Defaultowe nazwy procedur obslugi wyjatkow
    Undef_Handler:  B       Undef_Handler
    SWI_Handler:    B       SWI_Handler
    PAbt_Handler:   B       PAbt_Handler
    DAbt_Handler:   B       DAbt_Handler
    IRQ_Handler:    B       IRQ_Handler
    FIQ_Handler:    B       FIQ_Handler


    A powinno być tak, że procek adres obsługi pobiera z VIC i wówczas skacze do tego adresu, czyli można zdefiniować wiele wektorów obsługi przerwań i jest cacy. Jak to zrobić ? Bo widzę, że w rozbiegówce jest kod do pobrania adresu procedury obsługi przerwania z VIC, ale wygląda na to, że procek uparcie skacze do IRQ_Handler. Będę dźwięczny za każdą pomoc.

    EDIT:
    OK, co do przerwań to już wiem, przedstawiony fragment pliku startowego powinien wyglądać tak:

    Code:

    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, [PC, #-0x0FF0]     /* Vector from VicVectAddr */
                    LDR     PC, FIQ_Addr

    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

    //Defaultowe nazwy procedur obslugi wyjatkow
    Undef_Handler:  B       Undef_Handler
    SWI_Handler:    B       SWI_Handler
    PAbt_Handler:   B       PAbt_Handler
    DAbt_Handler:   B       DAbt_Handler
    IRQ_Handler:    B       IRQ_Handler
    FIQ_Handler:    B       FIQ_Handler


    Ale nadal nie umiem wyjaśnić dziwnego zachowania procka opisanego na początku :

    0 3
  • Pomocny post
    #2 03 Kwi 2009 17:10
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Skoro problem startupa już rozwiązałeś, to może napiszę cokolwiek o tym drugim.

    Po pierwsze - po co chcesz zmieniać wartość I / F z poziomu kodu? W znakomitej większości przypadków - jeśli nie korzystasz z przerwań zagnieżdżonych - nie ma takiej potrzeby. Przerwania aktywowane są (lub nie) w rozbiegówce przy okazji ustawiania stosów dla różnych trybów.

    Jeśli koniecznie masz potrzebę zmiany, to z poziomu czystego C nie jest to możliwe, ponieważ trzeba wykorzystać specjalną instrukcję MSR, która umożliwia dostęp do rejestru CPSR. Kolejny problem jest taki, że instrukcja ta nie jest dozwolona w trybie user, więc albo trzeba używać trybu np. system (oczywiście nie dotyczy to sytuacji wewnątrz przerwań), albo wykorzystać przerwanie programowe (instrukcja SWI), które trzeba odpowiednio oprogramować.

    Dodam może jeszcze, że ta pusta linijka:

    Code:

                    .word   0                      /* Reserved Address */


    jest całkowicie zbędna. Zarezerwowany jest tylko wektor.

    4\/3!!

    0
  • #3 03 Kwi 2009 17:45
    Zaquadnik
    Poziom 27  

    Dzięki za info :) A wiesz coś może na temat dziwnego zachowania LPC po zmianie CPSR ? Musiał to powodować mój program, ale czy to nie jest tak, że JTAG resetuje procka ? Powinno się chociaż dać skasować flash. Co do tej linijki, przeoczenie, adaptowałem gotową rozbiegówkę ;) Aha, i jeszcze jedno, w momencie kiedy konfiguruję VIC wypada chyba mieć wyłączone przerwania w CPU, prawda ? Więc po to potrzebowałem móc je zmieniać w kodzie. Na razie nie bawiłem się jeszcze mechanizmami ochrony, dopiero zaczynam z ARMami ;)

    0
  • #4 03 Kwi 2009 18:04
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Zaquadnik napisał:
    Dzięki za info :) A wiesz coś może na temat dziwnego zachowania LPC po zmianie CPSR ? Musiał to powodować mój program, ale czy to nie jest tak, że JTAG resetuje procka ?

    W LPC działa to trochę inaczej, ponieważ interfejs JTAG jest tu trochę skrzaczony. Ponieważ reset procka (SRST) powoduje też reset logiki JTAG (TRST), JTAG nie wie, kiedy może się podłączyć do rdzenia (przez pewien czas rdzeń nie włącza JTAGa czy coś tam...). Dlatego też soft zarządzający JTAGiem po prostu chwilę czeka (zwykle ok kilkuset ms) po czym podłącza się, stopuje rdzeń i zeruje rejestr PC - tak zwany soft-reset. Dlatego też jeśli twój kod coś poważnie namiesza, to zanim JTAG będzie próbował się dołączyć, to procek już leży ewentualnie podłączenie nie jest możliwe. Taka wada LPC - niestety.

    Cytat:

    Aha, i jeszcze jedno, w momencie kiedy konfiguruję VIC wypada chyba mieć wyłączone przerwania w CPU, prawda ? Więc po to potrzebowałem móc je zmieniać w kodzie.

    No ale po co? <: Jeśli dane przerwanie jest wyłączone w VIC, to możesz w nim zmieniać co tylko chcesz.

    4\/3!!

    0