Hallo, wenn auf einem AVR die Interrupts gloabl mit cli() deaktiviert werden, um beispielsweise ein Codestück unterbrechungsfrei auszuführen, und währenddessen tritt ein Interrupt auf, wird dieser dann ausgeführt, wenn ich die Interrupts mit sei() wieder aktiviere, oder ist der dann "verloren", bzw. was kann man machen, damit diese nicht verloren gehen? Grüße, Randy
Nein, die Interrupts gehen nicht verloren. Sie werden angesprungen, sobald sei() ausgeführt wurde. Wenn Interrupts zulange disablet werden, können allerdings eben doch Interrupts verloren gehen, eben dann, wenn in dieser Zeit mehr als ein Interrupt einer Quelle auftritt. Dann gibt es beispielsweise Zeichenverlust auf der seriellen Schnittstelle.
Als Lösung kann man innerhalb eines längeren Codeblocks mal eben kurz die Interrupts freigen: [code] sei nop cli [\code] Damit würden nach sei und nop jeweils Interrupts abgearbeitet werden können. Und für mehr als ein paar Takte muss man selten Interrupts verriegel.
Ja also das reicht mir. Also bei den schnellen Interrupts ist mir das nicht so wichtig - da kommen dann ja auch schnell wieder neue. Aber ich hab auch Interrupts, die nur sehr sehr selten kommen - und solche will ich nicht verpassen, aber diese würden ja nach dem cli()...sei()-Block ausgeführt werden.
"Also bei den schnellen Interrupts ist mir das nicht so wichtig - da kommen dann ja auch schnell wieder neue" Das muss man sich mal auf der Zunge zergehen lassen, sehr schön. Sch.... auf den Int, kommt ja bald ein neuer :-)
:-) Naja das was schnell ist ist bei mir entweder die Nulldurchgangserkennung, und wenn ich da mal vergesse, die Triacs zu zünden - das merkt keiner (zumindest so wie ich sie einsetze, als Dimmer, nicht), oder der IR-Empfänger, und da kann man im schlimmsten Fall auch einfach nochmal auf die Fernbedienung drücken :-).
mag sein, dass es Fälle gibt, wo es wirklich egal ist. Trotzdem, solltest du dir nicht angewöhnen. Interrupts sollten immer alle bearbeitet werden/können. Gerade das kann nämlich eine ziemlich tückische Angelegenheit werden, da hilft nur eine worst-case-Betrachtung. Es gibt Gerätschaften, die laufen wochenlang störungsfrei, dann plötzlich spinnen die. Wird dann schnell auf EMV oder Stress mit der Stromversorgung geschoben, ist aber eigentlich ein gravierender Softwarefehler.
Randy N. wrote: > :-) Naja das was schnell ist ist bei mir entweder die > Nulldurchgangserkennung, Hmmm, ääähhhh... 50 Hz (oder 100 Hz) sind bei Dir "schnell"??? Aus Sicht eines MCs ist das verdammt langsam... > ..., oder der IR-Empfänger, Naja, wirklich "schnell" sind die auch nicht. Wenn Du Deinem Programm wegen Rechenzeitmangel bereits die Freiheit gönnst solche "langsamen" Ereignisse verpassen zu dürfen, dann machst Du irgendwas Grundlegendes falsch... Es gibt einige Dinge, die nicht durch Interrupt unterbrochen werden dürfen, doch diese dauern immer nur wenige Takte. Im Übrigen hält man ISRs möglichst kurz, so dass auftretende Interrupts das Hauptprogramm nicht zu lange unterbrechen. ...
Hallo, hätte in dem Zusammenhang auch mal eine Frage. Habe in meiner ISR (UART Rx) eine State machin mit switch/case realisiert um die empfangenen Zeichen auszuwerten. Im worst case dauert ein Aufruf 745 Takte (minimal 206 Takte). Ist das so noch vertretbar? Oder währe es besser die Zeichen über einen Puffer einzulesen und im Hauptprogramm den Buffer bei jedem Durchlauf zyklisch abzufragen? Was sagt Ihr aus Eurer Erfahrung? Was währe ein besserer Stiel? Peter
@Peter: Das kann man nicht pauschal sagen. Wenn der UART-Rx-Interrupt der einzige aktive Interrupt ist und die ISR nicht länger dauert als der Abstand zwischen zwei ankommenden Zeichen, dann ist das kein Problem, auch wenn es kein guter Programmierstil ist.
@johnny-m Ja ist der einzige, aktive Interrupt. Hab den Quarz auch so gewählt das es mit den Takten passt (1, 8432MHz -> 1056 Takten @ 19200bps). Aber mir geht es halt ums Prinzip. Wie macht man so was am besten damit es sicher läuft (auch nach Änderungen/Erweiterungen) und nach Möglichkeit auch noch portabel ist (leicht in andere Programme zu integrieren ohne viele Änderungen. Peter
Peter wrote: > Wie macht man so was am besten damit > es sicher läuft (auch nach Änderungen/Erweiterungen) und nach > Möglichkeit auch noch portabel ist (leicht in andere Programme zu > integrieren ohne viele Änderungen. Indem im Interrupt nur das Nötigste gemacht wird (eben z.B. mit nem Puffer) und die Auswertung der Daten im Hauptprogramm.
Peter wrote: > ... > Aber mir geht es halt ums Prinzip. Hmmm, es kommt immer auf den Einzelfall an. Was in einem Fall vorteilhaft ist, kann im anderen Fall schon schädlich sein. Wenn das Programm größer wird und mehrere Interruptquellen hat, dann ist ein RX-Buffer als FIFO sicher sinnvoll. Meist wird aber an anderen Stellen Rechenzeit verschwendet, indem Wartezeiten durch Schleifenzählen (Zeitschleifen) oder Busywait erzeugt werden. Es lohnt sich also nicht, nur auf den RXC-Interrupt zu schauen ohne das gesamte Programm zu kennen. ...
@hannes Im Moment hängt eigentlich alles nur von der ISR ab. Sind Zeichen empfangen und ausgewertet, wird ein entsprechendes Flag gesetzt. Das Hauptprogramm fragt die Flags ab und führt entsprechende Funktionen aus. In diesem Fall macht es so evt. Sinn. Aber es ist halt geplant das ganze noch zu erweitern. Wie genau steht allerdings noch nicht fest. Dazu kommt auf jeden Fall noch SPI oder mindestens I2C. Denke mit diesem Hintergrund währe ein Rx FIFO sinnvoll. Danke für die Hilfe! Peter
>Nein, die Interrupts gehen nicht verloren. Sie werden angesprungen, >sobald sei() ausgeführt wurde. Das gilt aber nur, wenn es auch "echte" Interrupts mit eigenem Flag sind. Ist m.W. nicht auf allen MCs so. Gruß Lutz
> Wenn Du Deinem Programm wegen Rechenzeitmangel bereits die Freiheit > gönnst solche "langsamen" Ereignisse verpassen zu dürfen, dann machst Du > irgendwas Grundlegendes falsch... Ich habe noch nicht so einen Fall, aber angenommen ich hätte jede Stunde einen externen Interrupt, und der würde genau in der Zeit, in der die Interrupts deaktiviert sind, auftreten, dann wollte ich wissen, ob ich den jetzt verpasst hab (was fatale Folgen haben könnte), oder ob der noch nach dem sei() ausgeführt wird. Mich hatte es einfach rein hypothetisch interessiert, wie das der µC handhabt. Und natürlich verpasse ich auch die ganzen Nulldurchgänge nicht, aber das wäre (wieder hypothetisch) nun jetzt nicht sooo schlimm. Ob es irgendwann wirklich mal dazu kommt, dass der Interrupt genau dann auftritt, steht auf einem anderen Blatt, aber theoretisch ist es möglich. :-) > Es gibt einige Dinge, die nicht durch Interrupt unterbrochen werden > dürfen, doch diese dauern immer nur wenige Takte. Im Übrigen hält man > ISRs möglichst kurz, so dass auftretende Interrupts das Hauptprogramm > nicht zu lange unterbrechen. Genau so ist es bei mir. Im Interrupt schreibe ich etwas in eine Queue und erhöhe die Position und im Hauptprogramm lese ich die Queue, erniedrige die Position und verarbeite das Ganze. Und das Hauptprogramm darf nun nicht zwischen dem Lesen der Queue und dem Ändern der Position unterbrochen werden, und drum muss da ein cli()...sei() rundrum. Aber da cli()...sei() ja für alle Interrupts gilt, wollte ich wissen, ob alle Interrupts, die ja durchaus in dieser Zeit auftreten können, ignoriert werden. Um die Interrupts nicht ganz so häufig ein- und ausschalten zu müssen, setze ich sogar noch eine Statusvariable ein, die angibt, ob Änderungen in der Queue vorliegen, und vom Interrupt gesetzt wird.
Ein Ereignis, das einen Interrupt auslösen darf, setzt erstmal nur ein Interrupt-Flag. Einige spezielle Ereignisse können zusätzlich noch was Anderes tun, z.B. kopiert ICP noch den aktuellen Timerstand ins ICP-Register. Wir haben also ein gesetztes Interrupt-Flag... Dann gibt es für jeden möglichen Interrupt noch das Interrupt-Freigabe-Flag. Dieses wird vom Programm(ierer) gesetzt, wenn der Interrupt aktiviert/freigeschaltet werden soll. Und zu guterletzt gibt es noch das I-Flag im SREG, das Interrupts global erlaubt bzw. verbietet. Eine (Hardware-) Logik im AVR überürüft ständig (bei jedem Takt), ob alle drei Bedingungen (Interrupt-Freigabeflag, Interrupt-Flag und I-Flag im SREG) zutreffen und löst dann den (R)Call zum Interrupt-Vektor aus. Die meisten Interrupt-Quellen setzen ihr Int-Flag und lassen es stehen. Es wird dann durch den Aufruf der ISR (per Hardware) gelöscht. Es gibt aber auch Interrupt-Quellen, die ihr Interrupt-Flag wieder löschen, wenn die auslösende Bedingung nicht mehr vorliegt (z.B. UDRE). Im Einzelfall sollte man also das Datenblatt befragen, das ist da sehr informativ. Zur Queue... Ich nutze (allerdings in ASM) meist einen Ringbuffer mit zwei Pointern. Dabei verwaltet die ISR den einen Pointer, das Hauptprogramm den anderen. Bei Gleichstand der Pointer ist der Buffer leer. Der Pointer des Datenempfängers eilt also immer dem Pointer des Datenlieferanten hinterher. Hierbei kommt es zu keinem Konflikt, da muss kein Interrupt gesperrt werden. Den Fall, wo ISR und Hauptprogramm auf dieselben Ressourcen zugreifen, habe ich eigentlich sehr selten. > ..., aber angenommen ich hätte jede Stunde > einen externen Interrupt, und der würde genau in der Zeit, in der die > Interrupts deaktiviert sind, auftreten, ... Dann kommt es auf den Modus des externen Interrupts an. Im Flankenmode verpasst Du ihn nicht. Im Level-Mode bleibt das Interrupt-Flag allerdings nur solange stehen (laut Datenblatt des Tiny2313), wie der Auslösepegel am Int-Pin anliegt. Diesen Interrupt könntest Du also verpassen, wenn Dein Programm den Interrupt länger sperrt als der Interrupt-Impuls dauert. Also immer schön das Datenblatt befragen, das ist nicht nur für ASM-Programmierer interessant... ;-) ...
Hannes Lux wrote: > Zur Queue... Ich nutze (allerdings in ASM) meist einen Ringbuffer mit > zwei Pointern. Dabei verwaltet die ISR den einen Pointer, das > Hauptprogramm den anderen. Bei Gleichstand der Pointer ist der Buffer > leer. Der Pointer des Datenempfängers eilt also immer dem Pointer des > Datenlieferanten hinterher. Hierbei kommt es zu keinem Konflikt, da muss > kein Interrupt gesperrt werden. Den Fall, wo ISR und Hauptprogramm auf > dieselben Ressourcen zugreifen, habe ich eigentlich sehr selten. Kannst du mal ein Beispiel deiner push- und pop-Routinen zeigen? Mich würde mal interessieren, wie du da die Überprüfung auf Über-/Unterlauf mit gewohnt Lux'scher Effizienz eingebaut hast ;) Denn RP und WP (Readpointer und Writepointer) sind ja nun nicht nur bei leerem FIFO gleich, sondern auch wenn es voll ist. Daher habe ich mir angewöht, jeweils noch eine Variable mitzuführen, die den Füllstand beinhaltet, da geht auch die Auswertung relativ einfach.
@Hannes Lux: Joa soweit war mir das klar, aber es hätte ja sein können, dass wenn die Interrupts deaktiviert sind, keine Flags in die Flag-Register geschrieben werden. Trotzdem danke für das Posting :-). > Zur Queue... Ich nutze (allerdings in ASM) meist einen Ringbuffer mit > zwei Pointern. Dabei verwaltet die ISR den einen Pointer, das > Hauptprogramm den anderen. Bei Gleichstand der Pointer ist der Buffer > leer. Genau so mach ichs, mit einem statischen Array und von vornherein festgelegter Größe, z.B. 100 Elemente. Und mit Modulo rechne ich die Position für das Element aus, was neu hinzugefügt werden soll. Also neuerIndex = (alterIndex + 1) % maximaleGröße. Nun kann es aber sein, dass die Queue voll ist, und das älteste Element überschrieben werden muss. Und DANN muss ich die Interrupts für die Zeit sperren.
> Genau so mach ichs, mit einem statischen Array und von vornherein > festgelegter Größe, z.B. 100 Elemente. Und mit Modulo rechne ich die > Position für das Element aus, was neu hinzugefügt werden soll. Also > neuerIndex = (alterIndex + 1) % maximaleGröße. Nun kann es aber sein, > dass die Queue voll ist, und das älteste Element überschrieben werden > muss. Und DANN muss ich die Interrupts für die Zeit sperren. Urks, bitte nicht. Wenn du schon unbedingt modulo verwenden willst, dann bitte mit Grössen als Zweierpotenzen (z.B. 128 Byte statt 100). Den Index könntest du aber auch einfach auf die Länge des Puffers prüfen und gegebenenfalls nullen. Dann gibt's auch keine Probleme mit Überläufen (gibt's mit Zweierpotenzen allerdings auch nicht). Wenn ich's mir so überlege, ist die Verwendung von einem frei durchlaufenden Index, der mit modulo (Bzw. optimiert natürlich dann einfach and) zurückgesetzt wird sogar noch besser als mit einem Vergleich, spart zwei Takte pro Zugriff...
1 | inc rp |
2 | cpi rp, DATALENGTH |
3 | brne PC + 2 |
4 | clr rp |
5 | |
6 | ;gegen |
7 | |
8 | inc rp |
9 | andi rp, DATALENGTH - 1 |
> Kannst du mal ein Beispiel deiner push- und pop-Routinen zeigen? Mich > würde mal interessieren, wie du da die Überprüfung auf Über-/Unterlauf > mit gewohnt Lux'scher Effizienz eingebaut hast ;) Ein neues ("effizientes") Beispiel habe ich jetzt nicht greifbar... Beim Lesen vom Buffer vergleiche ich vorher den Low-Teil beider Pointer und breche bei Gleichstand ab (Buffer leer). Beim Schreiben auf den Buffer erhöhe ich eine Kopie vom Schreibpointer um 1 und vergleiche die mit dem Lesepointer, bei Gleichheit (die eigentlich nie eintreten sollte) wird bis zur Ungleichheit gewartet (Buffer voll). Mit Push und Pop hat das nix zu tun. > Wenn ich's mir so überlege, ist die Verwendung von einem frei > durchlaufenden Index, der mit modulo (Bzw. optimiert natürlich dann > einfach and) zurückgesetzt wird sogar noch besser als mit einem > Vergleich, spart zwei Takte pro Zugriff... Ach Du meinst das Begrenzen des Pointers auf Buffergröße... Das geht besonders einfach, wenn man den Buffer auf (SRAM-)Seitenanfang legt. > ... z.B. 100 Elemente. Auch beim Benutzen einer Hochsprache sollte man nicht vergessen, dass der AVR intern binär arbeitet und ihm Rechnerei mit "100" bedeutend mehr Arbeit bereitet als Buffergrößen in Zweierpotenzen. > Und mit Modulo ... Der AVR kann nicht (per Hardware) dividieren. Buffergrößen in Zweierpotenzen erlauben das Anwenden der AND-Verknüpfung zur Pointerbegrenzung, was (im günstigsten Fall (ANDI)) einen einzigen Prozessortakt kostet. Man kann in einer Hochsprache durch unbedachte Wahl der Funktionen bzw. Algorithmen einem AVR schon eine Menge unnötige Arbeit aufhalsen. 8-) ...
Hannes Lux wrote: >> Kannst du mal ein Beispiel deiner push- und pop-Routinen zeigen? Mich >> würde mal interessieren, wie du da die Überprüfung auf Über-/Unterlauf >> mit gewohnt Lux'scher Effizienz eingebaut hast ;) > > Ein neues ("effizientes") Beispiel habe ich jetzt nicht greifbar... > Beim Lesen vom Buffer vergleiche ich vorher den Low-Teil beider Pointer > und breche bei Gleichstand ab (Buffer leer). Beim Schreiben auf den > Buffer erhöhe ich eine Kopie vom Schreibpointer um 1 und vergleiche die > mit dem Lesepointer, bei Gleichheit (die eigentlich nie eintreten > sollte) wird bis zur Ungleichheit gewartet (Buffer voll). Mit Push und > Pop hat das nix zu tun. > >> Wenn ich's mir so überlege, ist die Verwendung von einem frei >> durchlaufenden Index, der mit modulo (Bzw. optimiert natürlich dann >> einfach and) zurückgesetzt wird sogar noch besser als mit einem >> Vergleich, spart zwei Takte pro Zugriff... > > Ach Du meinst das Begrenzen des Pointers auf Buffergröße... Das geht > besonders einfach, wenn man den Buffer auf (SRAM-)Seitenanfang legt. Achso, du verwendest jeweils "echte" Pointer. Bei mir ist das jeweils eine 8-Bit-Variable als Index. Erfordert dann natürlich noch etwas mehr Rechnerei. Mit push und pop meinte ich eigentlich das Laden eines Bytes in den Puffer, bzw. das Holen davon (Wie beim Stack halt). Mit Busy-Wait rumhängen bis wieder Platz ist, ist natürlich auch eine Idee ;)
Philipp Burch wrote: > Achso, du verwendest jeweils "echte" Pointer. Bei mir ist das jeweils > eine 8-Bit-Variable als Index. Erfordert dann natürlich noch etwas mehr > Rechnerei. Ja, und zwar jedes mal wenn du schreibst/liest. Also jedesmal wenn du das Array indizierst... Nicht so toll :-) Zwei einzelne Pointer finde ich besser.
> Mit Busy-Wait > rumhängen bis wieder Platz ist, ist natürlich auch eine Idee ;) Das schmeckt mir auch nicht, deshalb habe ich bei den LCD-Routinen bei der alten Zünduhr auch darauf verzichtet. Der Buffer umfasst aber eine ganze Page, da ist Überlauf mehr als unwahrscheinlich. Wenn es zum Überlauf kommen kann, dann klemmt irgendwas Anderes im Programm. Dann sollte man das Konzept überprüfen. ;-) Ich hatte auch bisher keine Anwendung, wo der AVR z.B. so schnell mit UART-Daten zugeschüttet wird, dass ihm die Zeit fehlt, sie zu verarbeiten. In einem Fall (die neue Zünduhr) schaufelt ein PC-Programm die Zünddaten aus einer EXCEL-Datei per UART in den Mega8535 der Zünduhr, der sie dann ins eigene EEP brennt. Da dies (durch das EEP-Brennen) länger dauert, hält das PC-Programm Pausen zwischen den Datensätzen ein. Es kommt eben darauf an, dass sich beide Kommunikationspartner verstehen, hohe Datenübertragungsrate alleine ist eben nicht alles... ...
Simon Küppers wrote: > Philipp Burch wrote: >> Achso, du verwendest jeweils "echte" Pointer. Bei mir ist das jeweils >> eine 8-Bit-Variable als Index. Erfordert dann natürlich noch etwas mehr >> Rechnerei. > > Ja, und zwar jedes mal wenn du schreibst/liest. Also jedesmal wenn du > das Array indizierst... Nicht so toll :-) Zwei einzelne Pointer finde > ich besser. Ich halte die L-Bytes der Pointer auch im SRAM, der H-Teil des gerade benötigten Pointers wird immidiate gesetzt, der Buffer reicht ja nicht über Pagegrenzen. Natürlich nutze ich zum Indizieren "echte Pointer", also die letzten Registerpaare des AVRs. Da diese auch noch andere Aufgaben haben, werden sie mit Push/Pop gesichert. ...
Hannes Lux wrote: >> Mit Busy-Wait >> rumhängen bis wieder Platz ist, ist natürlich auch eine Idee ;) > > Das schmeckt mir auch nicht, deshalb habe ich bei den LCD-Routinen bei > der alten Zünduhr auch darauf verzichtet. Der Buffer umfasst aber eine > ganze Page, da ist Überlauf mehr als unwahrscheinlich. Wenn es zum > Überlauf kommen kann, dann klemmt irgendwas Anderes im Programm. Dann > sollte man das Konzept überprüfen. ;-) > > Ich hatte auch bisher keine Anwendung, wo der AVR z.B. so schnell mit > UART-Daten zugeschüttet wird, dass ihm die Zeit fehlt, sie zu > verarbeiten. Kann aber noch kommen. Du wolltest die Firmware für die Drucker doch selbst schreiben, nicht wahr? ^^ Dort musste ich mir mit Flusskontrolle behelfen (Daher ist RTS auf dem Schema auch verbunden), um mit der Datenmenge zurechtzukommen, da die Druckvorgänge je nach "Pixeldichte" unterschiedlich lange dauern. > In einem Fall (die neue Zünduhr) schaufelt ein PC-Programm die Zünddaten > aus einer EXCEL-Datei per UART in den Mega8535 der Zünduhr, der sie dann > ins eigene EEP brennt. Da dies (durch das EEP-Brennen) länger dauert, > hält das PC-Programm Pausen zwischen den Datensätzen ein. Es kommt eben > darauf an, dass sich beide Kommunikationspartner verstehen, hohe > Datenübertragungsrate alleine ist eben nicht alles... > > ... Auch eine Idee. Hardware-Flusskontroller war keine Alternative? Simon Küppers wrote: > Philipp Burch wrote: >> Achso, du verwendest jeweils "echte" Pointer. Bei mir ist das jeweils >> eine 8-Bit-Variable als Index. Erfordert dann natürlich noch etwas mehr >> Rechnerei. > > Ja, und zwar jedes mal wenn du schreibst/liest. Also jedesmal wenn du > das Array indizierst... Nicht so toll :-) Zwei einzelne Pointer finde > ich besser. Ach, so tragisch ist das auch wieder nicht. Wenn etwas zeitkritisch ist, dann programmiere ich es in Assembler (Das ganze Prog) und optimiere auch dementsprechend. In C ist es mir aber lieber, ich kann ein Array über die Indizes ansprechen, anstatt an den Pointern rumzubasteln.
> Kann aber noch kommen. Das kommt mit Sicherheit. > Du wolltest die Firmware für die Drucker doch > selbst schreiben, nicht wahr? ^^ Jou... Spätestens dann kommt das. Trotzdem versuche ich im Vorfeld, solche Probleme zu vermeiden. Das ist aber nicht immer möglich (z.B. bei dem Drucker). > Dort musste ich mir mit Flusskontrolle behelfen (Daher ist RTS auf dem > Schema auch verbunden), um mit der Datenmenge zurechtzukommen, da die > Druckvorgänge je nach "Pixeldichte" unterschiedlich lange dauern. Prima Idee, werde ich dann vermutlich auch nutzen, hoffentlich klappt das auch noch hinter einem USB-SER-Adapter... ;-) > Auch eine Idee. Hardware-Flusskontroller war keine Alternative? In diesem Fall nicht, bei der ersten Version war kein Pin mehr frei, bei der aktuellen Version war es nicht nötig. Ich habe es sogar noch zusätzlich ausgebremst, damit man die Fortschrittsanzeige auch wahrnehmen kann. ;-) Und bei 512 Bytes Nutzdaten (allerdings HEX-codiert übertragen) interessiert das Tempo nicht wirklich... Als es noch schneller ging, war der Benutzer nie sicher, ob die Daten auch übertragen wurden. Nun sieht er anhand der Fortschrittsanzeige (xxx / 170), dass das System (explosive) Daten schaufelt. ...
Hannes Lux wrote: >> Dort musste ich mir mit Flusskontrolle behelfen (Daher ist RTS auf dem >> Schema auch verbunden), um mit der Datenmenge zurechtzukommen, da die >> Druckvorgänge je nach "Pixeldichte" unterschiedlich lange dauern. > > Prima Idee, werde ich dann vermutlich auch nutzen, hoffentlich klappt > das auch noch hinter einem USB-SER-Adapter... ;-) Tut es. Zumindest bei meinem (Prolific). >> Auch eine Idee. Hardware-Flusskontroller war keine Alternative? > > In diesem Fall nicht, bei der ersten Version war kein Pin mehr frei, bei > der aktuellen Version war es nicht nötig. Ich habe es sogar noch > zusätzlich ausgebremst, damit man die Fortschrittsanzeige auch > wahrnehmen kann. ;-) Und bei 512 Bytes Nutzdaten (allerdings HEX-codiert > übertragen) interessiert das Tempo nicht wirklich... Als es noch > schneller ging, war der Benutzer nie sicher, ob die Daten auch > übertragen wurden. Nun sieht er anhand der Fortschrittsanzeige (xxx / > 170), dass das System (explosive) Daten schaufelt. g 3... 2... 1... 0... BOOOM
> 3... > 2... > 1... > 0... > BOOOM Genau, und das mit bis zu 170 BOOOMs auf die Zehntelsekunde genau... Nur eben nicht beim Datentransfer, sondern später auf dem Abbrennplatz. ;-) ...
Wo liegt denn eigentlich genau euer Problem? Einen Überlauf beim FIFO mit einzelnem Read/Write Pointer herauszufinden? Man kann doch, bevor man das neue Byte reinschiebt, gucken ob die beiden Pointer direkt nebeneinander platziert sind. Sprich: Wenn ich jetzt den Write-Pointer inkrementiere, würden beide Zeiger "kollidieren". Zack: Funktion weiß: Überlauf ist passiert. Oder habe ich was verpasst? :-)
Simon Küppers wrote: > Wo liegt denn eigentlich genau euer Problem? Einen Überlauf beim FIFO > mit einzelnem Read/Write Pointer herauszufinden? > > Man kann doch, bevor man das neue Byte reinschiebt, gucken ob die > beiden Pointer direkt nebeneinander platziert sind. Sprich: Wenn ich > jetzt den Write-Pointer inkrementiere, würden beide Zeiger > "kollidieren". > > Zack: Funktion weiß: Überlauf ist passiert. > > Oder habe ich was verpasst? :-) Problem haben wir eigentlich gar keins, ich hab' nur etwas laut gedacht und ihr habt geantwortet ;) Wenn die Daten z.B. per RS232 reinkommen, dann ist das ja nicht so ein Problem, wenn das FIFO mal überläuft, dann kann ich die Daten einfach verwerfen, da sich der Datenstrom eh nicht einfach so unterbrechen lässt ("Wenn man mal ein Interrupt verpasst ist das ja nicht so schlimm, kommt ja bald wieder ein neuer" ;D ). In anderen Fällen wird aber ein FIFO auf Anforderung gefüllt und da hatte ich jeweils einfach keine gescheite Idee, wie FIFO_Push nun zurückliefern soll, dass der Puffer voll ist. Denn da ist es Voraussetzung, dass das gerade übergebene Byte in jedem Fall noch geschrieben wird, es muss also noch Platz sein. Daher habe ich mir dann angewöhnt, einfach den Füllstand jeweils noch zu aktualisieren, da ich damit zu jeder Zeit schauen kann, ob noch Platz ist und ob Daten zum Auslesen vorhanden sind. Aber egal, das geht hier langsam off-topic ;)
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.