Forum: Mikrocontroller und Digitale Elektronik Optimiert der Compiler das eventuell weg?


von Ernst B. (puravida)


Lesenswert?

Hi!

Besteht die Gefahr, daß der Compiler mir da was wegoptimiert?
1
uint16_t ADC_On_ReadAvg_Off(uint8_t average)
2
{
3
  uint32_t result = 0;
4
  
5
  ADCSRA |= (1<<ADEN);
6
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
7
  while (ADCSRA & (1<<ADSC) ) {}        // auf Abschluss der Konvertierung warten
8
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
9
     Wandlung nicht übernommen. */
10
  result = ADCW;
11
  
12
  result = 0;
13
 
14
  for (uint8_t i = 0; i < average; ++i )
15
  {
16
    result += ADC_Read();
17
  }
18
  
19
  ADCSRA &= ~(1<<ADEN);
20
  
21
  return (uint16_t)( result / average );
22
}

Diese zwei Zeilen
1
result = ADCW;
2
result = 0;

machen mir Sorgen. Erkennt der Compiler, daß ich da einen Wert lese und 
gleich wieder 0 rein schreibe und liest dann vielleicht erst gar nicht?

Mal so grundsätzlich: in welchen Fällen muß man sich Sorgen machen?

LG
Ernst

von Yalu X. (yalu) (Moderator)


Lesenswert?

ADCW wird auf jeden Fall gelesen, da es im Headerfile wie alle IO-Regis-
ter als volatile deklariert ist. Wahrscheinlich wird der gelesene Wert
aber nicht in result geschrieben, was aber auch egal ist.

Da du den Inhalt von ADCW sowieso nicht weiterverwenden möchtest, kannst
du statt
1
  result = ADCW;

auch einfach schreiben:
1
  ADCW;

von Ernst B. (puravida)


Lesenswert?

Danke Dir Yalu!

Was passiert wenn ich nur ADCW; schreibe? Also, wie wird sowas 
interpretiert?

wenn ich in die iom8.h schaue dann steht dort:

#define ADCW  _SFR_IO16(0x04)

Nur werde ich aus dem _SFR_IO16(0x40) nicht schlau. Leider auch dann 
nicht wenn ich in die sfr_defs.h schaue:

#define _SFR_IO16(io_addr) ((io_addr) + __SFR_OFFSET)

Sh*t, ich brauche ein libc Tutorial oder sowas...

von Purzel H. (hacky)


Lesenswert?

Was spricht gegen den simulator ?

von Ernst B. (puravida)


Lesenswert?

Nano Oschi schrieb:
> Was spricht gegen den simulator ?

Ich weiß nicht wie ich im Studio Werte für den Pin simuliere? Oder muß 
ich das gar nicht wenn ich einen  ADC simuliere?

von Ulrich (Gast)


Lesenswert?

Für den ADC muss man die PIN nicht extra einstellen. Der analoge Teil 
des ADC wird, soweit ich das noch kenne gar nicht simuliert.

Es auch gar nicht mal nötig ADCW überhaupt zu lesen. Man kann auch eine 
neue Wandlung anfangen ohne den alten Wert zu lesen.

von Karl H. (kbuchegg)


Lesenswert?

Ernst B. schrieb:
> Danke Dir Yalu!
>
> Was passiert wenn ich nur ADCW; schreibe? Also, wie wird sowas
> interpretiert?

genauso wie wenn du einfach

    i;

anstelle von

    j = i;

schreibst.

Oder

    sin( x );

anstelle von

     y = sin( x );

Das ist ein arithmetischer Ausdruck, dessen Ergebnis verworfen wird. 
Meistens warnen Compiler bei so etwas.

>
> wenn ich in die iom8.h schaue dann steht dort:
>
> #define ADCW  _SFR_IO16(0x04)

Das ist relativ uninteressant. Für dich als C Programmierer 
repräsentiert ADCW das 16 Bit Register, aus dem du dir das ADC Ergebnis 
abholen kannst. Wenn du so willst: eine Variable die 'magisch' den 
aktuellen Wert des ADC enthält.

von Peter D. (peda)


Lesenswert?

Ernst B. schrieb:
> Was passiert wenn ich nur ADCW; schreibe? Also, wie wird sowas
> interpretiert?

Jeder Ausdruck hat in C einen Wert. Ein Ausdruck ist also implizit ein 
Lesezugriff.
Da der Wert aber nicht verwendet wird, könnte der Compiler ihn 
wegoptimieren.
Allerdings sind IO-Register volatile definiert, d.h. ein Lesen oder 
Schreiben erfolgt immer.


Peter

von Peter D. (peda)


Lesenswert?

Ernst B. schrieb:
> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
>      Wandlung nicht übernommen. */

Wie kommst Du denn darauf?


Peter

von Ernst B. (puravida)


Lesenswert?

Peter Dannegger schrieb:
> Ernst B. schrieb:
>> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
>>      Wandlung nicht übernommen. */
>
> Wie kommst Du denn darauf?
>
>
> Peter

Ich bilde mir ein das im Datenblatt gelesen zu haben. Aber jetzt finde 
ich es nimmer. Sondern nur, daß die erste Wandlung länger dauert.

Aber irgendwo habe ich es gelesen...

LG
Ernst

von Tom (Gast)


Lesenswert?

Ernst B. schrieb:
> Mal so grundsätzlich: in welchen Fällen muß man sich Sorgen machen?

Wenn im List-File kein Assembler-Code zu deinem C-Codeteil auftaucht, 
ist das ein sicheres Zeichen für wegoptimierten Code. Allerdings ist das 
dann auch kein Grund zur Sorge, sondern ein klarer Fall ;-)

von Ernst B. (puravida)


Lesenswert?

Peter Dannegger schrieb:
> Ernst B. schrieb:
>> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
>>      Wandlung nicht übernommen. */
>
> Wie kommst Du denn darauf?
>
>
> Peter

Ich weiß es schon, hier im AVR-GCC Tutorial steht es:

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Nutzung_des_ADC


Zitat: "...In der praktischen Anwendung wird man zum Programmstart den 
ADC erst einmal grundlegend konfigurieren und dann auf verschiedenen 
Kanälen messen. Diese beiden Dinge sollte man meist trennen, denn das 
Einschalten des ADC und vor allem der Referenzspannung dauert ein paar 
Dutzend Mikrosekunden. Außerdem ist das erste Ergebnis nach dem 
Einschalten ungültig und muss verworfen werden. ..."

LG
Ernst

von Ulrich (Gast)


Lesenswert?

Im Datenblatt zum AVR steht nirgends das man den ADC nach einer Wandlung 
auch auslesen muss, oder das das lesen den ADC irgendeinen Nebeneffekt 
wie das löschen eines Flags hat.

Gut es gibt ggf. schon einen kleinen Nebeneffekt, indem beim Lesen von 
ADCL der Wert von ADCH gepuffert wird. Danach wird dann der Puffer mit 
dem lesen von ADCH auch wieder freigegeben. Es ist also nichts weiter 
passiert, als das ggf. ein 16 Bit Zugriff woanders gestört wurde. 
Benötigt wird das hier nicht, außer es wurde vorher mal nur ADCL 
gelesen. Dann reich aber das lesen von ADCH aus.

Was man daher nicht machen sollte, ist es nur ADCL aber nicht ADCH lesen 
- dann ließt man danach noch mal den alten Wert.

von Rolf M. (rmagnus)


Lesenswert?

Ernst B. schrieb:
> Zitat: "...In der praktischen Anwendung wird man zum Programmstart den
> ADC erst einmal grundlegend konfigurieren und dann auf verschiedenen
> Kanälen messen. Diese beiden Dinge sollte man meist trennen, denn das
> Einschalten des ADC und vor allem der Referenzspannung dauert ein paar
> Dutzend Mikrosekunden. Außerdem ist das erste Ergebnis nach dem
> Einschalten ungültig und muss verworfen werden. ..."

Und wo steht da jetzt, daß man den Wert auslesen muß?

von PuraVida (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Ernst B. schrieb:
>> Zitat: "...In der praktischen Anwendung wird man zum Programmstart den
>> ADC erst einmal grundlegend konfigurieren und dann auf verschiedenen
>> Kanälen messen. Diese beiden Dinge sollte man meist trennen, denn das
>> Einschalten des ADC und vor allem der Referenzspannung dauert ein paar
>> Dutzend Mikrosekunden. Außerdem ist das erste Ergebnis nach dem
>> Einschalten ungültig und muss verworfen werden. ..."
>
> Und wo steht da jetzt, daß man den Wert auslesen muß?

Da:

>> Außerdem ist das erste Ergebnis nach dem
>> Einschalten ungültig und muss verworfen werden.

Die Formulierung "muss verworfen werden" verlangt ja nach einem aktiven 
tun. Und auch drunter im Code steht es:


/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */

Da steht explizit, daß man es auslesen muß.

LG
Ernst

von Peter D. (peda)


Lesenswert?

PuraVida schrieb:
>>> Außerdem ist das erste Ergebnis nach dem
>>> Einschalten ungültig und muss verworfen werden.
>
> Die Formulierung "muss verworfen werden" verlangt ja nach einem aktiven
> tun. Und auch drunter im Code steht es:
>
>
> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
>      Wandlung nicht übernommen. */
>
> Da steht explizit, daß man es auslesen muß.

Da irrt das Tutorial. Tutorials werden auch nur von Menschen 
geschrieben.
Sogar das Datenblatt enthält manchmal Fehler oder Unsinniges.

Der ADC hat keine FIFO, wie z.B. die UART. Eine neue Wandlung 
überschreibt daher einfach den Inhalt. Ein Auslesen hat keinerlei 
Effekt. Man kann auch beliebig oft den gleichen Wert auslesen, solange 
die nächste Wandlung nicht abgeschlossen ist.


Peter

von Rolf M. (rmagnus)


Lesenswert?

PuraVida schrieb:
>> Und wo steht da jetzt, daß man den Wert auslesen muß?
>
> Da:
>
>>> Außerdem ist das erste Ergebnis nach dem
>>> Einschalten ungültig und muss verworfen werden.
>
> Die Formulierung "muss verworfen werden" verlangt ja nach einem aktiven
> tun.

Verwerfen heist doch nur, daß man es nicht verwendet.

> Und auch drunter im Code steht es:
>
>
> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
>      Wandlung nicht übernommen. */
>
> Da steht explizit, daß man es auslesen muß.

Das ist allerdings recht explizit. Ich konnte aber im Datenblatt keinen 
Grund für diese Behauptung finden.

von PuraVida (Gast)


Lesenswert?

Hi Peter!

Ja, klar, können überall Fehler sein, wir sind ja nicht unfehlbar. Es 
war nur die Antwort auf die Fragen wo ich das gelesen habe.

Ist mir nur recht wenn man es nicht verwerfen muß. Jetzt muß ich mich 
nur noch schlau machen wie das mit der internen Spannungsreferenz ist.

Da steht einerseits im Datenblatt:

The first ADC conversion result after switching reference voltage source 
may be inaccurate, and the user is advised to discard this result.

Fragt sich ob das auch gilt nach der Initialisierung des ADC also die 
erstmalige Einstellung von AVCC als eine Art "switching the reference" 
zu sehen ist. Ein- und Ausschalten des ADC wird da ja nicht drunter 
fallen, oder?

Und dann muß ich nochmal schauen wie ich das mit der Start-Up-Time von 
V-Bandgap mache die bis zu 70µs dauert. Da ist der gepostete Code sicher 
zu schnell wenn ich das Verwerfen der ersten Messung rauswerfe.

LG
Ernst

von MWS (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Verwerfen heist doch nur, daß man es nicht verwendet.

Korrekt verworfen ist es erst, wenn das Ergebnis in's Dev/Null-Register 
des µC geschoben wurde. :D

von Peter D. (peda)


Lesenswert?

Den ADC-Init-Kram kann man doch einfach noch vor die anderen 
Initialisierungen machen, also Referenz setzen und ne Dummy-Messung 
starten.
Dann z.B. das LCD initialisieren, wo 15ms gewartet werden muß und dann 
sollte sich alles eingeschwungen haben.


Peter

von spess53 (Gast)


Lesenswert?

Hi

Diese Dummymessung wird hier total überbewertet. Soll sich doch mal 
jeder selbst beantworten ob eine etwas ungenauere Messung in seinem 
Programm überhaupt eine Auswirkung hat. Wesentlich sinnvoller ist in den 
meisten Fällen eine Mittelwertbildung.

MfG Spess

von Peter D. (peda)


Lesenswert?

spess53 schrieb:
> Diese Dummymessung wird hier total überbewertet.

Das stimmt.

Wenn man sich mal kommerzielle Geräte anschaut, gibt es auch viele, wo 
die Anzeigen beim Einschalten erstmal Unsinn anzeigen. Und früher sind 
die Zeigerinsrumente auch gerne mal kurz auf Anschlag gesprungen. Keinen 
stört sowas.

Und was nützt es, wenn zwar der ADC richtige mißt, aber der OPV davor 
übersteuert und erst noch langsam seinen Arbeitspunkt finden muß.


Beim Einschalten zeigt man "Busy" an, solange die Meßwerte außerhalb des 
Arbeitsbereiches liegen.
Und erst, wenn sie nach einer Wartezeit immer noch falsch sind, zeigt 
man "Fault" an.


Peter

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.