Forum: Mikrocontroller und Digitale Elektronik Zeitlich genaues Sampling mit dem ATmega168


von Christian (Gast)


Angehängte Dateien:

Lesenswert?

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

von Chris L. (kingkernel)


Lesenswert?

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

von Thomas E. (thomase)


Lesenswert?

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
von Christian (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Thomas E. (thomase)


Lesenswert?

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.

von Optimierer (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.