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

[STR912] - Nie działa przerwanie od timera 1 przy użyciu VIC i UART

bimbarabam 15 Lis 2012 13:47 2082 19
REKLAMA
  • #1 11532024
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    W swoich programach korzystam z biblioteki dostarczanej przez ST. I mam w tym takie dwa pliki 91x_it.c i 91x_it.h, w których mam deklaracje i defnicje handlerów. Handlery te sa odpowiednio podpinane do przerwań, za pomocą funkcji VIC. I zasadniczo chciałem zrobić sobie przerwanie od timera 1, na przepełnieniu licznika, w którym przez UART wysyła się literka 'c'. Tak tylko dla testu, żeby wiedzieć czy przerwania mi działają, ale nie działają niestety. Wydaje mi się, że w kodzie nie ma błędów, ale jak coś kod wrzucam poniżej. Jeżeli kod jest poprawny, to ma ktoś ma jakiś pomysł, czego mogłem jeszcze nie zrobić, żeby to zadziałało?

    Tu sobie inicjuje timer
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Tu handler:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #2 11532114
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    Witaj,

    Zrobiłem kilka dużych projektów na tym STR912. Nie mam jednak kodu pod ręką więc napisze coś co Ci może pomóc a resztę wieczorem.
    ARM, ma dwie linie przerwań, jedna IRQ druga FIQ, i tyle. Ten VIC jest zewnętrzny i nie ma nic do ARMa. Trzeba więc mieć:
    1) Handler do IRQ ARMa, zwykle assembler, poszukaj plików *.s a w nich czegoś o nazwie "Vector Table"
    2) Włączyć przerwania na poziomie ARM'a, niezależnie od VIC.

    Dodano po 9 [minuty]:

    Mniej więcej wygląda to tak:

    
    ;*******************************************************************************
    ;                        Exception vectors
    ;*******************************************************************************
    
            LDR     PC, Reset_Addr
            LDR     PC, Undefined_Addr
            LDR     PC, SWI_Addr
            LDR     PC, Prefetch_Addr
            LDR     PC, Abort_Addr
            NOP                             ; Reserved vector
            LDR     PC, IRQ_Addr
    
    ...
    
    IRQ_Addr        DCD     IRQHandler
    
    ...
    
    ;*******************************************************************************
    ;* Function Name  : IRQHandler
    ;* Description    : This function is called when IRQ exception is entered.
    ;* Input          : none
    ;* Output         : none
    ;*******************************************************************************
    
    IRQHandler
    	portSAVE_CONTEXT					; Save the context of the current task.
    
    	LDR    r0, = VectorAddress
    	LDR    r0, [r0]						; Read the routine address
    	LDR    r1, = VectorAddressDaisy
    	LDR    r1, [r1]
    	MOV	   lr, pc
    	bx	   r0
    	LDR    r0, = VectorAddress			; Write to the VectorAddress to clear the
    	STR    r0, [r0]						; respective interrupt in the internal interrupt
    	LDR    r1, = VectorAddressDaisy		; Write to the VectorAddressDaisy to clear the
    	STR    r1,[r1]						; respective interrupt in the internal interrupt
    	
    	portRESTORE_CONTEXT					; Restore the context of the selected task.
    
    



    Tu akurat z FreeRTOS, stąd "portSAVE_CONTEXT", zwykle w tym miejscu ma być zapis na stos rejestrów. Ważne jest to że kod pobiera adres do którego ma skoczyć z VIC!

    A jeszcze jedno. Po resecie, w kodzie assemblera musi się znaleźć inicjalizacja adresu stosu dla IRQ. Stos IRQ jest niezależny od kilku innych stosów które ARM wykorzystuje (nie ma sensu wyjaśniać zawiłości bo to ogólnie dostępna wiedza). Trzeba się upewnić, że stos jest gdzieś ustalony i że jest zainicjowany. Np, taki kod:
          
     MSR     CPSR_c, #Mode_IRQ|I_Bit|F_Bit    ; No interrupts
     LDR     SP, = SFE(IRQ_STACK)
    
  • #3 11532225
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Tj ja ogólnie planuję zrobić szaloną rzecz. Bo mam program, który śmiga z FreeRTOS'em i do tego chce dołożyć przerwanie - nieFreeRTOS'owe, które ma priorytet wyższy niż FreeRTOS i jak ono wchodzi zatrzymuje się FreeRTOS i robi się kod przerwania, zauważyłem, ze FreeRTOS jest podpięty pod timer3, dlatego moje przerwanie ma być na timerze 1. Mam sobie taki pliczek jak vector.s (był już dolączony wcześniej do dema FreeRTOS'a), który podsyłam w załączniku. Porównałem to co podesłałeś i mam wrażenie, że mam dokładnie identyko kod
  • #4 11532589
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    Zależy co ma robić, ale najlepiej to wykorzystać FIQ, czyli linie która jest nadrzędna do przerwań na poziomie ARM'a. Gdyby zostać w IRQ, trzeba by zrobić zagnieżdżone przerwania czyli takie które mogą być ponownie przerwane przez inne IRQ, a to sporo kłopot i ryzyko.
    Czyli tak:
    1) ostatnia linia wektora wyjątków (exception handler) ma być początkiem kodu obsługi przerwania FIQ (zrobili tak by nie tracić czasu na skok!). Taki kod ja mam tak zrobiony:
    
            IMPORT  CFIQHandler;
    
      ;-------------------------------------------------------------
      ; FIQ handler, serves the only FIQ in the system
      ; that is sampling timer
      ;-------------------------------------------------------------
    FIQHandler
            ;-------------------------
            ; put on the stack some regs
            ; r0-f7 and lr needs to be saved
            ; other registers are FIQ banked
            ;-------------------------
            SUB    lr,lr,#4
            STMFD  sp!,{r0-r7,lr}
    
            PRESERVE8
            BL     CFIQHandler
    
            ;-------------------------
            ;return from the interrupt
            ;-------------------------
            LDMFD  sp!,{r0-r7,pc}^
    
            NOP
            NOP
    
       END
    
    


    2) Kod w C, to funkcja o nazwie: "CFIQHandler", konieczne jest by była skompilowana w jako "ARM Mode" a nie "Thumb Mode". Funkcja nie ma nic specjalnego w sobie.

    3) Należy pamiętać o zarezerwowaniu stosu dla FIQ odpowiednio dużego do zapotrzebowania funkcji w C.

    4) Konfiguracja przerwania powinna zwierać wpis do rejestru VICx_INTSR by dana linia była podpięta to FIQ a nie do IRQ

    5) odblokować FIQ w ARMie:funkcja "__enable_fiq();" z tym że to jest "wbudowana" funkcja kompilatora ARM'a. (to też jest KAIL). Jak nie będzie to poszukaj w necie, trywialny kod assemblera.
  • REKLAMA
  • #5 11533383
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Cytat:
    Gdyby zostać w IRQ, trzeba by zrobić zagnieżdżone przerwania czyli takie które mogą być ponownie przerwane przez inne IRQ, a to sporo kłopot i ryzyko.

    Czemu zagnieżdżać, nie wystarczy po prostu poustawiać odpowiednie priorytety przerwań w VIC? Musze ogarnac pisanie tych skryptow w asmie. Bo widze ze bez tego daleko nie pojade. To jakos sensownie opisane w dokumentach na stronie ST? Poniżej załączyłem mój plik vector.s. Wg tego co ustaliłem to FreeRTOS jest ustawiony na przerwaniu o priorytecie 5, a ja ustawiłem mój timer na priorytecie 0, więc na wyższym, więc nie powinny się żreć między sobą. FreeRTOS jednak caly czas dziala, a przerwanie od timera nie może się w ogóle uruchomić
    Załączniki:
    • vector.rar (1.8 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #6 11533756
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    Nalegałbym na FIQ. Trzeba sobie uświadomić jak działają przerwania. Przychodzi przerwanie jak ARM jest w normalnym trybie, dostaje sygnał na linii IRQ, przerywa wykonanie programu i skacze pod wektor przerwań, tam ma skok do obsługi przerwań. Fajnie, tylko pierwszą rzeczą jaką robi ARM w chwili otrzymania przerwania to je wyłącza! Tak, że wykonując obsługą przerwania są one wyłączone! Nie ważne czy VIC jest ustawiony czy nie, ARM robi obsługą przerwania i nie weźmie się za następne zanim nie skończy tego choćby to następne było o wyższym priorytecie. No tak, nie bardzo to realtime skoro jakieś nieważne przerwanie może przez swój czas obsługi zablokować coś ważnego, np. próbkowanie! Dlatego robi się zagnieżdżone przerwania, zaraz po odłożeniu na stos rejestrów, odblokowuje się przerwania ARMowi (ale przedtem trzeba skasować przerwanie w danym źródle). I wtedy ARM może wykonać przerwanie obsługi przerwania! Lepiej, ale nie perfekcyjnie bo opóźnienie wykonania przerwania to czasami czas do momentu odblokowania przerwań w handlerze, co może prowadzić do "jittera" próbkowania (no bo czasami będzie a czasami nie, zależnie czy strzeliło w przerwaniu czy w normalnym kodzie)!

    FIQ jest ponad tym, więc idealnie się nadaje do tego typu działań. Wszystko zależy od naszego "realtime", my decydujemy jakie czas opóźnień jest dopuszczalny, jak wystarczy bez zagnieżdżania to dobrze.
    Wiem, że czasami nie myśli się o chipe jak o dwóch różnych rzeczach - ARM i peryferia ale to tak na prawdę jest. ARM jest oddzielnym ciałem przepiętym drucikami, wszystko co robi ST/NXP/ATMEL to otoczka, ale nie ingeruje w ARM'a. Dlatego niektóre rzeczy wydaja się nie do końca idealne, ten VIC z STR9xx jest najlepszym przykładem. Brzmi jak wypas a tak na prawdę to tylko dostarcza adresu handlera w kolejności priorytetów.
    To co intuicyjnie by się chciało mieć jest już w CortexMx. Tam kontroler przerwań, priorytety i preemptive jest integralną częścią rdzenia, a nie zewnętrznym peryferie.
  • REKLAMA
  • #7 11535200
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Brzmi bardzo przekonujaco. Dzieki za ten mały wykład :). Zastanawia mnie teraz taka rzecz, bo w moim pliku vector.s mam m.in handler do FIQ. Przeczytałem w takim fajnym manualu od hitexa dotyczacego str912, że połączenie handlera miedzy kodem w C, a kodem w assemblerze, możemy uzyskać nazywając tak samo funkcję odpowiedzialną tu i tu. Przeanalizowałem kod z tej biblioteki od ST i widze ze jak tam sie wywołuje vicconfig dla jakiejs konkretnej lini przerwania np dla timera jak wyzej, to podaje się adres funkcji TIM0_handler, ale takowego handlera nie ma w moim pliku.s. I pytanie czy w zwiazku z tym ponadto, że mam FIQ_handler muszę w vector.s dodać też TIM0_handler? I mam jeszcze jedno pytanie. bo widziałem w tutorialach, że dodaje się przy deklaracjach funkcji przerwań, stosuje się __attribute__((interrupt("FIQ"))), żeby poinformować kompilator, że to jest procedura szybkiego przerwania. Jak ja dodaje takie coś u siebie to kompilator sypie mi błędem w tym miejscu
    error: expected ',' or ';' before '{' token
    

    Czy ta dyrektywa __attribute__ jest zawsze konieczna? Czy ona zalezy od kompilatora? Ja uzywam arm-none-eabi-gcc
  • #8 11535240
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Dałeś ten atrybut w złym miejscu. Zrób tak:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Atrybut jest generalnie konieczny chyba że masz wrapper w assemblerze, który załatwi za Ciebie niuanse powrotu z przerwania.

    4\/3!!
  • #9 11535379
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Ok - kompiluje się, ale dalej nie działa ;D. Bo rozumiem, że jeżeli tutaj dowolne przerwanie czy to od timera, czy tam RTC jeżeli jest ustawione jako FIQ, to ma najwyższy priorytet i wykonuje się przed wszystkimi przerwaniami IRQ?

    Dodano po 2 [godziny] 49 [minuty]:

    Zaczalem sie bawic z przerwaniem na RTC, moja procedura obslugi przerwania to RTC_IRQHandler() - to ma być przerwanie szybkie FIQ( nie sugerujcie sie nazwa IRQ - nie chcialo mi sie zmieniac nazwy w pliku).
    Funkcja jest zadeklarowana jako:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Dodałem sobie taką procedurkę w moim pliku vector.s
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Dodałem także
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Żeby bylo wiadomo, że definicja jest gdzieś indziej. Wydawało mi się, że to już powinno wystarczyć ale nie wiem czemu dalej nie działa.
    Załączniki:
    • vector.s.zip (1.99 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #10 11537219
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    Freddie Chopin napisał:

    Atrybut jest generalnie konieczny chyba że masz wrapper w assemblerze, który załatwi za Ciebie niuanse powrotu z przerwania.


    Tu właśnie mamy taki wrapper, więc to wywal. Ja dałem przykład z mojego działającego kodu. Może raczej pomyślał bym nad atrybutem "naked"

    BTW, czym to kompilujesz?

    PS. W zasadzie to kompilator by strasznie krzyczał, jednak zapytam. Ten handler w C jest kompilowany do ARM kodu (nie Thumb)?
  • #11 11537689
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Kompiluje arm-none-eabi-gcc. Wlasnie zauwazylem, ze ten plik z przerwaniem mam w makefile w THUMB_SOURCE. Wrzuce pliczek do ARM_SOURCE w poniedzialek jak bede mial dostep do mojej plytki i dam znać co dalej sie dzieje. A ostrzezenia zadne nie wyskakuja.
  • #12 11537768
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    michcior napisał:
    PS. W zasadzie to kompilator by strasznie krzyczał, jednak zapytam. Ten handler w C jest kompilowany do ARM kodu (nie Thumb)?

    Skoro macie wrapper, to nie ma znaczenia.

    4\/3!!
  • REKLAMA
  • #15 11538518
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    ARM jest ogólnie uznawany za szybszy od Thumb. Zresztą oficjalne stanowisko ARM'a jest by pisać krytyczne kawałki w kodzie ARM (bo szybszy) a co nie krytyczne w Thumb (bo mniejszy). Jeśli już zadaliśmy sobie sporo trudu by wykorzystać FIQ, bo zależy na na szybkości i krótkim czasie wykonania przerwania FIQ, to raczej należy napisać/skompilować tą procedurę w kodzie ARM.
  • #16 11547768
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Trochę zmodyfikowałem kod - procedurę przerwania, dodałem także procedurę uruchamiającą przerwania i zwiększyłem znacznie rozmiar stosu dla FIQ. Funkcja obsługi przerwania jest wrzucona do sekcji ARM. I dalej nie działa :(. W ogóle nie wchodzi mi do przerwania. A przerwanie ma być okresowe i w nim ma zapalać się dioda i wysyłać literka przez uart. Podsyłam zaktualizowaną wersję vector.s. Moglibyście jeszcze raz rzucić okiem na to co stworzyłem i powiedzieć mi co jeszcze może być nie tak? Kod konfiguracji RTC od którego ma być przerwanie FIQ wygląda następująco:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    RTC, nie licząc przerwań działa poprawnie.
    Załączniki:
    • vector.s.zip (2.09 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #17 11563973
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Udało mi się po części uporać z problemem. Napiszę co poprawiłem - może komuś się przyda. W tym demie co miałem była funkcja do ustawiania przerwań, ale naklepana ręcznie - bez użycia tych funkcji z biblioteki od ST, początkowo nie używałem tej funkcji. Co zrobiłem, żeby działało - wyrzuciłem konfigurację przerwania z poziomu biblioteki ST - usunąłem następujące linijki
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    I zamiast tego wrzuciłem wywołaine mojej funkcji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Gdzie funkcja ta wygląda następująco:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Jedyny problem jest taki, że FreeRTOS startuje, program wchodzi w przerwanie raz wysyla literke a potem sie zacina i idzie gdzies w pole
  • Pomocny post
    #18 11564081
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    Chyba to właśnie co znalazłem w źródłach. Deklaracja funkcji przerwania nie może mieć atrybutu Interrupt("FIQ") skoro mamy już wrapper w assemblerze. Tak jak pisałem, spróbuj z __attrybut__((naked)) albo wcale. Jeśli zadeklarujemy to jako FIQ to kompilator dodaje kod odejmujący 4 od adresu powrotu, co my już robimy we wrapperku.
  • #19 11564147
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    michcior napisał:
    spróbuj z __attrybut__((naked))

    Niezbyt dobry pomysł, chyba że sam chcesz zajmować się odkładaniem na stos i przywracaniem rejestrów, oraz alokacją na stosie przestrzeni potrzebnej funkcjom.

    Atrybut ten można sobie stosować do napisanych ręcznie funkcji w assemblerze...

    4\/3!!
  • #20 11564212
    bimbarabam
    Poziom 14  
    Posty: 194
    Ocena: 1
    Dokladnie - usunałem ten atrybut i działa elegancko. Dzieki za pomoc!

Podsumowanie tematu

LABEL_AI_GENERATED
W dyskusji poruszono problem z nieprawidłowym działaniem przerwania od timera 1 w mikrokontrolerze STR912, przy użyciu VIC i UART. Użytkownik próbował skonfigurować przerwanie, aby wysyłać literkę 'c' przez UART, ale napotkał trudności. Odpowiedzi sugerowały, że konieczne jest poprawne skonfigurowanie wektora przerwań oraz użycie odpowiednich atrybutów w deklaracjach funkcji przerwań. Wskazano na znaczenie użycia FIQ dla priorytetowych przerwań oraz na konieczność usunięcia atrybutu "interrupt" w przypadku użycia wrappera w assemblerze. Ostatecznie, po modyfikacjach w kodzie, użytkownik zdołał rozwiązać problem, eliminując niepotrzebne linie kodu i poprawnie konfigurując przerwania.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA