Hallo zusammen, ich habe heute einige Zeit mit dem ATmega168 verbracht, da ich eine kleine Messung durchführen will. Der uC soll einen Puls mit einstellbarer Länge Ausgeben (dies habe ich über Timer1 / Output Compare A geregelt). Der Puls wird auf dem OC1A Pin ausgegeben. Nun möchte ich möglichst kurz vor dem Ende des Pulses ein Signal messen (per ADC). Dazu habe ich mich dem Output Compare B bedient. Der OCR1B Wert ist entsprechend etwas kleiner als der OCR1A Wert. Die Interruptroutine startet dann die ADC Conversion. Das funktioniert soweit, dauer aber etliche mikrosekunden. Zur Kontrolle habe ich OC1B auf PB2 ausgegeben und in der ISR nach dem ADC Conversion Start kurz PB0 angehoben, dabei gibt sich ein deutlicher Versatz zwischen der falling edge auf PB2 und der risig edge auf PB0 den ich auf den ISR Overhead schiebe. Nun habe ich im Datenblatt gelsen, dass ich den ADC auch direkt über Timer 1 / Output Compare B starten kann. Ich hab das so verstanden, dass das "conversion start" signal direkt zum ADC Block geroutet wird und nicht den Umweg über den Prozessor nimmt, also deutlich flinker sein sollte. Ist das so richtig? Dies umzusetzen ist mir aber nicht gelungen, der ADC wurde einfach nicht getriggert. Hat hierzu jemand vielleicht ein kleines Beispiel? Meinen aktuellen Code habe ich mal angehängt, vielleicht hat ja noch jemand einen hinweis wie man das ganze noch besser umsetzen kann. Hier nochmal das Timing so wie ich mir das vorstelle: (Die Linie stellt den Ausgabepuls an PB1 da. |-------------------------| | | ----- x ---------- t_on t_mess t_off Am Punkt x möchte ich Messen und die Zeit zwischen t_mess und t_off muss möglichst klein sein. Momentan mache ich den ganzen Puls recht lang und lege t_mess weit nach vorne, was aber auch suboptimal ist, weil ich den Puls an sich auch recht kurz halten möchte. Vielen Dank schonmal für Eure Antworten Christian
Starte den ADC doch im "Dauerfeuer"-Modus, das er durchgehend konvertiert. Dann nimmst du kurz vor Ende deiner Zeitspanne einfach das letzte Ergebnis aus dem ADC-Register
Dann zeig doch mal den Code für das Triggern. Der angehängte ist ja der alte Versuch. Eines zum Autotriggern: Der ADC wird nicht mit dem blossen Erreichen des Compare Match getriggert, sondern mit Eintritt in die zugehörige ISR. Die kann auch komplett leer sein.
1 | EMPTY_INTERRUPT(TIMER1_COMPB_vect); |
Aber da sein muss sie. mfg.
:
Bearbeitet durch User
Hmm darin könnte mein Verständnisproblem liegen, ich hatte angenommen ohne die ISR auszukommen. Werde das nochmal mit der leeren ISR ausprobieren und dann berichten.
Thomas Eckmann schrieb: > Eines zum Autotriggern: Der ADC wird nicht mit dem blossen Erreichen des > Compare Match getriggert, sondern mit Eintritt in die zugehörige ISR. Das ist Unsinn. Das Setzen des entsprechenden Interruptflags genügt zum Auslösen der Triggerfunktion vollständig. Das Problem ist, daß es irgendwer zurücksetzen muß, damit es erneut Triggern kann. Sonst funktioniert die Sache nämlich nur genau ein Mal. > Die kann auch komplett leer sein. >
1 | >
|
2 | > EMPTY_INTERRUPT(TIMER1_COMPB_vect); |
3 | >
|
4 | >
|
> Aber da sein muss sie.
Nein, muß sie nicht.
Zwar erfüllt der ausgelöste Interrupt durchaus die Aufgabe, das
Triggerflag zurückzusetzen, aber ansonsten ist er vor allem eins:
sinnlose Verschwendung von Rechenzeit. Denn die ISR ist natürlich nicht
wirklich "leer".
Tatsächlich verbrät das Konstrukt mindestens 10 Takte. Das allein wäre
vielleicht noch nicht so schlimm, aber es sind 10 Takte exclusiv, was
ganz automatisch für alle gleich und niedriger priorisierten ISRs mal
eben 10 Extratakte variabler Latenz einführt. Sowas kann durchaus über
Funktion oder Nichtfunktion entscheiden.
Ach diese C-ler, die lernen's nie...
Der sinnvollere Weg ist natürlich i.d.R., das Triggerflag im zum Abholen
des Ergebnisses ohnehin nötigen ADC-Interrupt mit zurück zu setzen.
Oder, wenn C-üblich gepollt wird, es in dem Moment zu tun, wenn das
Ergebnis der ADC gepollt wird. Das kostet nämlich im schlimmsten Fall
nur zwei Takte. Also Faktor 5 gespart.
c-hater (Hofnarr) schrieb: > Thomas Eckmann schrieb: > >> Eines zum Autotriggern: Der ADC wird nicht mit dem blossen Erreichen des >> Compare Match getriggert, sondern mit Eintritt in die zugehörige ISR. > > Das ist Unsinn. > > Das Setzen des entsprechenden Interruptflags genügt zum Auslösen der > Triggerfunktion vollständig. Das ist richtig. Allerdings lieferst du die Erklärung dafür, daß man die ISR trotzdem braucht, gleich hinterher. > Das Problem ist, daß es irgendwer zurücksetzen muß, damit es _erneut_ > Triggern kann. Sonst funktioniert die Sache nämlich nur genau ein Mal. > >> Die kann auch komplett leer sein. >>
1 | >>
|
2 | >> EMPTY_INTERRUPT(TIMER1_COMPB_vect); |
3 | >>
|
4 | >>
|
>> Aber da sein muss sie. > > Nein, muß sie nicht. Sollte sie aber. > Zwar erfüllt der ausgelöste Interrupt durchaus die Aufgabe, das > Triggerflag zurückzusetzen, aber ansonsten ist er vor allem eins: > sinnlose Verschwendung von Rechenzeit. Denn die ISR ist natürlich nicht > wirklich "leer". > Tatsächlich verbrät das Konstrukt mindestens 10 Takte. Das allein wäre > vielleicht noch nicht so schlimm, aber es sind 10 Takte exclusiv, was > ganz automatisch für alle gleich und niedriger priorisierten ISRs mal > eben 10 Extratakte variabler Latenz einführt. Sowas kann durchaus über > Funktion oder Nichtfunktion entscheiden. > 10 Takte. Da können sich auch nur verbohrte Assemblerfriggler mit ihrem von jeglicher Optimierung befreiten ineffektivem Code dran aufgeilen. > Ach diese C-ler, die lernen's nie... > > Der sinnvollere Weg ist natürlich i.d.R., das Triggerflag im zum Abholen > des Ergebnisses ohnehin nötigen ADC-Interrupt mit zurück zu setzen. Wieso ist die denn nötig? Da gibt es doch einen viel eleganteren Weg. Womit die paar Takte für die Timer-ISR auch gleich ausgeglichen werden. Oder gibt es die ADC_ISR umsonst? > Oder, wenn C-üblich gepollt wird, es in dem Moment zu tun, wenn das > Ergebnis der ADC gepollt wird. Das kostet nämlich im schlimmsten Fall > nur zwei Takte. Also Faktor 5 gespart. mfg.
Thomas Eckmann schrieb: > 10 Takte. Da können sich auch nur verbohrte Assemblerfriggler mit ihrem > von jeglicher Optimierung befreiten ineffektivem Code dran aufgeilen. Mit diesem Argument braucht ein Arduino Due etliche µs zum einfachen Setzen eines Portbits, was ohne den ganzen Arduino-Schnick-Schnack-Rechenleistung-ist-verfügbar in unter 0,1 µs erledigt ist.
Thomas Eckmann schrieb: > 10 Takte. Da können sich auch nur verbohrte Assemblerfriggler mit ihrem > von jeglicher Optimierung befreiten ineffektivem Code dran aufgeilen. Oooch, ist das niedlich... Wie das Gebrüll eine Kleinkinds, dem man den geliebten Schnuller wegnimmt... > Wieso ist die denn nötig? Da gibt es doch einen viel eleganteren Weg. > Womit die paar Takte für die Timer-ISR auch gleich ausgeglichen werden. > Oder gibt es die ADC_ISR umsonst? Nein, natürlich nicht. Aber: 1) Sie ist niedriger priorisiert. Dementsprechend sind die Auswirkungen des zusätzlichen Lags geringer. Denn die "zwingende" Erhöhung der variablen Latenz betrifft eben nur gleich oder niedriger priorisierte ISRs. 2) Du zitierst es selber: >> Oder, wenn C-üblich gepollt wird, es in dem Moment zu tun, wenn das >> Ergebnis der ADC gepollt wird. Das kostet nämlich im schlimmsten Fall >> nur zwei Takte. Also Faktor 5 gespart. Dieser Faktor FÜNF gilt in beiden Fällen, also sowohl für die Verwendung des ADC-Int als auch für die Polling-Variante. Zusammenfassend gilt: 1) Nur das konkrete Gesamtsystem kann entscheiden, ob es sinnvoll ist, den ADC-Int zu verwenden oder besser zu pollen. 2) Eine leere ISR allein zum Zurücksetzen des Triggerflags ist immer Schwachsinn. Ganz egal, ob der ADC-Int verwendet wird oder nicht, denn in beiden Fällen ist so eine leere Timer-ISR eine zusätzliche (und deshalb sinnlose) Last. Anders sieht das natürlich aus, wenn in der Timer-ISR sowieso noch etwas anderes gemacht werden soll. Dann könnte man jeglichen zusätzlichen Aufwand zum Zurücksetzen des Flags sparen. Aber genau dann ist sie eben gerade NICHT LEER! Das ist der Punkt.
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.