ATmega: Zpracování více přerušení než jedno. Jak na to?

Pokud jsem to pochopil správně, umí Atmega více přerušení než jedno. Nikde jsem se ale nedočet nic ohledně prioritách, jelikož bych chtěl použít alespoň 2 přerušení.

:arrow_right: administrator: přejmenováno z "Zpracování přerušení"

U avr určite môžeš používať viac prerušení súčasne, tabuľka “Reset and Interrupt Vectors” v kapitole “Interrupts” datasheetu je už zoradená podľa priorít (najvyššiu prioritu má vždy reset).

Priority jsou dány adresou vektoru. Nižší adresa = vyšší priorita. Přerušení nemůže být přerušeno, pokud to ručně nepovolíš (tím můžeš také prioritu ovlivnit - přerušitelné přerušení má ve výsledku nejnižší prioritu).
Vektorů je hejno, stačí se podívat do DS.

A jak v bascomu to nastavit netušim.

Je to tak, jak jsem tušil. Jen jsem nevěděl, že mám hledat vektory přerušení. Vlastní přerušení povolit a využít vím - to jsem úspěšně použil v semaforech, ale nevěděl jsem, které přerušení “vyhraje”, když se potkají dvě.

Vezmu teoretickou situaci. Mám přerušení 0-3. S nejvyšší prioritou má 0, nejnižší 2.

Pokud probíhá podprogram přerušení 2 a přijde přerušení 1, tak se přeruší přerušení 2 jako kdyby ten podprogram byl součástí programu a nastalo klasické přerušení? A zpětně to dopadne stejně jako u klasického jednoho přerušení? Takže po skončení přerušení 1 to skočí na místo, kde to vyskočilo z podprogramu pro přerušení 2. Předpokládám, že pokud by nastalo přerušení 0, tak by se přerušilo i provádění podporogramu pro přerušení 2, provedl by se podprogram pro přerušení 0, navrátilo by se to do boku výskoru z podprogramu pro přerušení 1 a následně i 2 do základního programu.

Je moje úvaha správná?

V případě nutnosti nebude až tak obtížný programově donutit libovolné přerušení se zažadit do fronty, pokud se bude momentálně provádět jiné.

Jak bys chtěl donutit přerušení, aby se řadila do fronty, mi vskutku není jasné :slight_smile:.

Do fronty ano, ale s pevne urcenym miestom v nej. :slight_smile:

To znamena, ze akonahle je prerusenie povolene, (je jedno ci rucne alebo po ukonceni nejakeho predchadzajuceho prerusenia) vykona sa to prerusenie, ktore je aktivne a zo vsetkych aktivnych ma najvyssiu prioritu.

Takže asi takto:

Běží program
Vyvolá se přerušení s nižší prioritou
Zpracovává se podprogram přerušení s nižší prioritou
Vyvolá se přerušení s větší prioritou
Zpracuje se podprogram pro přerušení s vyšší prioritou
Dokončí se podprogram pro přerušení s nižší prioritou
Skočí to opět na místo v programu, kde byl přerušen

Doběhnutí přerušení aniž by bylo přerušeno přerušením s vyšší prioritou bych viděl takto:

Dal bych na začátek podprogramu test zda běží nějaké přerušení co nechci přerušit, ale má nižší prioritu.

Např.:

[code]Podprogram přerušení s nižší prioritou
x = 1
.
příkazy podprogramu
.
.
x =0
if y = 1 then gosub Podprogram přerušení s vyšší prioritou
return

Podprogram přerušení s vyšší prioritou
if x = 1 then y=1: return else y=0
.
příkazy podprogramu
.
return[/code]

Tak mě napadla ještě jedna otázka. Když běží podprogram přerušení s vyšší prioritou a nastane přerušení s nižší prioritou, tak:
a) přerušení s nižší prioritou se vynechá, jako by nikdy nenastalo
b) zařadí se do fronty a provede se ihned po skončení přerušení s vyšší prioritou
c) nastane něco jiného - nenapadá mě co

Tak to predsa nefunguje.

Preco necitas prispevky? :slight_smile: :slight_smile: :slight_smile:

napriklad ten moj z 08 leden 2012, 16:45

Spustenie prerusenia (akehokolvek) je automaticky spojene so zakazanim globalneho prerusenia. Po ukonceni prerusenia sa globalne prerusenie povoli. Ak ho medzitym nepovolis rucne.

Taky nevím, co složitého na větě: “Přerušení nemůže být přerušeno, pokud to ručně nepovolíš” :slight_smile:.
Přerušení se spustí, vykoná, pak se provede nejméně 1 instrukce přerušeného programu a pokud čekají další přerušení, pokračuje se tím s nejvyšší prioritou.
Pouze pokud si ÚMYSLNĚ RUČNĚ povolíš “nested interrupts” - tedy přerušení probíhajícího přerušení, pak může být probíhající přerušení přerušeno jiným.

Pokud se budeš držet pravidel pro tvorbu obsluhy přerušení (minimální délka), nemusíš priority a nested interrupts vůbec řešit.

Máš pravdu, nečet jsem to pořádně. Ale stále si nejsem jistý, jak zákaz přerušení funguje. Čítače běží a jen se nevygeneruje přerušení při jejich přetečení. Nebo se vygenerují, ale čekají ve frontě podle priority, až skončí to aktuální?

… a vykona sa to prerusenie, ktore je aktivne a zo vsetkych aktivnych ma najvyssiu prioritu.

Ved trochu kukni do toho datasheetu okolo tych preruseni.

Zkusím se do toho ds podívat. Anglicky umím mizerně, ale snad to nějak přelouskám.

1.) Poku je se objeví nové přerušení během obsluhy přerušení jiného,
pak toto nové přerušení čeká “ve frontě” až na něj dojde řada.

2.) Pokud se přerušení objeví vícera zdrojů najednou,
jsou obslouženy všechny v závislosti na prioritě.

3.) Pokud dojde k vícenásobnému přerušení z jednoho zdroje dřív,
než se k tomuto přerušení program dostane (např. obsluhuje jiné přerušení),
pak se zpravidla obslouží pouze to poslední (data z předešlých budou ztracena).
Tím bych se však moc nevzrušoval, protože k takové eventualitě může
dojít pouze při velmi rychlé komunikaci a při nedodržení jistého pravidla,
které říká, že

Prostě používej přerušení na uložení hodnot a vyhodnocení ponechej na hlavním programu. Snaž se v přerušeních vyvarovat smyček.
Ono takové zacyklované přerušení není žádná slast.

4.) Povolovat přerušení během obsluhy přerušení nedoporučuji,
pokud si vskutku nejseš jistý v kramflecích.
Ona nějaká ta ztráta času či dat je stále přijatelnější než zacyklovaný či
“zakouslý” program.

5.) Zdroj přerušení se po vygenerování přerušení z pravidla sám od sebe nezastaví.
Většinou to musíš obsloužit ty, pokud je to však potřeba.

Každé přerušení se dá individuálně povolit/zakázat příkazy ENABLE / DISABLE.
Kromě toho se dají globálně povolit/zakázat všechna přerušení příkazy ENABLE INTERRUPTS/DISABLE INTERRUPTS

Po resetu jsou všechna přerušení zakázána (tj. individuální i globální).
Pokud např. chceme povolit pouze přerušení od přetečení čítače 1, napíšeme
ENABLE OVF1
ENABLE INTERRUPTS

Jakmile program vstoupí do rutiny přerušení, automaticky se zakážou všechna přerušení.
Před opuštěním rutiny se opět automaticky povolí.

Pokud je program v přerušení a přijde další (povolené) přerušení, dokončí se první přerušení
a potom se vykoná druhé. Pokud čeká víc přerušení, vykonají se podle priority.
Žádné přerušení se neztratí.

Povolit přerušení v přerušení, jak se tu psalo, je většinou zbytečné
a může přinést víc škody než užitku.

Mám v tom trochu zmatek. Divous píše, že když přijde při jednom přerušení další a je povolené, tak se zařadí do fronty. Jenže taky píšete, že v okamžiku, kdy se provádí podprogram přerušení, tak je automaticky další přerušení zakázané. Takže pokud to chápu dobře, pokud by mělo proběhnout další přerušení, ale ještě není dokončeno první, tak se na konec fronty nezařadí, pokud ho já osobně nepovolím.

Mechanismus přerušení je tento:
Pro každé přerušení existuje “příznak přerušení” (interrupt flag).
Je to bit v IO registrech.
Po resetu má hodnotu 0.

Pokud nastane událost pro kterou existuje přerušení,
nastaví se příslušný příznak na 1 (bez ohledu na to, jestli je přerušení povoleno).
Tento příznak se vynuluje automaticky v rutině přerušení (ke které tento příznak patří).

Při běhu programu CPU neustále, během každé instrukce, kontroluje příznaky povolených přerušení.
Jakmile zjistí např. že příznak přerušení od přetečení čítače1 (timer1_overflow_flag) je nastavený a přerušení
od přetečení čítače1 je povoleno, vyvolá toto přerušení.
V rutině přerušení

  1. zakáže globální přerušení
  2. vymaže příznak timer1_overflow_flag
  3. vykoná kód přerušení
  4. povolí globální přerušení

Tyto operace nemají žádný vliv na eventuální další přerušení čekající ve frontě.
Jejich příznaky jsou stále nastaveny na 1.

Uvědomil jsem si, že pořádně nevím, co je to přesně globální přerušení. Zda při zákazu globálního přerušení se nesmí provést (další) přerušení s tím, že čekají ve frontě, až bude globální přerušení povoleno, či má to nějaké jiné dopady na program.

Globální přerušení … pokud není povoleno, žádné přerušení (kromě resetu) se nekoná i kdyby ses stavěl na hlavu

Lokální přerušení … povolují se pro každou instanci zvlášť. (čítače, AD převodníky, ap.)
Pro správnou činnost musíš mít povolené jak globální, tak lokální přerušení.

Příznak přerušení … každá instance, která dokáže vyvolat přerušení má někde v registrech tento bit,
který říká, že požadovaná událost (příjem bitu, překlopení čítače, ap.) nastala.

Celá sekvence pak vypadá takto:

  1. Povolíš globální přerušení
  2. Nastavíš instanci (př. časovač na 1s)
  3. Povolíš lokální přerušení pro časovač
  4. čekáš 1s
  5. objeví se log. 1 na příznaku přerušení
  6. zkontroluje se zda je povoleno lokální přerušení.
    Pokud není, tak se vrať na 5í.
  7. zkontroluje se globální přerušení.
    Pokud povolené není, tak se vrať na 5.
    8.) Přeruš současný běh programu a skoč na patřičnou funkci
    speciálně vytvořenou pro tuto instanci.

Zhruba tak nějak to funguje.
První tři kroky lze v podstatě navzájem přehazovat.

Globální přerušení povoluje nebo zakazuje všechna přerušení.
Pokud je globální přerušení zakázáno (DISABLE INTERRUPTS), jsou zakázána všechna přerušení.

Příklady:

ENABLE OVF1
ENABLE INTERRUPTS
Přerušení OVF1 (a každé další povolené) bude provedeno.
(To jest, při přetečení čítače1 program skočí na rutinu přerušení,
vykoná její kód, vrátí se do hlavního programu a pokračuje od místa, kde byl přerušen).

DISABLE OVF1
ENABLE INTERRUPTS
Přerušení OVF1 nebude provedeno (ale každé jiné, pokud je povolené, bude provedeno).
Program na přetečení čítače1 nijak nereaguje.

ENABLE OVF1
DISABLE INTERRUPTS
Přerušení OVF1 (a žádné jiné i když je povolené) nebude provedeno.

Přerušení lze povolit/zakázat kdykoliv během programu.
Když potřebujeme vykonat kód který nesmí být přerušený, napíšeme

DISABLE INTERRUPTS
'kód       'všechna přerušení jsou zakázána
ENABLE INTERRUPTS
'ta přerušení, která byla povolena před příkazem DISABLE INTERRUPTS jsou opět povolena

Edit:

Je to tak, a jiný dopad ohledně přerušení to nemá.
Samozřejmě takový zákaz nesmí trvat příliš dlouho, jinak bychom mohli některé přerušení propást. (Například čítač už mezitím přetekl vícekrát)
Proto se zdůrazňuje že obsluha přerušení má být co nejkratší.