Zdravím, měl bych takový dotaz. Jde o GCC pro AVR (mega). Řekněme že přijímám nějaká data, třeba po UARTu, v přerušení při příjmu. Takže přijde bajt, zavolá se přerušení, ja si vyzvednu obsah příslušného registru a dám ho třeba někam do bufferu a přerušení skončím. Problém je, že pokud se buffer zaplní (nebo nastane nějaká jiná událost) tak bych rád data v bufferu zpracoval. Na to by se mi asi hodilo nějak zařídit aby skončila obsluha přerušení ale místo návratu někam náhodně do hlavního programu (podle toho kde zrovna byl když přišlo přerušení) aby skočil do další funkce a až z té potom zpátky do hlavního programu. Jde tohodle nějak dosáhnout? Napadá mě pár řešení, teď narychlo jsem to vyřešil tak, že ke konci ISR zjistím jestli je třeba něco z bufferu zpracovávat a pokud ano tak povolím globální přerušení (ta zpracovávací funkce chvíli trvá a já chci obsluhovat další přerušení) a zavolám příslušnou funkci. Dále mám přes volatile globální proměnnou zařízeno aby případné další vyvolané UART přerušení nehráblo do bufferu nebo znovu nezavolalo zpracovávácí funkci dřív než je to možné (což povolí potom ta zpracovávací funkce). Problém vidím v tom, že ta obsluha přerušení která zavolá onu zpracovávací funkci je vlastně stále neopuštěná až dokud se zpracovávací funkce nedokončí, takže hádám že v paměti visí nějaké hodnoty registrů zazálohované před vstupem do rutiny přerušení což je zbytečné. Má někdo nějaký tip jak to řešit lépe? Jo a jednoduché řešení - ptát se v hlavním programu občas na stav bufferu, se mi nelíbí ani nehodí. Doufám že jsem svůj dotaz popsal dost srozumitelně.
Na fórech se často uvádí tyto zásady pro obsluhu přerušení.
Má být co nejkratší. Má v ní být jen to nejnutnější, ostatní se má udělat v hlavním programu.
2.
Nemají se v něm volat funkce.
3.
Přerušení se nemají vnořovat.
Tyto zásady můžeme porušit, ale např. čím více různých přerušení použijeme, tím těžší je
promyslet všechny eventuality.
Specielně u vnořených přerušení vidím komentáře jako
“Zkusil jsem to jednou a víckrát to dělat nebudu.”
Tady hrozí horší věci než že v paměti budou zbytečné hodnoty.
Co když přijdou další přerušení v době kdy se ještě nedokončil kód prvního přerušení?
Pokud přerušení RX nebude dokončeno do příchodu dalšího bajtu, dojde k jeho rekursivnímu volání se všemi nepříjemnými následky.
Já bych to řešil jednoduše tak, že bych v přerušení RX zapsal přijatý bajt do kruhového buferu
a z něho v hlavním programu četl.
Jak jsem řekl, ostatní jiná přerušení můžou být bez problému obsluhována a i další zavolání RX preruseni (nerikal bych tomu rekurze) je vyreseno tak aby se zkrátka nemohlo nic špatného stát, jediné co se může stát je, že by se zahodilo pár přijatých bajtů, což se ale nestane díky poměru rychlosti MCU a pomalosti UART komunikace (4800baud). Zkrátka nemám problém s tím že by mi to nefungovalo, funguje to, a bude to fungovat vždy. Jak jsi řekl: “tím těžší je promyslet všechny eventuality” - ano, je to fuška, ale promyslel jsem je a troufám si říct (i po “zátěžových” testech), že to bude vždy fungovat. Připomenout si ona tři doporučení určitě neuškodí, ale ty já znám a vím čemu se pokud možno vyhýbat.
A jak jsem také psal - jednoduše v hlavním programu to prostě řešit nemůžu, protože hlavní program dělá spoustu věcí, občas si klidně na půl hoďky odskočí do nějakého podprogramu atd… takže bych musel na X místech v programu kontrolovat stav bufferu a to se mi nelíbí. Vážně by mi vyhovovalo, kdyby prostě šlo zařídit, že občas se z RETI neskočí hned zpátky tam odkud se přišlo, ale udělá se mezipřistání v nějaké funkci. RX přerušení už by bylo dávno vyřízeno, mohlo by být klidně voláno znovu aniž by se znovu někde štosovaly nějaké zálohy registrů.
Co mě napadá za možná řešení:
- Nasadit nějaký RTOS - ten program je vcelku rozsáhlý, některé věci se právě musí dít tak nějak na pozadí, zároveň je potřeba obsluhovat displej, klávesnici, SDkartu, data z UARTu, uživatelské rozhraní…zkrátka čím víc toho mám tím víc vidím že si to o RTOS úplně říká, nicméně učit se RTOS a celé to předělavát na to teď nemám čas a potřebuji to dodělat.
- Napsat tu obsluhu přerušení nějak “naked” nebo jak se tomu říká, všechno co C řeší za mě řešit ručně a zároveň si ručně pohrát s návratovýma adresama na které se skočí po RETI a samozřejmě to vyřešit i tak aby se nakonec skočilo tam kam má. Ale to mi příjde skoro až jako šílenost. Ani nevím jestli to jde…?
- Nasimulovat nějaké softwarové přerušení, RX funkce by zkontrolovala buffer, případně nastavila nějaký bitík který by po opuštění RX funkce vyvolal ihned další přerušení do funkce na zpracování bufferu, v té povolit globální přerušení a zařídit aby se nevolala vícekrát už by bylo jednoduché. Nicméně to se mi také moc nelíbí, nenapadá mě jaké přerušení by se dalo použít, a všude se píše že softwarová přerušení nejsou vůbec nutná.
No a pak by mě zajímalo jestli někdo nemá nějaký jiný geniální nápad.