Forum: Mikrocontroller und Digitale Elektronik sigma delta dac in c


von chris (Gast)


Lesenswert?

Im Moment beschäftige ich mich gerade mit den Prinzipien der Sigma-Delta 
AD-Wandlung.

Um das mal praktisch auszuprobieren, habe ich einen Sinus Genrator 
programmiert:

http://hobby-roboter.de/forum/viewtopic.php?f=5&t=141

Man muss nur eine RC-Tiepass an den LED-Ausgang des Arduino anschließen 
und dann das Signal auf einen Lautsprecher geben.

von chris (Gast)


Lesenswert?

Erstaunlich fand ich, wie wenig Codezeilen für eine Sigma Delta Dac 
benötigt werden.
1
// sigma delta DAC, hold the DAC value for n-steps constant
2
for(n=0;n<50;n++)
3
{
4
   integrator+=sollwert-oldValue;
5
   if(integrator>0)
6
   {
7
      oldValue=MAXVALUE;
8
      digitalWrite(13, HIGH);   // set the LED on
9
   }
10
   else
11
   {
12
      oldValue=0;
13
      digitalWrite(13, LOW);    // set the LED off
14
   }
15
}

Durch die Arduino digitalWrite Funktionen wird die Hauptschleife 
allerdings etwas langsam. Der DAC läuft in etwa mit 100kHz, sodass eine 
Schleife mit 50 Durchläufen in meinem Beipiel mit dem Sinus eine 
effektive Abtastfrequenz von 100kHz/50=2kHz ergibt. Bin gepsannt, wie 
schnell das Ganze wird, wenn die Funktionen durch direkte Portzugriffe 
ersetzt werden.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mit GCC 4.2.4 oder 4.3.6 dauert ein Schleifendurchlauf 14 Taktzyklen.
Bei 20 MHz Taktfrequenz entspricht das 1,43 MHz, die Abtastrate ist 28,6
kHz. Neuere GCCs sind aber teilweise mehr als Faktor 2 langsamer. Ein
schon etwas älterer Snapshot von 4.8.0 braucht für jeden Schleifendurch-
lauf 36,5 Taktzyklen. Möglicherweise ist die Release-Version besser, ich
habe sie allerdings noch nicht getestet.

von chris (Gast)


Lesenswert?

>Bei 20 MHz Taktfrequenz entspricht das 1,43 MHz

Das klingt gut. Auf dem Arduino mit 16MHz und digitalWrite waren es nur 
so um die 100kHz. Faktor 10 bringt da qualitativ viel. Stellt sich nur 
die Frage, mit welcher Optimierung komiliert?

von Yalu X. (yalu) (Moderator)


Lesenswert?

chris schrieb:
> Stellt sich nur die Frage, mit welcher Optimierung komiliert?

Ach so, das habe ich ganz vergessen zuschreiben: Die angegebenen
Ergebnisse gelten für die Optimierung mit -O2. Bei -Os wird der Code
etwas langsamer und etwas kleiner. Die Unterschiede liegen in der
Größenordnung von 10%, sind also nicht so riesig.

Was tut eigentlich diese digitalWrite-Funktion alles, dass sie so extrem
langsam wird? Klar, sie muss die Pin-Nummer in ein I/O-Register und eine
Bitmaske umsetzen, dazu sind sicher ein paar Lookups und/oder Shifts
erforderlich, aber dass das Ganze gleich sooo lange dauert?

von chris (Gast)


Angehängte Dateien:

Lesenswert?

>Was tut eigentlich diese digitalWrite-Funktion alles, dass sie so extrem
>langsam wird?
Das weis ich leider auch nicht. Die Routine ist wohl in C++ geschrieben.

Ich habe noch mal ein wenig experimentiert. Mit dem direkten Zugriff auf 
PORTD komme ich auf 500kHz Abtastfrequenz.
Es war auch eine hochfrequente Störung auf dem Signal. Diese verschwand 
interessanterweise, als ich die Variablendefinitionen in die loop 
gesetzt habe ( vorher waren sie global )
1
void loop() {
2
  uint16_t phaseDelta=1070;
3
  int16_t integrator=0;
4
  uint8_t sollwert=64;
5
  uint8_t oldValue=0;
6
  uint16_t phase=0;
7
  cli();
8
  while(1)
9
  {
10
    // sin wave DDS ( direct digital synthesis )
11
    sollwert=128+sintab[phase>>8];
12
    phase+=phaseDelta;
13
    //phaseDelta++;
14
  
15
    // sigma delta DAC, hold the DAC value for n-steps constant
16
    DDRD|=(1<<2); // set pin as output
17
    for(n=0;n<25;n++)
18
    {
19
      integrator+=sollwert-oldValue;
20
      if(integrator>0) 
21
      {
22
        oldValue=MAXVALUE;
23
        PORTD|=(1<<2); // set pin high
24
      }
25
      else 
26
      {
27
        oldValue=0;
28
        PORTD&=~(1<<2); // set pin low
29
      }
30
    }
31
    DDRD&=~(1<<2); // set pin into high impedance state
32
    PORTD&=~(1<<2); // turn off pull up
33
  }
34
}
Den Sinus habe ich mit dem Mikrofon aufgenommen. Deshalb die 
tieffrequenten Schwingungen ( die man aber nicht hört )

von chris (Gast)


Angehängte Dateien:

Lesenswert?

Hier das Spektrum des direkt mit dem Line-In augenommenen Signals.

von chris (Gast)


Lesenswert?

Man sieht die für einen Sigma-Delta Wandler typische Verlagerung des 
Rauschens zu hohen Freunzen.
Die harmonischen im unteren Frequenzbereich hätte ich in dieser Stärke 
nicht erwartet. Das könnte aber mit der geringen Auflösung des Sinus ( 8 
Bit ) zusammenhängen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

chris schrieb:
> Diese verschwand
> interessanterweise, als ich die Variablendefinitionen in die loop
> gesetzt habe ( vorher waren sie global )

Die alten GCCs (4.2.4 und 4.3.6) haben netterweise selber die Inhalte
der globalen in lokale Variablen (d.h. Register) kopiert, weswegen die
innere Schleife auch so schnell lief. Bei den neueren Versionen muss
der Programmierer etwas nachhelfen, so wie du es getan hast.

>     DDRD&=~(1<<2); // set pin into high impedance state
>     PORTD&=~(1<<2); // turn off pull up

Warum denn das? Das gibt doch nur zusätzliches Rauschen und kostet
Zyklen?

von chris (Gast)


Lesenswert?

>Warum denn das? Das gibt doch nur zusätzliches Rauschen und kostet
>Zyklen?

Du hast recht, es kostet Zyklen. Allerdings gibt es am Ende der 
For-Schleife eine zeitliche Verzögerung. In der Zeit, in der dann der 
Sinuswert aktualisiert wird, bleibt der Ausgang auf dem letzten Wert. 
Ist dieser Wert High, wird der Kondensator des RC-Tiefpass am Ausgang ( 
bie mir 470Ohm, 100nF ) zu stark aufgeladen. Ist der Wert Low wird der 
Kondensator zu stark entladen. Wenn man den Ausgan hochohmig schaltet, 
hält der Kondensator den Wert ( zumindest wenn die Senke hochohmig genug 
ist ).

Mein Eindruck war, dass der Sinus mit dem "hochohmig Schalten" sauberer 
klingt.

von Alexxx (Gast)


Lesenswert?

Ein Sigma-Delta ADC mit weniger als 50dB SNR - Genial.

von Jonas B. (jibi)


Lesenswert?

ADC != DAC - Genial.

gruß Jonas

von chris (Gast)


Lesenswert?

>Ein Sigma-Delta ADC mit weniger als 50dB SNR - Genial.

Das SNR des DAC hängt vom Glättungsfilter ab. Dieser besteht momentan 
aus einem RC-Glied ( 470 Ohm, 100nF ). Durch einen zweiten 
nachgeschaltetn RC-Tiefpass ( 4700Ohm, 10nF ) sollte sich das SNR 
deutlich verbessern.

von Peter D. (peda)


Lesenswert?


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.