Forum: Mikrocontroller und Digitale Elektronik Interrupt-Routine zu langsam


von Daniel (Gast)


Lesenswert?

Ich möchte Daten empfangen, die während eines Clocksignals von einem
anderen Baustein übetragen werden. Der Controller ist ein At90S2313 und
ich programmiere ihn mit Codevision C-Compiler. Das Clocksignal wird von
dem Baustein generiert. Zur Zeit arbeite ich mit einem externen
Interrupt, der zur steigenden Flanke des Colocksignals auslöst. In der
Interrupt-Routine wird dann den Port abfragt und das Ergebnis in ein
Array geschrieben(0 oder 1).
Die Routine arbeitet allerdings zu langsam, so daß Daten verloren
gehen.
Gibt es eine Möglichkeit, die Routine zu beschleunigen? Ist es
überhaupt sinnvoll einen Interrupt so einzusetzen?
Gruß Daniel

von dave (Gast)


Lesenswert?

In welchem Verhältnis stehen denn die "ankommende Frequenz" und die
Taktfrequenz?

Inline Assembler oder ganz einfache Operationen beschleunigen sicher.
Sobald du irgendwas mit dem Array machst (Berechnungen, Verschieben
etc.) muss das ausgelagert werden.. meiner Meinung nach.

Notfalls einfach in die ISR eine Bool an oder aus machen... an = bit
abholen, aus = kein bit abholen.. und das dann in der Main abhandeln.

dave

von Michael Wilhelm (Gast)


Lesenswert?

Hört sich irgendwie nach einer Software I2C Routine an. Such mal ein
bischen im Forum, wurde schon oft beschrieben.
MW

von Uwe Große-Wortmann (Gast)


Lesenswert?

wenn C zu langsam ist bliebe noch die möglichkeit, (zumindestens in der
interruptroutine) auf assembler umzusteigen. denn nur so kann man die
maxiamle geschwindigkeit des avrs ausnutzen. ein compiler muss immer
kompromisse zu lasten der geschwindigleit eingehen, da er für sämtliche
fälle ein funktionerende lösung liefern soll. wenn du direkt in
assembler programmierst, kansst du selbst entscheiden, welcher befehl
nötig ist und was in deinem speziellen fall weggelassen werden kann.

wie hoch ist in etwa die frequenz des taktsignals, und wieviele daten
müssen dabei eingelesen und gespeichert werden?

von Aleksej Kiselev (Gast)


Lesenswert?

The automatic saving and restoring of registers R0, R1, R15, R22, R23,
R24, R25, R26, R27, R30, R31 and SREG, during interrupts can be turned
on or off using the #pragma savereg directive.

So was steht in Gebrauchanleitung von CodeVision, wenn du diese
automatische Speicherung abschaltest, bringt es dir ein Ersparnis von
mindestens 26 Befehlen.
Wenn es doch nicht ausreichend wird, dann hilft nur Assembler...

von crazy horse (Gast)


Lesenswert?

ganau das wird die Lösung sein.
Listing anschauen, welche Register in der ISR wirklich gebraucht werden
und nur diese sichern. Allerdings aufpassen bei Programmänderungen.

von Daniel (Gast)


Lesenswert?

Danke für eure Antworten.
Es handelt sich nicht um I2C. Die Taktflanke kommt ca alle 60us und die
Taktfrequenz ist 9,216MHz. #pragma savereg hatte ich schon eingebaut.
Mit Assembler kenne ich mich leider nicht wirklich gut aus.

Der Inhalt meiner Interruptroutine (Sichern einiger Register ist
natürlich auch noch enthalten)ist dieser:

if (PIND.4 == 1)
{messung[i]='1';}
else
{messung[i]='0';
}
TCNT0=0;
i++;

Könnte mir das jemand in Assembler übersetzen? Das Array kann auch vom
Typ Bit sein.
Wäre prinzipiell eine Routine ohne Interrupt schneller?
Daniel

von crazy horse (Gast)


Lesenswert?

wie gross ist denn messung[x]?

von wb1 (Gast)


Lesenswert?

Wenn du ein Array aus 8 bit hast, kann es so aussehen:

.def temp = r16
.def temp1 = r17
Einsprung_von_interrupt:
sbis pind,0     ;teste bit0 und ueberspringe befehl wenn wenn pind,0=1
sbr temp,1  ;setze im register temp bit 0 auf 1
rol temp  ;rotiere nach links
clr temp1  ;lade temp 1 mit 0
out tcnt0,temp1  ;schreibe temp1 nach tcnt0
reti

Das sind inclusive interruptaufruf, sprung zur Serviceroutine und
Interruptruecksprung 24 Takte.
Bei 9,2 MHz also 2,6 ex-6 Sekunden

von wb1 (Gast)


Lesenswert?

Entschuldigung
Im temp ist jetzt der Kehrwert von pind,0
statt sbis pind,0 muss es sbic pind,0 heissen.
Dann herrscht wieder Gleichlauf

von peter dannegger (Gast)


Lesenswert?

Ehe Du überhaupt anfängst zu programmieren, mußt Du erstmal wissen, wie
lang der Impuls an PIND.4 nach der Taktflanke stabil anliegt.

Da die Impulse ale 60µs kommen dürfte das arg wenig sein.

Dann kannst Du ausrechnen, wieviel CPU-Zyklen Du Zeit hast und ob
überhaupt eine minimale Chance besteht.

Ein leerer Interrupt kostet ja schon 10 Zyklen.

Andere Interrupts kannst Du getrost vergessen.

Der AVR ist für schnelle Interrupts schlecht geeignet, da er keine
Interruptprioritäten unterstützt.


Peter

von Daniel (Gast)


Lesenswert?

Es sollen ca. 90 Bits empfangen werden. messung[90]. Habe den Takt
gerade noch mal genau gemessen. Der Takt steht ca. 75us stabil an, die
Taktflanke kommt nach 150us wieder. Wie lange sollte der Takt denn
stabil anstehen? Nach einigen Modifikationen wird meistens auch nur 1
Bit registriert. Gestern vormittag waren es noch ca. 20 Bits.
Danke für den Assemblercode, werde ihn probieren.

von Michael (Gast)


Lesenswert?

Ich sehe keinerlei Probleme, 75µs Signale sauber zum empfangen, auch
wenn alle Register gerettet würden. Allerdings sollte die INT-Routine
nur empfangen und nicht noch 'rumtüddeln'. Das kann man Deinem Code
aber nicht ansehen.

von Daniel (Gast)


Lesenswert?

Es läuft jetzt einwandfrei!!!
Sogar ohne Assembler, nur #pragma savereg- und manuelles Sichern
einiger Register. Hab Verzögerungsschleifen in die Interruptroutine
eingebaut. Hab den Eindruck, sie ist zu schnell durchgelaufen.
Irgendwie schon seltsam, aber hauptsache es geht jetzt.
Vielen Dank an alle.
Gruß Daniel

von Michael (Gast)


Lesenswert?

"Hab Verzögerungsschleifen in die Interruptroutine eingebaut. "

Bitte nicht ! Hast Du vielleicht die falsche Flanke erwischt ?

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.