Intteruptprioritäten AVR ändern/umgehen in C

OP #1919398
Lesenswert?

Hallo!

Ich benutze bei einem mega168 das Input-Capture-Int und ein 
Compare-Match-Int des Timer1. Zusatzlich noch UART per Int. Das 
Compare-Match ist vergleichsweise Timing-kritisch (auch unter Ausnutzung 
der automatischen Pin-Funktionen!).

Unter bestimmten Umständen führt das ausführen eines UART-Ints dazu, 
dass ICP-Int und Comp-Match-Int beide getriggert werden. Leider wird 
dann zuerst das ICP-Int ausgeführt (höhere Priorität), was dann dazu 
führt, dass das Compare-Int die Timing-Constraints nicht einhalten kann.

Als Lösung (abgesehen von anderen Optimierungen) hatte ich 
Pseudocode-maßig an folgendes gedacht:
1
ISR(ICP)
2
{
3
   if (CompareMatch)
4
   {
5
       "ret" (ohne Int-Flag zurückzusetzen)
6
   }
7
   .....
8
}

Das geht natürlich so nicht ganz, da dann wieder das ICP-Int 
angesprungen würde.

Was habt ihr für Vorschläge?

Grüße
Robert
Gast #1919441
Lesenswert?

Hi,

mal so ins blaue gesponnen:
1
u08 ICPFlag= flase;
2

3
ISR(ICP)
4
{
5
   if (CompareMatch)
6
   {
7
       ICPFlag= true;
8
       return;
9
   }
10
   .....
11
}
1
ISR(CompareMatch)
2
{
3
   .....
4
   // am ende
5
   if (ICPFlag == true)
6
   {
7
     // setze ICP-Int von Hand
8
     ....
9
     ICPFlag= false;
10
   }
11
}

Es treten also beide Ints gleichzeitig auf.
Der Input-Int verabschiedet sich und setzt noch vorher ein globales 
Flag.
In der CompareMatch wertest du nach allen anderen Operationen dieses 
Flag aus und setzt von Hand den Input-Intterupt.

Stephan
OP #1919468
Lesenswert?

Hallo Stephan,

vielen Dank für Deine zur Frage passende Antwort! Hab mal schnell 
nachgeschaut - aber leider täuscht mich meine Erinnerung nicht - das 
Int-Flag läßt sich nicht manuell setzen. Jedoch könnte man das ICP-ISR 
evtl. als Funktion aus dem Comp-Match-Int aufrufen - vielen Dank für die 
gute Idee!

Grüße
Robert
#1919700
Lesenswert?

Es gibt mehrere Möglichkeiten:
1
ISR( TIMER1_CAPT_vect, ISR_NOBLOCK )
2
{
3
// ...
4
}
Dann kann der Interrupt unterbrochen werden.


Den langsamen UART-Interrupt kann man leider nicht unterbrechbar machen, 
da das Flag beim Eintritt nicht gelöscht wird.
Du kannst aber die UART mit nem Timerinterrupt pollen und den dann 
unterbrechbar machen.


Peter
Persönliche Seite #1919785
Lesenswert?

Peter Dannegger schrieb:


> Den langsamen UART-Interrupt kann man leider nicht unterbrechbar machen,
> da das Flag beim Eintritt nicht gelöscht wird.

Doch geht auch. Allerdings nicht über diesen Mechanismus.

Stattdessen implementirt man es als normale ISR, deaktiviert direkt am 
Anfang die betreffende IRQ und dann folgt ein SEI. Am Ende alles retour.

So hab ich's mal in eienr länglichen Tmer-IRQ gemacht, die den 
IR-Empfang ausbrembste. Hat prima funktioniert. (Inzwischen geht's 
allerdings anders und ohne kaskadierende IRQ indem ich in der Timer-IRQ 
auf den IR polle.)

Wenn die Auswerte-Routinen für ICP/COMP nicht zu lange dauern, sehe ich 
keinen Grund, warum es nicht gehen sollte.
OP #1919951
Lesenswert?

Karl heinz Buchegger schrieb:
> Robert B. schrieb:
>> Mensch danke, darauf wär ich nie gekommen! Du meinst ich soll die
>> "_delay_ms(500);" Zeilen entfernen?
>>
>> Danke Danke Danke!
>
> Wenn das tatsächlich ernst gemeint ist, dann hat es wenig Sinn über
> irgendwelche ausgefuchsten Mechanismen zu debattieren. Dann stimmt
> vorher schon so einiges nicht, das bereinigt werden müsste.

Nein, war es natürlich NICHT! Es sind überhaupt keine _xs_delays in 
meinem ganzen Projekt. Die Antwort war um all jene glücklich zu machen, 
die glauben immer ihr lapidares Basiswissen kundtun zu müssen.

Ich "dekodiere" bzw. "enkodiere" einen seriellen Bus mit engen 
zeitlichen Vorgaben. Leider ist dafür auch mit Klimmzügen der 
Hardware-USART nicht ansatzweise in der Lage, so dass ich eben - extrem 
vereinfacht ausgedrückt - mit dem ICP-Int "dekodieren" und mit dem 
Compare-Match "enkodieren" muss. Da ich die Timing-Constraints einhalten 
muss ist das nicht so einfach. Die einzige "Beschleunigung" wäre es alle 
Bitzeiten vorher zu berechnen, was aber aufgrund von Telegrammlänge zu 
viel Speicher verbraucht: 30 Byte * 10 Bit/Byte * 2 Flanken/Bit * 
16bit/Flanke = 1,2KByte SRAM nur für ein Sende-Paket wenn nur 0xFF 
verschickt werden. Gleiches für RX = geht nicht. Also muss ich es leider 
wohl on-the-fly machen.

Die Möglichkeit Interrupts wieder global freizugeben scheint die Lösung 
zu sein. Es funktioniert alles wie gewünscht!

Vielen Dank!

Grüße
Robert
Gast #1919970
Lesenswert?

> Die Möglichkeit Interrupts wieder global freizugeben scheint die Lösung
> zu sein. Es funktioniert alles wie gewünscht!

Damit bestätigst Du mein Statement von gaanz oben: Deine ISRs dauern zu 
lang. Schön dass Du das doch noch zugeben konntest :-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren