Forum: Mikrocontroller und Digitale Elektronik ADC: Konvertierung sofort starten?


von ADC (Gast)


Lesenswert?

Hi,

im Quellcode von einigen AVR Projekten, die Gebrauch vom ADC machen, ist 
mir aufgefallen, dass das ADC im ersten Schritt "eingestellt" wird, und 
erst im zweiten die ersten Konvertierung beginnt.

Das sieht dann in etwa so aus:
1
ADCSRA = _BV(ADEN) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS0);
2
ADCSRA |= _BV(ADSC);

Inwiefern ist es denn möglich/sinnvoll bzw. nicht sinnvoll das zusammen 
zu fassen, sodass es ein paar Byte weniger Programmcode werden. Ich 
finde im Datenblatt jedenfalls nichts was dagegen spricht.

Aussehen würde das dann in etwa so:
1
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS0);

Vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

ADC schrieb:
> Hi,
>
> im Quellcode von einigen AVR Projekten, die Gebrauch vom ADC machen, ist
> mir aufgefallen, dass das ADC im ersten Schritt "eingestellt" wird, und
> erst im zweiten die ersten Konvertierung beginnt.
>
> Das sieht dann in etwa so aus:
>
>
1
> ADCSRA = _BV(ADEN) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS0);
2
> ADCSRA |= _BV(ADSC);
3
>
>
> Inwiefern ist es denn möglich/sinnvoll bzw. nicht sinnvoll das zusammen
> zu fassen, sodass es ein paar Byte weniger Programmcode werden.

Das ganze wird dann sinnvoll, wenn du bedenkst, dass diese 
Konfigurierung im Regelfall ja nur ein einziges Mal bei Programmstart 
gemacht wird und danach ja nur noch mittels ADSC jeweils die nächste 
Messung gestartet wird.

Allerdings zeigt sich auch immer wieder, dass dieses einfache Konzept
1
int main()
2
{
3
  Konfigurierung und Hardware initialisieren
4
  zb den ADC einschalten und die ADC Vorteiler einstellen
5
6
  sei();
7
8
  while( 1 ) {
9
10
    Programmlogik, zb eine ADC Wandlung starten
11
12
  }
13
}
des öfteren schon mal auf Verständnisprobleme bei so manchem 
Programmierer stösst.

> Ich
> finde im Datenblatt jedenfalls nichts was dagegen spricht.
>
> Aussehen würde das dann in etwa so:
>
>
1
> ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS0);
2
>

Ich würds trotzdem nicht tun.

von ADC (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Allerdings zeigt sich auch immer wieder, dass dieses einfache Konzept

Das habe ich schon verstanden. Bei mir geht es einzig und allein um die 
Initialisierung. Dort vollführe ich genau eine Wandlung und halte diese 
vor, sodass ggf. andere Module bereits darauf zugreifen können.

In einem Timer wird dann regelmäßig eine neue Messung durchgeführt und 
verarbeitet.

Karl Heinz Buchegger schrieb:
> Ich würds trotzdem nicht tun.

Wieso nicht? Damit spart man sich 10 Byte und einen echten Grund, 
welcher dagegen spricht, hast du nicht genannt :(.

Dennoch vielen Dank schon einmal ...

von Karl H. (kbuchegg)


Lesenswert?

ADC schrieb:

> Wieso nicht? Damit spart man sich 10 Byte

wie kommst du auf 10?
Das eine Bit im ADCSRA zu setzen dauert genau 1 Assembler-Befehl und 
damit 2 Byte Flash. Bei deeeen Flash-Größen ziemlich uninteressant.

> und einen echten Grund, welcher dagegen spricht, hast du nicht genannt
Ich bin eben ein Verfechter der alten Schule: zuerst konfigurieren und 
dann erst einschalten. Keine Experimente oder Race-Conditions. Hat sich 
für mich bewährt.

von ADC (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> wie kommst du auf 10?

Durch Ausprobieren ;).

Karl Heinz Buchegger schrieb:
> Das eine Bit im ADCSRA zu setzen dauert genau 1 Assembler-Befehl und
> damit 2 Byte Flash. Bei deeeen Flash-Größen ziemlich uninteressant.

Dann sag das meinem avr-gcc. Im "zusammengefassten" Teil generiert er 
mir Folgendes für das Setzen des Bits:
1
lds  r24, 0x007A
2
ori  r24, 0x40
3
sts  0x007A, r24

Laut Instruktionssatz sind das 10 Byte (4 + 2 + 4). So genau kenne ich 
den Instruktionssatz auch wieder nicht, aber "sbi" geht nur bei I/O 
Registern (Adressen 0 - 31). Und sobald ich den Inhalt des ADCSRA in ein 
Register kopieren muss, welches ich bearbeiten kann, komme ich um die 8 
Byte für das "lds" und "sts" nicht herum.

Ich würde fast davon ausgehen, dass der Compiler bei solchen einfachen 
Registeroperationen sein Bestes gibt und kann mir kaum vorstellen, dass 
es da noch Optimierungspotential gibt. Oder hast du hier eine Idee?

Karl Heinz Buchegger schrieb:
> Ich bin eben ein Verfechter der alten Schule: zuerst konfigurieren und
> dann erst einschalten. Keine Experimente oder Race-Conditions. Hat sich
> für mich bewährt.

Naja, das ist für mich zunächst einmal ziemlich subjektiv. Wenn es 
anders herum auch geht, und das Datenblatt einen nicht davon abhält, 
dann sehe ich nämlich keinen Grund das nicht so zu machen.

Vielen Dank!

von ADC (Gast)


Lesenswert?

Übrigens bezieht sich das o.g. Assembler Listing auf den Fall der nicht 
zusammengefassten Version. Konkret sind die o.g. Befehle für das Setzen 
des ADSC Bits im ADCSRA Register zuständig.

von Karl H. (kbuchegg)


Lesenswert?

ADC schrieb:

> Dann sag das meinem avr-gcc. Im "zusammengefassten" Teil generiert er
> mir Folgendes für das Setzen des Bits:
>
>
1
> lds  r24, 0x007A
2
> ori  r24, 0x40
3
> sts  0x007A, r24
4
>
>
> Laut Instruktionssatz sind das 10 Byte (4 + 2 + 4). So genau kenne ich
> den Instruktionssatz auch wieder nicht, aber "sbi" geht nur bei I/O
> Registern (Adressen 0 - 31). Und sobald ich den Inhalt des ADCSRA in ein
> Register kopieren muss, welches ich bearbeiten kann, komme ich um die 8
> Byte für das "lds" und "sts" nicht herum.

OK. erwischt.
Ich hab nicht bei allen Prozessoren nachgesehen, wo im Speicher das 
ADCSRA Register liegt und ob es mit einem sbi erreichbar ist. Bei einem 
Mega8 geht ein sbi.

von ADC (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ich hab nicht bei allen Prozessoren nachgesehen, wo im Speicher das
> ADCSRA Register liegt und ob es mit einem sbi erreichbar ist.

Gut, ich habe auch nicht erwähnt auf welchen Prozessor ich mich hier 
beziehe (ATmega168), wobei ich mir kaum vorstellen kann, dass es einen 
Controller in der AVR Familie gibt bei welchem das ADCSRA im I/O Bereich 
liegt. Wobei ich das jetzt auch nicht kontrolliert habe ;).

von Karl H. (kbuchegg)


Lesenswert?

ADC schrieb:
> Karl Heinz Buchegger schrieb:
>> Ich hab nicht bei allen Prozessoren nachgesehen, wo im Speicher das
>> ADCSRA Register liegt und ob es mit einem sbi erreichbar ist.
>
> Gut, ich habe auch nicht erwähnt auf welchen Prozessor ich mich hier
> beziehe (ATmega168), wobei ich mir kaum vorstellen kann, dass es einen
> Controller in der AVR Familie gibt bei welchem das ADCSRA im I/O Bereich
> liegt. Wobei ich das jetzt auch nicht kontrolliert habe ;)., der alte

Doch.
Der alte M8 hat es dort liegen, die kleineren Tinys, der Mega16 hat es 
per SBI erreichbar.

Also einigen wir uns: Bandbreite 2 bis 10 Bytes.

Sind bei zb 8K Flash immer noch keine Welten.

von Spess53 (Gast)


Lesenswert?

Hi

>Laut Instruktionssatz sind das 10 Byte (4 + 2 + 4)

Macht bei mir

LDS   2 bytes
ori   2 bytes
STS   2 bytes

oder 3 Befehle

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

ADC schrieb:


> Gut, ich habe auch nicht erwähnt auf welchen Prozessor ich mich hier
> beziehe (ATmega168), wobei ich mir kaum vorstellen kann, dass es einen
> Controller in der AVR Familie gibt bei welchem das ADCSRA im I/O Bereich
> liegt. Wobei ich das jetzt auch nicht kontrolliert habe ;).

Ich habs mir gerade beim M168 angesehen.
Das ist ja cool.
Die Hälfte der Adressen im I/O Register Bereich ist 'reserved', dafür 
drängelt sich alles in dem Bereich, der mittels Bit-Befehle nicht mehr 
erreichbar ist.
OK, Ich bin sicher dass Atmel dafür einen extrem guten Grund hat (den 
ausser dem Entwicklungsingenieur keiner kennt), aber so ganz einsichtig 
ist das für mich nicht.

von ADC (Gast)


Lesenswert?

Spess53 schrieb:
> Macht bei mir
>
> LDS   2 bytes
> ori   2 bytes
> STS   2 bytes
>
> oder 3 Befehle

Dann solltest du dir den Instruktionssatz nochmal genau ansehen ;). LDS 
und STS gibt es jeweils in zwei Versionen (2 und 4 Byte breit). Die 2 
Byte breite Version kann aber nur Bereiche zwischen 0x40..0xbf 
adressieren. Das bringt mir in meinem Fall aber nichts.

Wie gesagt: Ich wäre sehr erstaunt, wenn ein Compiler bei einfachen 
Registeroperationen nicht "optimal" arbeitet. Das ist ja verhältnismäßig 
einfach umzusetzen.

von ADC (Gast)


Lesenswert?

Um zur eigentlichen Frage zurück zu kommen: Gibt es noch andere 
Meinungen? Bzw. Meinungen von anderen Leuten ;). Einfach nur aus 
Interesse ...

10 Byte hin oder her - das soll jetzt nicht der entscheidende Faktor 
sein. Mir geht es eher allgemein ums Prinzip bzw. ob einen Probleme 
erwarten.

von spess53 (Gast)


Lesenswert?

Hi

>Dann solltest du dir den Instruktionssatz nochmal genau ansehen ;). LDS
>und STS gibt es jeweils in zwei Versionen (2 und 4 Byte breit).

Hast Recht. Da war ich beim 'falschen' lds gelandet.

Ansonsten halte ich das Ganze eher für eine akademische Frage. Bei 
Autotrigger braucht man, außer im Freerunning-Mode, überhaupt kein ADSC.

MfG Spess

von Uwe (de0508)


Lesenswert?

Guten Morgen,

ein wichtiger Grund den ADC nur einmalig zu aktivieren ist, dass der 
erste Messwert verworfen werden muss und auch etwas mehr Zeit für die 
Wandlung benötigt.

Somit müsste man bei einem Aus - Einschalten, mehr Zeit für die Erste 
Wandlung einplanen, das Ergebnis ADCW lesen und verwerfen und danach 
eine weitere Messung starten.
Erst jetzt wären die ADC Messwert 'glaubwürdig'.

Steht aber auch alles im Datenblatt.

von spess53 (Gast)


Lesenswert?

Hi

>Somit müsste man bei einem Aus - Einschalten, mehr Zeit für die Erste
>Wandlung einplanen, das Ergebnis ADCW lesen und verwerfen und danach
>eine weitere Messung starten.
>Erst jetzt wären die ADC Messwert 'glaubwürdig'.

Hast du das schon mal getestet?

Ich kann nämlich keine nennenswerten Abweichungen feststellen (AVR 
Dragon, ADC ATMega644P mit interner Refrenz 2,56V).

>Steht aber auch alles im Datenblatt.

Persönlich liest sich das für mich wie die 'Möglichen Nebenwirkungen' 
auf einem Beipackzettel.

MfG Spess

von Joerg S: (Gast)


Lesenswert?

Ein weiterer Grund wäre, dass ich mit dem Mux einen anderen Eingang 
auswählen möchte!? Dann ist es schon ganz praktisch, den Zeitpunkt der 
Wandlung "im Griff" zu haben.

Grüße,

Jörg

von Udo S. (urschmitt)


Lesenswert?

Joerg S: schrieb:
> Ein weiterer Grund wäre, dass ich mit dem Mux einen anderen Eingang
> auswählen möchte!? Dann ist es schon ganz praktisch, den Zeitpunkt der
> Wandlung "im Griff" zu haben.

Dann musst du auf jeden Fall die settling time berücksichtigen, die der 
MUX und der S/H braucht (abhängig vom Innenwiderstand der zu messenden 
Quelle) bis man überhaupt mit der Wandlung starten darf oder eben Mist 
misst.

Also immer besser der Karl Heinz Ansatz:
Im Zweifel jede Race condition vermeiden.
Kontrolliert eines nach dem anderen tun.

Sonst handelt man sich Probleme ein, die nicht reproduzierbar und fast 
nicht zu finden sind.

von amateur (Gast)


Lesenswert?

Für mich sind die eingebauten Wandler nichts als bessere Schätzeisen und 
sonst nichts.
In den meisten Anwendungen geht es aber gar nicht um absolute 
Genauigkeiten, sondern um eine Kombination aus Was und Wann, um sich 
dann mit der Änderung herumzuschlagen.
Unter diesen Bedingungen könnte ich mit einem Messwert, der "irgendwann" 
angefallen ist, sowieso nichts anfangen. So schön die Antwort vom 
A/D-Wandler: "Ja ich habe was für dich", auch im Programmablauf ist.

von Hannes L. (hannes)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die Hälfte der Adressen im I/O Register Bereich ist 'reserved', dafür
> drängelt sich alles in dem Bereich, der mittels Bit-Befehle nicht mehr
> erreichbar ist.

Ja, leider. Trotzdem verwende ich den ATMega48 recht gern, er hat doch 
ein paar nützliche Features mehr als der ATMega8. Und wenn es nur die 
ganz brauchbaren PWMs des 8-Bit-Timers sind.

Karl Heinz Buchegger schrieb:
> OK, Ich bin sicher dass Atmel dafür einen extrem guten Grund hat (den
> ausser dem Entwicklungsingenieur keiner kennt), aber so ganz einsichtig
> ist das für mich nicht.

Vermutlich will Atmel "Ordnung schaffen", also bei allen ATMegas 
einheitliche Adressen für denselben Zweck benutzen. Das bringt aber 
nichts, denn dann könnten sie aber auch gleich einen Einheits-AVR 
schaffen, den sie in unterschiedliche Gehäuse packen und ggf. bei 
kleineren Gehäusen I/O-Ports weglassen.

ADC schrieb:
> Gibt es noch andere
> Meinungen? Bzw. Meinungen von anderen Leuten ;). Einfach nur aus
> Interesse ...

Ja. Gibt es.
Wenn ich einzelne Bits in I/O-Registern schalten muss, die nicht mit 
SBI/CBI erreichbar sind, dann verwende ich auch gern mal vordefinierte 
Konstanten, die ich dann nur ausgeben brauch (LDI/Out oder LDI/STS). Das 
erspart dann das Read/Mofify/Write-Geraffel.

Und gerade beim ADC gibt es auch andere Strategien als "Starten, warten, 
auslesen".

...

von Hannes L. (hannes)


Lesenswert?

amateur schrieb:
> Für mich sind die eingebauten Wandler nichts als bessere Schätzeisen und
> sonst nichts.

Das dachte ich auch mal. Inzwischen sehe ich das anders. Das kommt aber 
natürlich auch auf die Ansprüche an. Andererseits erfordert ein 
"besserer" externer ADC auch ein entsprechend besser designtes Board, 
ansonsten misst der auch nur Mist.

...

von Dex (Gast)


Lesenswert?

Es kann ja sein dass ich mich irre, aber soweit ich mich erinnern kann 
benötigen ADC doch eine gewisse start-time. Das bedeutet er muss diese 
Zeit vor der ersten conversion warten.
müsste doch im Datenblatt stehen aber selbst habe ich es nicht 
überprüft.

von batman (Gast)


Lesenswert?

Ja, es steht drin.

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.