Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Cortex] NVIC Priorytety przerwań

tymon_x 08 May 2012 23:56 5899 29
Computer Controls
  • #1
    tymon_x
    Level 30  
    Po małej dyskusji oraz przejrzeniu Cortex ™-M3 TechnicalReference Manual, Revision: r1p1, nasuwa się takie ciekawe pytanie. Wiadomo, że zewnętrzne przerwania od układów peryferyjnych są podłączane pod odpowiednie linie IRQ_n, w tym przypadku mamy numery od 0-239, czyli IRQ0-239. Natomiast poziom priorytetów można ustalić dla wszystkich przerwań od 0 do 255 w rejestrze Interrupt Priority Registers. Dla systemowych przerwań (SysTick...) mamy specjalny rejestr System Handler Priority Registers, który spełnia podobną rolę, ale z dopiskiem: System handlers are a special class of exception handler that can have their priority set to any of the priority levels. Do czego zmierzam ? Cierpliwości...

    W opisie na temat rejestrach IP widniej coś takiego:

    5.3.1. Priority levels wrote:
    The NVIC supports software-assigned priority levels. You can assign a priority level from 0 to 255 to an interrupt by writing to the eight-bit PRI_N field in an Interrupt Priority Register, see Interrupt Priority Registers. Hardware priority decreases with increasing interrupt number. Priority level 0 is the highest priority level, and priority level 255 is the lowest. The priority level overrides the hardware priority. For example, if you assign priority level 1 to IRQ[0] and priority level 0 to IRQ[31], then IRQ[31] has higher priority than IRQ[0].
    Note

    Software prioritization does not affect reset, Non-Maskable Interrupt (NMI), and hard fault. They always have higher priority than the external interrupts.


    When multiple interrupts have the same priority number, the pending interrupt with the lowest interrupt number takes precedence. For example, if both IRQ[0] and IRQ[1] are priority level 1, then IRQ[0] has higher priority than IRQ[1]

    Interrupt Priority Registers wrote:
    Use the Interrupt Priority Registers to assign a priority from 0 to 255 to each of the available interrupts. 0 is the highest priority, and 255 is the lowest.

    Czyli rejestry IP dotyczy wszystkich przerwań, nawet systemowych, to by się zgadzało że jest 240 sztuk IRQ dla układów peryferyjnych oraz 16 systemowych. Ciekawostką jest, że konfiguracja dla zewnętrznych przerwań zaczyna się od 0 do 239, czyli ostatnie 16 mogą należeć do systemowych.Wynika to z chociażby funkcji CMSIS NVIC_SetPriority i przykładowych wartości IRQ_n, dla przykładu STM32F1, WWDG_IRQn = 0 i tak dalej. Natomiast przerwania systemowe są zapisywane do rejestru SHP. I wszystko jest cacy, bo działa zgodnie z tabelką 5.2. Exception types. Natomiast podejrzewam, że przerwania systemowe (jeśli faktycznie dobrze zgaduje) mają zawsze w IP wartość zero, bo CMSIS je pomija, ale najlepiej w ogóle nie są tam podłączone i poziom zależy od SHP, ale z cytatu wynika że dotyczy to tylko względem reszty przerwań systemowych. Czyli zawsze będą miały wyższy priorytet niż te zewnętrzne, taka sztuczka hardware. Druga sprawa to optymalizacja sprzętu, bo taki zabieg wymaga tylko 8 32-bitowych rejestrów do podtrzymania wartości przerwań (240 IRQ + 16).

    Teraz sprawa priorytetów na grupy i ich podgrupy za pomocą rejestru Application Interrupt and Reset Control Register:

    5.3.2. Priority grouping wrote:
    To increase priority control in systems with large numbers of interrupts, the NVIC supports priority grouping. You can use the PRIGROUP field in the Application Interrupt and Reset Control Register to split the value in every PRI_N field into a pre-emption priority field and a subpriority field.

    Widać, że dotyczą wszystkich pól IP. Czyli całego zakresu 0-255, mimo że przerwania zewnętrzne mają zakres 0-239. Idąc tym tropem, rejestr AIRCR i pole PRIGROUP nie ma żadnego wpływu na zachowanie rejestrów SHP. A jeśli przerwania systemowe faktycznie są zaszyte w rejestrach IP, to CMSIS je sprytnie pomija. Nawet ujemne wartości w IRQ_n to potwierdzają. To mamy zawsze przerwania systemowe o większym priorytecie niż zewnętrzne (co jest logiczne), bo ich wartość w IP jest zawsze teoretycznie równa 0 (zakładając, że są tam podłączone, ciągle przypominam o 0-255 pól po 8 bitów według Reference Cortex). Natomiast w rejestrze SHP możemy uwzględnić priorytety względem przerwań systemowych, a przerwania zewnętrzne zawsze można jeszcze podzielić na grupy i odpowiednie podgrupy.

    Więc teoretycznie można ustalić przerwania systemowe na równi z zwykłymi przerwaniami poza rdzeniem ? (nie wliczając tych HardFault bo one zawsze mają najwyższy priorytet i nie są typu Configurable) Jeszcze tego nie stosowałem, ale w weekend to sprawdzę, taki hacking rdzenia Cortex :D Ale się zdziwię, jeśli moje domysły są prawdziwe, może ktoś to testował już ?
  • Computer Controls
  • #2
    michalko12
    MCUs specialist
    Czytam i nie do końca rozumiem co masz na myśli. Przecież przypisanie wyższych wartości priorytetów przerwaniom systemowym i niższych zewnętrznym już powoduje, że zewnętrzne przerwania mają wyższy priorytet.
  • #3
    tymon_x
    Level 30  
    PRIGROUP wrote:
    PRIGROUP field is a binary point position indicator for creating subpriorities for exceptions that share the same pre-emption level. It divides the PRI_n field in the Interrupt Priority Register into a pre-emption level and a subpriority level.

    PRIGROUP wedlug Reference dotyczy tylko rejestrow IP, a nie SHP (System Handler). Czyli jak interpretowac wartosc pol priotytetow ? Zalozmy ze IRQ23 bedzie zapisany jako 0010_1000, a PRIGROUP ustawiony na 011, czyli 16 grup i kazdy po 16 podgrup (xxxx_yyyy). To systemowe przerwanie bedzie mialo mniejszy priorytet tylko w przypadku > 0010_1000 i nie bedzie podzialu na pre i sub priorytety ?
  • Helpful post
    #4
    michalko12
    MCUs specialist
    tymon_x wrote:
    To systemowe przerwanie bedzie mialo mniejszy priorytet tylko w przypadku > 0010_1000 i nie bedzie podzialu na pre i sub priorytety ?

    Dokładnie tak.
    Quote:
    The combination of the group priority and the sub-priority is referred to generally as the priority.


    Grupowanie działa tylko na zewnętrznych przerwaniach i powoduje, że przerwania z tej samej grupy nie wywłaszczają się mimo że maga mieć wyższy subpriorytet . Subpriorytety decydują o tym które następne przerwanie ma być wywołane jeśli wisi kilka naraz.

    Np. mamy grupę z zakresem od 16 do 32 czyli 0001_yyyy

    Pierwszy przypadek
    Aktualnie wykonywane przerwanie ma 20 priorytet, a przerwanie systemowe 18, to przerwanie zostanie wywłaszczone.

    Drugi przypadek
    Jeśli aktualnie wykonywane przerwanie ma 20 priorytet a przerwanie systemowe 22, to przerwanie nie zostanie wywłaszczone.

    Trzeci przypadek
    Jeśli aktualne przerwanie ma 20 priorytet i jest zgłoszone inne zewnętrzne z priorytetem 17 to aktualne nie zostanie wywłaszczone. Z zewnętrznych przerwań mogą tylko te wywłaszczyć co są w grupie 0 - 15 (0000_yyyy)
  • Computer Controls
  • #5
    slawek55
    Level 23  
    Zobacz. W bibliotekach jest taka funkcja
    void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority){..}
    która przyjmuje tylko wartość priorytetu oraz nr przerwania, z tym że zarówno systemowe jak i zewnętrze działają.
    To teraz, czy można tak np ustawić przerwanie np SysTick że będzie miało najniższy priorytet od pozostałych, niższy niż np USART.
    Teraz na zewnętrznych mamy grupowanie, które nie dotyczy (tak jak piszesz) systemowych (tak jak piszesz) SysTick'a. Jak określisz taktycznie kolejność przerwań?
    W takim razie dlaczego dołożyli (ARM) rejestr SCB->SHP
  • #6
    michalko12
    MCUs specialist
    Domniemam....

    Rdzeń ma fizycznie własny mały kontroler przerwań z 16 liniami, sa to te systemowe, które maja własną grupę rejestrów SHP. Do jednej z linii przyczepiony jest NVIC prawdopodobnie na którejś pozycji "reserved". NVIC ma własne rejestry i własne reguły rządzenia przerwaniami. Rdzeń wystawia priorytet akurat wykonywanego przerwania do NVICa, ten na na każdej linii z 240 ma komparator, takie komparatory są tez na tych 16 liniach w rdzeniu ( w rzeczywistości jest mniej i komparatory są krótsze niż 8 bitów). Jeśli jakiś komparator wskaże mniejszą wartość wystawia sygnał. Jeśli sygnał pochodzi z rdzenia no to przerwanie zostaje wywłaszczone i numer priorytetu zmienia się. W NVICu ten sygnał zanim trafi do rdzenia jest przepuszczany przez filtr grupowy. Jeśli sygnal pochodzi z grupy o mniejszym numerze to trafia do rdzenia i następuje wywłaszczenia przerwania.

    Dodano po 10 [minuty]:

    slawek55 wrote:
    To teraz, czy można tak np ustawić przerwanie np SysTick że będzie miało najniższy priorytet od pozostałych, niższy niż np USART.


    Jeśli uC obsługuje 16 priorytetów wystarczy że SYSTick'owi przypiszesz 16 (15) i SYSTick już żadnego przerwania nie wywłaszczy. Grupowanie to jest maskowanie linii zgłoszenia przerwania tylko w NVICu, ale wagi priorytetów nadal oznaczają to samo.
  • #7
    tymon_x
    Level 30  
    No wlasnie tez mialem podobne domniemania jak to zostalo rozwiazane praktycznie. Bo wezmy taki przyklad , PRIGROUP=011 (xxxx_yyyy). Dla IRQ=23, IRQ=21 damy 0001_0100, a dla IRQ=18 oraz IRQ=40 0001_0011 (ta sama grupa), natomiast SysTick i Usage ustalimy na 0001_0011. To przerwania systemowe zawsze beda wywlaszczac przerwania zewnetrzne, w tym wypadku ma wieksze prawo niz IRQ=23/21 (bedzie wywlaszaczac), natomiast dla reszty bedzie sie wykonywalo zgodnie z pozycja jaka ma przerwanie (gdzie Usage ma pierwszenstwo w tym wypadku), natomiast miedzy IRQ nie bedzie dochodzilo do wywlaszczania, ale jesli jeszcze przeniesc SysTick wyzej do 0001_0100, to bedzie wywlasczal pozycje od 0001_0101, ale sam bedzie mogl wywlaszczany przez wyzsze priorytety, czyli ponizej 0001_0011 wlacznie. To troche niedermistyczne zachowanie dla reszty, bo trzeba o tym pamietac. A NVIC widzi to tylko jako 256 przerwan.
  • #8
    slawek55
    Level 23  
    A powiedz, czy to nie powinno być opisane. Zwróć uwagę, że, jak to fajnie nazwałeś, domniemasz, a wg mnie powinno być jasno powiedziane co i jak i nawet w takim dokumencie, który ARM publikuje.

    P.S. Czyli z tym grupowaniem to jest tak, że należy rozpatrywać łączą ilość bitów w rejestrze priorytetów i to określi dopiero poziom priorytetu jako całość, zobaczyć jaki priorytet ma przerwanie systemowe i dopiero zbadać które wywłaszczy które. Bo teraz oczywiście będzie mowa o wywłaszczeniu, a nie czekaniu w kolejce na zakończenie aktualnego. Czy tak?

    Piszę tak na "chłopski"i rozum bo jakoś łatwiej to ogarnąć, więc proszę o wyrozumiałość :-)
  • #9
    michalko12
    MCUs specialist
    Zawsze powtarzałem, że ARMy nie są łatwe ze względu na dokumentację. I jak ktoś nie ma doświadczenia to naprawdę będzie miał z nimi problemy. Do wielu spraw tez trzeba na logikę podchodzić.

    Dodano po 2 [minuty]:

    slawek55 wrote:
    P.S. Czyli z tym grupowaniem to jest tak, że należy rozpatrywać łączą ilość bitów w rejestrze priorytetów i to określi dopiero poziom priorytetu jako całość, zobaczyć jaki priorytet ma przerwanie systemowe i dopiero zbadać które wywłaszczy które.


    Dokładnie tak.

    slawek55 wrote:
    Bo teraz oczywiście będzie mowa o wywłaszczeniu, a nie czekaniu w kolejce na zakończenie aktualnego. Czy tak?

    ???
  • #10
    slawek55
    Level 23  
    Quote:
    Bo teraz oczywiście będzie mowa o wywłaszczeniu, a nie czekaniu w kolejce na zakończenie aktualnego. Czy tak?
    ???


    Chodziło mi o to że:
    Np w książce z BTC o STM32 jest napisane, iż przerwania należące do tego samego priorytetu grupowego (preemption prioritet) mającego np nr 1 nie przerywają tych mających nr 0 tylko czekają na ich zakończenie. nie mam jej przy sobie ale jest tam nawet taki rysunek pokazujący iż niektóre czekają a inne przerywają.
  • #11
    michalko12
    MCUs specialist
    slawek55 wrote:
    mającego np nr 1 nie przerywają tych mających nr 0 tylko czekają na ich zakończenie.


    Przerwania z priorytetem ustawionym na 0 wywłaszczy przerwanie z priorytetem ustawionym na 1. Na odwrót to nie nastąpi. Jeśli obydwa przerwania będą w tej samej grupie to w żadna stronę wywłaszczenie nie nastąpi i przerwanie oczekujące będzie musiało poczekać aż aktualnie wykonywane samo się zakończy.
  • #12
    slawek55
    Level 23  
    Zrobiłem kilka testów z STM32F103RB.
    Układ testowy działał tak
    SystTick przerwanie co 0.3sek zmienia stan diody.
    EXTI0_IRQ z Line0 przy opadającym zboczu ma pętlę wstrzymującą na 5 sek.
    Każemu z przerwań ustawiam priorytet funkcją NVIC_SetPriority().
    Dodatkowo mogę zmienić
    Code:
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);                //Wybor modelu grupowania przerwan
    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;      //Priorytet grupowy
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;


    Z tym że funkcja NVIC_SetPriority() jest pod tymi trzema funkcjami, czyli powinna jako ostatnia ustawić priorytet dla EXTI0 i on powinien być obowiązujący.

    Obserwacje:
    1 Jeśli PriorityGroup=0 i dwie poniższe też 0 jak na listingu u góry to EXTI0 zawsze ma przerywa działanie SysTicka niezależnie jak jemu ustawię (próbowałem od 0 do 15)
    2.PriorityGroup=1 a IRQChannelPreemptionPriority=0 oraz IRQChannelPreemptionPriority =0 to przy Systick proprity =0 oraz 7 to on przerwywa EXTI0 a dla 8 EXTI0 wstrzymuje SysTick_IRQ
    3. Taka funkcja w ustawieniach przykładu 2 NVIC_SetPriority (EXTI0_IRQn, 0..15); nic nie zmienia.

    Zgłupiałem!!!
  • #13
    michalko12
    MCUs specialist
    Nie używałem nigdy tych bibliotek i nie rozumiem o czym piszesz tym bardziej że dublujesz linijki kodu:

    Code: c
    Log in, to see the code


    Nie powinno być cos takiego:?
    Code: c
    Log in, to see the code



    Skorzystałem z tych dwóch linków:

    http://brawikov.narod.ru/StdPerLibSTM32F10x/group__MISC__Private__Functions.html

    http://www.fioboards.com/learn/index.php/STM32_Interrupt_Service_Routine_Priority

    I pamiętaj, że 0 to najwyższy priorytet.
  • #14
    slawek55
    Level 23  
    Tak prawda, pomyliłem linijki przy wklejaniu. W oryginale było tak jak Ty napisałeś.
    Ale poz tym niżej występujące linijka czyli zastosowanie takiej instrukcji
    NVIC_SetPriority(EXTI0_IRQ, 1);

    powinna nadpisac ustawienia dla IRQChannelPreemptionPriority oraz IRQChannelSubPriority a jakoś tego nie robi mimo że operuje na tych samych rejestrach.

    Poza tym przecież SysTick jest wyżej w hierarchii priorytetów więc nawet jak będą oba miały ustawiony priorytet na 0 to i tak pierwszeństwo ma SysTick. A z testów tak nie było.

    Po prostu dało mi to do myślenia: Jak mając ustawioną GroupPriority, PreemptionPriority oraz SubPriotity wyliczyć priorytet z zakresu 0-15, bo z tego co pisałeś wcześniej i tak na to się przekłada.
  • #15
    Freddie Chopin
    MCUs specialist
    A przypadkiem żeby jedno przerwanie przerwało drugie nie trzeba w obsłudze każdego z nich rozpocząć od... włączenia przerwań (bo przecież domyślnie po wejściu do przerwania są zablokowane). Tym sposobem w ogóle przerwania zagnieżdżone mogą działać...

    4\/3!!
  • #16
    michalko12
    MCUs specialist
    slawek55 wrote:
    Poza tym przecież SysTick jest wyżej w hierarchii priorytetów więc nawet jak będą oba miały ustawiony priorytet na 0 to i tak pierwszeństwo ma SysTick. A z testów tak nie było.


    Przerwania o takim samym priorytecie nigdy nie są wywłaszczane. Ta hierarchia ma tylko zastosowanie gdy oba przerwania będą miały taki sam priorytet i oba będą w oczekiwaniu na obsługę, wtedy przerwanie z niższym numerem zostanie wykonane jako pierwsze.

    Używasz tej biblioteki więc ja nie mam nic do powiedzenia bo nie znam jej, spróbuj zrobić to samo bezpośrednio na rejestrach i wtedy możemy dalej dyskutować chyba że ktoś Ci pomoże kto zna dobrze ta bibliotekę.

    Dodano po 2 [minuty]:

    Freddie Chopin wrote:
    A przypadkiem żeby jedno przerwanie przerwało drugie nie trzeba w obsłudze każdego z nich rozpocząć od... włączenia przerwań (bo przecież domyślnie po wejściu do przerwania są zablokowane)


    Nie są zablokowane, to nie AVR. ;) Bez sensu byłby wtedy system priorytetowy. Można je sobie samemu zablokować jak istnieje taka potrzeba ;)
  • #17
    felekfala
    Level 19  
    Dokładnie nie są blokowane, kiedyś robiłem testy na przyciskach i nie pamiętam by obsługiwane przerwanie domyślnie blokowało inne przerwania.

    Zastanawiam się natomiast ile poziomów zagnieżdżania przerwań jest dostępnych. We wszystkich przykładach są pokazywane sytuacje gdy przerwanie o wyższym priorytecie zostaje wywłaszczone o następnym przerwaniu o niższym priorytecie. Co będzie w sytuacji gdy w trakcie trwania poprzednich przerwań zgłoszone zostanie trzecie przerwanie o jeszcze niższym priorytecie. Wydaje mi się, że sytuacja zostanie powtórzona i dojdzie do następnego zagnieżdżenia, czyli do obsługi tego trzeciego przerwania i wywłaszczeniu poprzednich?
  • #19
    michalko12
    MCUs specialist
    Nie no, jakiś limit jest np. rozmiar stosu ;)
  • #20
    slawek55
    Level 23  
    Ponieważ dalej mi to spędza sen z oczu, a przy okazji daje fragment z książki o której mówiłem na temat STM32 opisującej przerwania.
    Zabaczcie jeszcze cos ciekawego. W bibliotece STM są takie dwie funkcje przeliczające nr priorytetu mając grupę, preempriority oraz subpriority.

    Z książki o STM:
    Quote:
    NVIC...kieruje się następującymi zasadami arbitrażu
    1. Jeśli przerwania mają różne priorytety grupowe:
    - Przerwanie którego priorytet grupowy jest wyższy (ma niższy numer) jest wykonywane natychmiast - wywłaszcza (przerywa) wykonywanie obsługi przerwań o niższych priorytetach grupowych.
    2. Jeśli przerwania należą do tej samej grupy:
    - kolejność obsługi określa podpriorytet
    - rozpoczęta procedura obsługi nie jest przerywana nawet jeśli przyjdzie zgłoszenie o wyższym podpriorytet z tej samej grupy
    3. Jeśli przerwania maja identyczne priorytety
    - decyduje nr przerwania - niższy ma pierwszeństwo
    4. Jeśli zgłoszenie ma niższy priorytet od już obsługiwanego:
    - oczekuje w kolejce na wykonie procedury obsługi


    Oraz te funkcje
    Code:
    static __INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
    
    {
      uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);          /* only values 0..7 are used          */
      uint32_t PreemptPriorityBits;
      uint32_t SubPriorityBits;

      PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;
      SubPriorityBits     = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;
     
      return (
               ((PreemptPriority & ((1 << (PreemptPriorityBits)) - 1)) << SubPriorityBits) |
               ((SubPriority     & ((1 << (SubPriorityBits    )) - 1)))
             );
    }

    static __INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* pPreemptPriority, uint32_t* pSubPriority)
    {
      uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);          /* only values 0..7 are used          */
      uint32_t PreemptPriorityBits;
      uint32_t SubPriorityBits;

      PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;
      SubPriorityBits     = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;
     
      *pPreemptPriority = (Priority >> SubPriorityBits) & ((1 << (PreemptPriorityBits)) - 1);
      *pSubPriority     = (Priority                   ) & ((1 << (SubPriorityBits    )) - 1);
    }


    Z książki fragment ten jest na stronie od 113.

    To nie zgadza się trochę z tym co Wy pisaliście o przerwaniach.
    Czy zechcecie jakoś to mi wytłumaczyć? Zobaczcie jeszcze na te moje testy z przerwaniami.
  • #21
    michalko12
    MCUs specialist
    A pokaz w którym miejscu się nie zgadza, bo dokładnie tak to było opisywane
  • #22
    slawek55
    Level 23  
    Mój błąd źle to zinterpretowałem.

    A jak bys określił ogólny nr przerwania mając grupę oraz pre i sub priorytet?
    Przykładowo 2 przypadki:
    1. Jest przerwanie systemowe oraz dwa zewnętrze i zależy aby zewnętrze były przed systemowym.
    2. Jak wyżej z tym że to systemowe ma być najwalniejsze.

    Próbowałem wyznaczyć numer ogólny przerwania korzystając z tych podanych funkcji, ale nie wiem dlaczego dostaję zakres do 4.
  • #23
    michalko12
    MCUs specialist
    W tym wątku jest wszystko już napisane.

    Masz np 16 priorytetów przerwań. 16 bo tyle np w STM32 zaimplementował producent.
    W rejestrach priorytetów te 16 priorytetów jest reprezentowane przez 4 najstarsze bity XXXX----. Bity X mogą być jeszcze rozdzielone tworząc grupy priorytetów i subpriorytety np
    GGSS----. G oznacza numer grupy, S oznacza numer subpriorytetu. Nie wnikając w grupowanie mamy 16 priorytetów o wartościach od (0<<4) do (15<< 4) czyli 0x00, 0x10, 0x20, 0x30..., 0xF0. Priorytet 0x00 jest najwyższym priorytetem, priorytet 0xF0 jest najniższym priorytetem. Jeśli przerwania pogrupujesz niczego to nie zmieni, nadal będziesz miał te same wartości priorytetów.np bez grupowanie 1100_0000 i z grupowaniem 1100_0000.
    Np. dla podziału na 4 grupy (GGSS----) wartość 1100_0000 reprezentuje 3 grupę i 0 sybpriorytet, ale po złożeniu nadal reprezentuje ogólny priorytet czyli 0xC0. Dla pierwszego przypadku wystarczy, że ustawisz priorytet przerwania systemowego na 0xF0 a resztę na dowolny inny i już będziesz miał to czego oczekujesz. Dla drugiego przypadku ustawiając wartość priorytetu na 0x00 i resztę na dowolne inne z 16 dostępnych też będziesz miał oczekiwany rezultat.
    Przedstawiłem wartości, które są w rzeczywistości wstawiane do rejestrów, biblioteka prawdopodobnie jako argumenty przyjmuje wartości priorytetów od 0-15.
  • #24
    slawek55
    Level 23  
    Dzięki.
    Na razie nie męczę Ciebie bo mnie przeklniesz, a absolutnie nie jest to moim celem.
    To co piszesz mam sens.
    W takim razie jak robiłem te swoje testy z przerwaniami musiałem coś pomylić i chyb domyślam się że funkcja która ustawiała priorytet wpisywała wartości na pozycje które nie są brane przez uC pod uwagę. Może dlatego zwiększanie wartości priorytetu nie dawało rezultatu i niby dla ciągłych wartości liczb podawanych do funkcji przez pewien moment nic się nie działo, choć powinno.

    Dodano po 5 [godziny] 24 [minuty]:

    Zastanawia mnie jeszcze coś ale od innej strony.
    Do czego tak na prawdę jest grupowanie?
    Dlaczego pytam? Jak poprzednio w tym układzie testowym ustawiłem pre i sub priorytet na 0 dla przerwania zewnętrznego natomiast dla systemowego na 2 funkcją NVIC_SetPriority. Dla ustawionego grupowania 0 przerwanie zewnętrzne wstrzymuje przerwanie systemowe. Po zmianie na grupowanie 1 przewianie systemowe przerywa przerwanie zewnętrzne.
    Skoro grupowanie oznacza tylko interpretację dla bitów a po ich złożeniu powinniśmy mieć to samo to skąd różnica w działaniu?
  • Helpful post
    #25
    michalko12
    MCUs specialist
    Przełączenie się na PRIGROUP modyfikuje zachowanie się kontrolera NVIC. Masz 16 przerwań czyli 4 bity konfiguracyjne, np. dzielisz to na 4 grupy czyli dwa bity będą tworzyć grupę, a dwa podgrupę. Są 4 grupy z 4 subpriorytetami. Teraz np. masz 4 UARTY i ich przerwaniom nadajesz priorytety z tej samej grupy ale z innymi subpriorytetami. Nadchodzi przerwanie od jednego UARTA i jest obsługiwane, jeśli w tym czasie nadejdzie przerwanie od innego UARTA te pierwsze nie zostanie przerwane mimo że może mieć wyższy subpriorytet i tym samym ogólny priorytet. Zostanie ono obsłużone dopiero po zakończeniu obsługi pierwszego. To przerwanie może zostać tylko przerwane przez przerwanie z priorytetem z innej grupy z wyższym priorytetem lub przez przerwanie systemowe które ma wyższy priorytet ogólny. Czyli jeśli UARTY były przypisane od grupy 01xx to tylko przerwanie z priorytetem z grupy 00xx może przerwać działanie procedury obsługi przerwania od UARTA. Np priorytety z grupy 00xx mogą być przypisane magistralom SPI i I2C.

    Jaki cel ma to grupowanie? Ograniczenie ilości wywłaszczeń, a tym samym zapotrzebowania na stos, ponieważ przerwania z tej samej grupy będą wywoływane jedno po drugim, nie będą się wywłaszczać na wzajem, a o kolejności decydują subpriorytety. Stosując grupowanie z np. takim podziałem 4:4 jest pewność, że maksymalnie ( wśród przerwań IRQ) mogą nastąpić tylko 4 wywłaszczenia, bez grupowania takich wywłaszczeń może być 16, a każde wywłaszczenie pochłania stos. Pamięci w ARMach dużo, ale jeśli zaczniesz stosować RTOSa to ta pamięć szybko będzie pochłaniana.
  • #26
    Smashing
    Level 20  
    Witam
    Próbuje to połączyć z tym co piszą na stornie ARM.
    Czyli jeśli np w M3 rejestr AIRCR bity [10:8] wyglądają tak:

    [Cortex] NVIC Priorytety przerwań

    1. To dla Stm32 wygląda tak że nie ma pozycji PRIGROUP:
    0b000
    0b001
    0b010
    tylko zaczyna się od 0b010 do 0b111 ?
    Z tego wychodzi że Interrupt priority level value w STM32, nie jest PRI_N[7:0] tylko PRI_N[7:4] wtedy z tej tabelki wychodzi że w Stm32 jak wpiszę :
    AIRCR bity [10:8]
    b011 to
    Group priorities =16
    Subpriorities =0;... czyli OK
    Tylko jak procesor wstaje to PRIGROUP ustawione jest na 0 (0b000), czyli co wtedy?
    Pozdrawiam
  • #27
    michalko12
    MCUs specialist
    Smashing wrote:
    Tylko jak procesor wstaje to PRIGROUP ustawione jest na 0 (0b000), czyli co wtedy?

    Nic. Wszystkie wartości PRIGROUP od 0 do 3 mają takie same znaczenie czyli 16 grup i 0 sub.
  • #28
    Smashing
    Level 20  
    michalko12 wrote:
    Nic. Wszystkie wartości PRIGROUP od 0 do 3 mają takie same znaczenie czyli 16 grup i 0 sub.

    No właśnie w teorii też myślę że tak jest ale praktyka jest dla mnie trochę inna jeśli chodzi o FreeRtos.
    Na stronie http://www.freertos.org/RTOS-Cortex-M3-M4.html piszą wyraźnie:
    If you are using an STM32 with the STM32 driver library then ensure all the priority bits are assigned to
    be preempt priority bits by calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS is started.
    Oni używają bibliotek stm32 czyli:
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ) równa się NVIC_SetPriorityGrouping(3) z core_cmX.h
    Jeśli tego nie zrobię czyli nie ustawię NVIC_SetPriorityGrouping(3) wcale (pownno być zero jak procesor wstaje) to jak w FreeRtos używam gdzieś:
    Code: c
    Log in, to see the code

    Ważne jest to portMAX_DELAY, to po kilku minutach, czasem godzinach procesor "stoi" w:
    Code: c
    Log in, to see the code
    i nie może wyjść z przerwania.
    Opisane jest to tutaj:
    http://www.freertos.org/FreeRTOS_Support_Foru...horeGive_Interrupt_infinite_Loop_4040580.html
    Jak dam np
    Code: c
    Log in, to see the code

    to tego problemu nie ma.
    Wychodzi z tego że PRIGROUP 0 jest ale nie działa tak jak PRIGROUP 3

    Pozdrawiam
  • #29
    Freddie Chopin
    MCUs specialist
    Może jednak masz błąd gdzieś indziej? Wg informacji z najbardziej pewnego źródła: http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/DUI0552A_cortex_m3_dgug.pdf (strona 4-18) ustawienie PRIGROUP na wartości od 0 do 3 ma jednakowy efekt dla STM32, bo tenże układ ma tylko 4 wyższe bity priorytetów:

    Quote:
    Implementations having fewer than 8-bits
    of interrupt priority treat the least significant bits as zero.


    Dopiero ustawienie PRIGROUP na wartości od 4 do 7 faktycznie ma jakiś efekt, który może coś tam zaburzać.

    Co do tematu który przywołałeś, to tam jest opisane raczej to, że ktoś nie umie czytać ze zrozumieniem i ustawił priorytet przerwania na 0, czyli powyżej max dozwolonej wartości dla przerwań korzystających z API FreeRTOSa dla przerwań (w domyślnym przypadku, jest to zwykle 11, gdy configMAX_SYSCALL_INTERRUPT_PRIORITY we FreeRTOSConfig.h jest ustawione na 191).

    U siebie zawsze ustawiam Priority Grouping na 0 (zresztą jest to domyślna wartość), i nie spotkałem się z problemami, choć nie używam też bzdurnych bibliotek od ST.

    4\/3!!
  • #30
    szczywronek
    Level 27  
    Pozwolę sobie odkopać temat... i się nie zgodzić ;) Jeśli dobrze rozumiem wypowiedzi kolegi michalko12 m.in.:
    michalko12 wrote:
    Domniemam.... [...] Grupowanie działa tylko na zewnętrznych przerwaniach
    to domniemał On, że:
    - grupowanie priorytetów odnosi się tylko do przerwań przechodzących przez NVIC
    - porównując priorytety dwóch przerwań: "zewnętrznego" (priorytet w rejestrze IPR) oraz "systemowego" (priorytet w rejestrze SHP) należy zapomnieć o całym grupowaniu i po prostu porównać dwie wartości bez żadnych ceregieli

    Dotąd się zgadza? Bo jeśli nie, to moje dalsze wywody nie mają sensu, albowiem twierdzę iż: grupowanie dotyka tak samo przerwań przechodzących przez NVIC jak i „systemowych”. Chyba, że czegoś nie zauważam i da się inaczej wytłumaczyć poniższy eksperyment:

    - podział bitów priorytetu ustawiony na GGSS (dwa bity grupa + dwa bity pod-priorytet/subpriority)
    - priorytet przerwania zewnętrznego (NVIC'owego): 6 (dwójkowo 0110: grupa – 1, podpriorytet – 2)
    - priorytet przerwania systemowego: 5 (dwójkowo 0101: grupa – 1, podpriorytet – 1)
    - przerwanie systemowe nadchodzi w czasie wykonywania procedury obsługi zewnętrznego

    Wnioski z tego wątku są takie (jeśli dobrze rozumiem), że porównując priorytety z rejestru SHPR i IPR należy „olać” grupowanie i porównać wartości. W „eksperymencie” przerwanie systemowe ma niższą wartość priorytetu/wyższy priorytet, więc powinno wywłaszczyć przerwanie zewnętrzne. A tego nie robi!

    Idąc dalej:
    michalko12 wrote:
    Jeśli przerwania pogrupujesz niczego to nie zmieni.

    A jednak! Po wprowadzeniu do powyższego przykładu małej modyfikacji, polegającej tylko na zmianie podziału bitów priorytetu z GGSS na GGGS (modyfikacja PRIGROUP):

    - priorytet przerwania zewnętrznego (0110) oznacza teraz: grupa – 3, podpriorytet 0
    - priorytet przerwania systemowego (0101) oznacza teraz: grupa – 2, podpriorytet 1

    przerwanie systemowe przejmuje kontrolę nad... światem i zaczyna wywłaszczać zewnętrzne!

    Wcześniej oba przerwania były w tej samej grupie i wywłaszczanie nie następowało, teraz są w różnych grupach i się wywłaszczają. Wartości priorytetów się nie zmieniły, zmieniło się tylko grupowanie.

    Poniżej kod „eksperymentalny”, testowany na Cortexie M3 w STM32F103. W roli przerwania NVIC'owego występuje EXTI0, w roli przerwania „rdzeniowego” występuje PendSV. Żadne inne przerwania (w tym SysTick) nie są uruchomione. Funkcje "wyświetlaczowe" służą tylko obrazowaniu co się aktualnie dzieje - nazwy są intuicyjne więc myślę, że każdy się domyśli co robią.

    Code: c
    Log in, to see the code