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
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
Hört sich irgendwie nach einer Software I2C Routine an. Such mal ein bischen im Forum, wurde schon oft beschrieben. MW
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?
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...
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.
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
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
Entschuldigung Im temp ist jetzt der Kehrwert von pind,0 statt sbis pind,0 muss es sbic pind,0 heissen. Dann herrscht wieder Gleichlauf
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
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.
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.
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
"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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.