Forum: Mikrocontroller und Digitale Elektronik Intteruptprioritäten AVR ändern/umgehen in C


von Robert B. (robertb)


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

von g457 (Gast)


Lesenswert?

> Was habt ihr für Vorschläge?

ISRs kürzer machen.

von Robert B. (robertb)


Lesenswert?

Mensch danke, darauf wär ich nie gekommen! Du meinst ich soll die 
"_delay_ms(500);" Zeilen entfernen?

Danke Danke Danke!

von g457 (Gast)


Lesenswert?

> Du meinst ich soll die "_delay_ms(500);" Zeilen entfernen?

Wär schon mal ein guter Anfang.

von Floh (Gast)


Lesenswert?

>> Du meinst ich soll die "_delay_ms(500);" Zeilen entfernen?
>
> Wär schon mal ein guter Anfang.

Du könntest auch noch mehr machen. Z.b. Code zeigen, deine 
Timingvorgaben mal spezifizieren...
:-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ohne was vom Code zu sehen kann man da schlecht Tipps geben.

Möglicherweise dauert die UART-ISR zu lange, weil sie ne FIFO bedient... 
man weiß es nicht.

Welche Möglichkeiten hast du, die IRQ-Latenz zu verringern?

von Stephan (Gast)


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

von Robert B. (robertb)


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

von Peter D. (peda)


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

von Johann L. (gjlayde) Benutzerseite


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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Robert B. (robertb)


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

von g457 (Gast)


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 :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.