Forum: Mikrocontroller und Digitale Elektronik ADC benötigt sehr viele Takte


von nordman (Gast)


Lesenswert?

Moin Moin,

ich habe heute versucht bei meinem Atmega88 das ADC in Betrieb zu 
nehmen. Dazu kommt das Signal an Port PC5 an. Als Takt habe ich 20MHZ 
gewählt. Ich benötige allerdings nicht jeden Messwert, den der Atmega 
produziert, sondern nur einmal jeden 7. 61. und 446. Dazu habe ich 
folgende Funktion geschrieben:
1
void capture_wave(int8_t *low, int8_t *mid, int8_t *high) {
2
  
3
  int8_t temp;
4
  uint16_t count = 3122;
5
  
6
  ADMUX = _BV(REFS0)|_BV(ADLAR)|_BV(MUX2)|_BV(MUX0);        // channel
7
  ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADATE)|_BV(ADIF)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
8
    
9
  do {
10
    while(bit_is_clear(ADCSRA, ADIF));
11
    temp = ADCH - 128;
12
    ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADATE)|_BV(ADIF)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
13
        
14
    if (count == 0 || count == 8 || count == 16 || count == 24 || count == 32 || count == 40 || count == 48 || count == 56)
15
    {
16
      *high++ = temp;
17
    }
18
    if (count == 0 || count == 61 || count == 122 || count == 183 || count == 244 || count == 305 || count == 366 || count == 427)
19
    {
20
      *mid++ = temp;
21
    }
22
    if (count == 0 || count == 446 || count == 892 || count == 1338 || count == 1784 || count == 2230 || count == 2676 || count == 3122)
23
    {
24
      *low++ = temp;
25
    }
26
  
27
  } while(--count);
28
29
  ADCSRA = 0;
30
}

Nun wollte ich wissen wie lange es dauert den Code auszuführen. Der 
Simulator im Atmel Studio hat mir dazu 259.755,25 µs ausgegeben. Da ich 
allerdings eher mit einer Zeit von 19.981 µs gerechnet habe 
(1/(20MHZ/128)*3122=19.981 µs), habe ich noch einen schlankeren 
Algorithmus geschrieben:
1
count = 3122;
2
do {
3
    while(bit_is_clear(ADCSRA, ADIF));
4
    temp = ADCH - 128;
5
    ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADATE)|_BV(ADIF)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
6
    } while(--count);

Dieser benötigt auch 259.831,55 µs.

Meine Frage ist, habe ich einen Fehler gemacht oder ist das Studio nur 
nicht in der Lage die Laufzeit ordentlich anzugeben?

Vielen Dank für die Antworten.

von Karl H. (kbuchegg)


Lesenswert?

Hast du im SImulator auch die Taktfrequenz korrekt eingegeben?

von Falk B. (falk)


Lesenswert?

@nordman (Gast)

>ich habe heute versucht bei meinem Atmega88 das ADC in Betrieb zu
>nehmen. Dazu kommt das Signal an Port PC5 an. Als Takt habe ich 20MHZ
>gewählt.

Der Takt ist der CPU bzw. SYSTEMTakt. Dieser wird nochmal per Prescaler 
geteilt auf den ADC-Takt.
Von diesem Takt benötigt der ADC 13 Takte, um eine Wandlung auszuführen.

> Ich benötige allerdings nicht jeden Messwert, den der Atmega
>produziert, sondern nur einmal jeden 7. 61. und 446.

Warum auch immer.

>Simulator im Atmel Studio hat mir dazu 259.755,25 µs ausgegeben. Da ich
>allerdings eher mit einer Zeit von 19.981 µs gerechnet habe
>(1/(20MHZ/128)*3122=19.981 µs), habe ich noch einen schlankeren
>Algorithmus geschrieben:

Hast du im Simulator 20 MHz CPU-Takt eingestellt?

>Meine Frage ist, habe ich einen Fehler gemacht

Wahrscheinlich.

>oder ist das Studio nur
>nicht in der Lage die Laufzeit ordentlich anzugeben?

Doch.

Kleiner Tipp. Man sollte den ADC nach dem Auslesen des Ergebnisses 
sofort wieder starten, damit läuft die AD-Wandlung und die Auswertung 
des Ergebnisses parallel.

von Südseeinsulaner (Gast)


Lesenswert?

nordman schrieb:
> Ich benötige allerdings nicht jeden Messwert, den der Atmega
> produziert, sondern nur einmal jeden 7. 61. und 446.

> Meine Frage ist, habe ich einen Fehler gemacht

Warum läßt du den ADC überhaupt wandeln, wenn dich die Werte nicht 
interessieren?

Da würde man doch eher per Timer-Interrupt oder sonstwie gesteuert zu 
den passenden Momenten eine Wandlung anstoßen und gut.

von Rolf M. (rmagnus)


Lesenswert?

Falk B. schrieb:
> Kleiner Tipp. Man sollte den ADC nach dem Auslesen des Ergebnisses
> sofort wieder starten, damit läuft die AD-Wandlung und die Auswertung
> des Ergebnisses parallel.

Allerdings ist dann auch der gesamplete Wert um eine Wandlung 
verschoben.

von M. K. (sylaina)


Lesenswert?

Rolf M. schrieb:
> Allerdings ist dann auch der gesamplete Wert um eine Wandlung
> verschoben.

Womit wir wieder zur Timer-gesteuerten Wandlung kommen. Nur jeder 7., 61 
und 446. Wert schreit ja gradezu danach.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Allerdings ist dann auch der gesamplete Wert um eine Wandlung
> verschoben.
Wenn man das weiß, dann kommt das nicht überraschend und man kann damit 
rechnen...

von Peter D. (peda)


Lesenswert?

nordman schrieb:
> 259.755,25 µs ausgegeben. Da ich
> allerdings eher mit einer Zeit von 19.981 µs gerechnet habe
> (1/(20MHZ/128)*3122=19.981 µs)

Paßt doch perfekt:
260ms / 13 = 20ms.
Der ADC braucht 13 Takte zum Wandeln.

von nordman (Gast)


Lesenswert?

Peter D. schrieb:
> Paßt doch perfekt:
> 260ms / 13 = 20ms.
> Der ADC braucht 13 Takte zum Wandeln.

Gibt es eine Möglichkeit die Wandelung zu beschleunigen, so dass die 
Wandelung etwa 13ms braucht.

Südseeinsulaner schrieb:
> Warum läßt du den ADC überhaupt wandeln, wenn dich die Werte nicht
> interessieren?
>
> Da würde man doch eher per Timer-Interrupt oder sonstwie gesteuert zu
> den passenden Momenten eine Wandlung anstoßen und gut.

Das war nur mein erster Entwurf. Ich wusste nicht, wie ich das anders 
löse. Der µC kann während eigentlich eh nichts nützliches tun. Wie kann 
ich denn die Messung per Interrupt steuern?

von Falk B. (falk)


Lesenswert?

@ nordman (Gast)

>> Der ADC braucht 13 Takte zum Wandeln.

>Gibt es eine Möglichkeit die Wandelung zu beschleunigen, so dass die
>Wandelung etwa 13ms braucht.

Mit der passenden Einstellung des Prescalers.

>> Da würde man doch eher per Timer-Interrupt oder sonstwie gesteuert zu
>> den passenden Momenten eine Wandlung anstoßen und gut.

>Das war nur mein erster Entwurf. Ich wusste nicht, wie ich das anders
>löse. Der µC kann während eigentlich eh nichts nützliches tun.

Dann lass es so.

> Wie kann ich denn die Messung per Interrupt steuern?

Mit dem Free running mode zu ADC-interrupt. Siehe Interrupt.

von Walter S. (avatar)


Lesenswert?

nordman schrieb:
> sondern nur einmal jeden 7. 61. und 446.

darf man erfahren was das werden soll?

von nordman (Gast)


Lesenswert?

Walter S. schrieb:
> nordman schrieb:
>> sondern nur einmal jeden 7. 61. und 446.
>
> darf man erfahren was das werden soll?

Das sind Daten für eine FFT. Ich transformiere 3 Mal. Dadurch spart man 
sich eine Menge Stützstellen und man kann trotzdem die Frequenzen von 
60-20000 hz nachweisen.

von Karl M. (Gast)


Lesenswert?

Hallo nordman,

hast Du auch die mathematische Herleitung für dein Vorhaben parat ?

Würde mich mal interessieren, wie das geht.

von Walter S. (avatar)


Lesenswert?

nordman schrieb:
> Da ich
> allerdings eher mit einer Zeit von 19.981 µs gerechnet habe
> (1/(20MHZ/128)*3122=19.981 µs), habe ich noch einen schlankeren
> Algorithmus geschrieben:

ich weiß nicht was du da rechnest (3122??), bei mir rechnet sich das so:

20MHz durch den Teiler 128 macht 156 kHz für den ADC,
der braucht mind. 13 Takte also Abtastrate max. 12kHz
das reicht also nicht dafür

nordman schrieb:
> Das sind Daten für eine FFT. Ich transformiere 3 Mal. Dadurch spart man
> sich eine Menge Stützstellen und man kann trotzdem die Frequenzen von
> 60-20000 hz nachweisen.

Aber du kannst natürlich einen anderen Teiler als 128 einstellen (auf 
Kosten der Genauigkeit)

von Bastler (Gast)


Lesenswert?

nordman schrieb:
> Das sind Daten für eine FFT. Ich transformiere 3 Mal. Dadurch spart man
> sich eine Menge Stützstellen und man kann trotzdem die Frequenzen von
> 60-20000 hz nachweisen.

Wie genau transformierst Du 3 mal?
Hört sich, sagen wir mal, ungewöhnlich an.

von M. K. (sylaina)


Lesenswert?

nordman schrieb:
> Gibt es eine Möglichkeit die Wandelung zu beschleunigen, so dass die
> Wandelung etwa 13ms braucht.

ADC-Takt anpassen hilft. Stellst du den z.B. auf 100 kHz ein brauchst du 
für eine Wandlung im Freerunning-Mode nur noch 130 µs (erste Wandlung 
nicht berücksichtigt).

nordman schrieb:
> Das sind Daten für eine FFT. Ich transformiere 3 Mal. Dadurch spart man
> sich eine Menge Stützstellen und man kann trotzdem die Frequenzen von
> 60-20000 hz nachweisen.

Kannst du da mal genauer erläutern was du da machst? Das könnte 
interessant sein. Ich selbst mache auch zur Zeit eine FFT mit dem 
Atmega. Bei mir gehts dabei um Detektion von Schwingungen bis 50 kHz. Da 
mir 8 bit am ADC dabei genügen kann ich problemlos den ADC mit 1.5 MHz 
fahren, dadurch hab ich ne Abtastrate von ~115 kHz.

von nordman (Gast)


Lesenswert?

Karl M. schrieb:
> Hallo nordman,
>
> hast Du auch die mathematische Herleitung für dein Vorhaben parat ?
>
> Würde mich mal interessieren, wie das geht.

Ich habe mich nicht ganz eindeutig ausgedrückt. Man kann natürlich mit 
dieser Methode nicht das gesamte hörbare Spektrum in 60-Hz-Bereiche 
unterteilen.

Mir ging es darum eine FFT für Musik zu schreiben. Da das menschliche 
Gehör akustische Frequenzen logarithmisch einem Ton der klassichen 
Tonleiter zu ordnet, ist es am natürlichsten eine solche 
Frequenzeinteilung auch mit der FFT nachzubilden. Die Formel, die Töne 
einer Frequenz zu ordnet, ist:

Zum Thema FFT gibt es nun 2 Dinge die man beachten muss:
Zum Einen gilt das WKS-Abtasttheorem. Das besagt, dass die maximal 
nachweisbare Frequenz die Hälfte der Abtastrate beträgt.
Zum Anderen gilt die Unschärfe-Relation. Frequenz-Auflösung ≈ 
1/Zeitfensterbreite

Durch beide Sätze ergeben sich, wenn man ein Spektrum von 60-20000 hz 
nachweisen will, mindestens
 Stützstellen braucht.
Nun mache ich mir die logarithmische Skala zu nutze. Ich teile das 
Spektrum in 3 Bänder von 60-416 hz, 416-2885 hz und 2885-20000 hz.
Das bedeutet, man benötigt lediglich 42 Stützstellen. Natürlich verliert 
man bei höheren Frequenzen an Auflösung, aber die Tonleiter ist ohnehin 
nicht so feistufig.

Nun transformiert man jede Messung seperat und erhält das gesamte 
Spektrum, in dem man die 3 eizelnen Spektren zusammensetzt.

von M. K. (sylaina)


Lesenswert?

Das ist ein interessanter Ansatz. Wie gesagt, wenn du nur jeden 7., 61. 
und 446. ADC- Wert brauchst würde ich den ADC Timergesteuert 
realisieren. Überlege mal, wenn du nach deinem Schema vorgehst hast du 
446 ADC-Werte und benutzt nur 3 davon, d.h. 443 ADC-Wandlungen hast du 
total umsonst gemacht da du die ja eh weg wirfst.

von Falk B. (falk)


Lesenswert?

@ Michael Köhler (sylaina)

>Das ist ein interessanter Ansatz.

Eher arge Selbstäuschung.

> Wie gesagt, wenn du nur jeden 7., 61.
>und 446. ADC- Wert brauchst

Der OP verwechselt da einiges. Man kann vielleicht bei der FFT nur einen 
Teil der Spektrallinien berechnen, weil der Rest physiologisch 
uninteressant ist, aber dazu braucht man immer noch ein komplettes, 
lückenloses Sample der Audiodaten.

>realisieren. Überlege mal, wenn du nach deinem Schema vorgehst hast du
>446 ADC-Werte und benutzt nur 3 davon, d.h. 443 ADC-Wandlungen hast du
>total umsonst gemacht da du die ja eh weg wirfst.

Allein bei DER Aussage würde ich verdammt stutzig werden. Wie soll man 
aus eine handvoll Samples großartige FFT Informationen gewinnen?

von M. K. (sylaina)


Lesenswert?

Die Idee finde ich nicht schlecht vom TE. Er will im Prinzip drei FFTs 
machen, einmal nur bis 416 Hz geht, einmal bis 2885 Hz und eine bis 
20000 Hz. Und er will für jede FFT 14 Stützstellen haben. Also im 
Prinzip ist das ja keine FFT sondern eine DFT, für eine FFT bräuchte man 
Stützstellenanzahl die eine Potenz zur Basis 2 darstellen, z.B. 16 
Stützstellen und nicht 14.
Wie er hier genau darauf kommt dann nur jeden 7. 61. und 446. ADC-Wert 
zu benötigen kann ich aktuell auch noch nicht verifizieren. Auch wie er 
darauf kommt, dass eine Wandlung etwa 13 ms benötigen soll. Für eine FFT 
alleine schon bei 416 Hz wäre das viel zu langsam.

Ich würde entweder drei Arrays anlegen und jedes mit unterschiedlichem 
ADC-Takt befüllen lassen oder aber halt nur ein Array anlegen, mit 
maximalen ADC-Takt samplen und dann für jede FFT die entsprechenden 
Werte aus dem Array picken.

von nordman (Gast)


Lesenswert?

ich lege im Prinzip 3 seperate Arrays an. Die sind nur in einander 
verschachtelt. Dadurch spart man Messzeit. Ich benötige kein besonders 
detailliertes Spektrum, daher nehme ich 3x8 Datenpunkte auf. Die Dauer 
der jeweiligen Messung richtet sich nach der Periodendauer kleinsten 
Frequenz. 1/(60hz) = 0,02 s. Bei einer äquidistanten Messung muss ein 
Messwert alle 0,0028 s gemacht werden. Dadurch erreicht man eine obere 
Frequenzschranke bei 2/0,0028 = 179 hz. Das heißt man benötigt nur alle 
0,0028 s einen Messwert und da ich nicht wusste, dass man Messungen 
anders timen kann, habe ich einfach sehr viele Messungen gemacht und 
alle weggeworfen, die ich nicht benötige. Daher jede 7., 61., 446.

Mir sind aber in meinem ursprüglichen Post einige Fehler unterlaufen. 1. 
ich habe nicht bedacht, dass eine Wandelung 13 Takte dauert und ich habe 
auch vergessen, dass die Abtastrate doppelt so hoch sein, wie die 
höchste Frequenz ist. Daher ergeben die Frequenzen alle keinen Sinn.

Mittlerweile bin ich dazu übergegangen 16-point FFTs zu machen. Der 
Prozessor ist schnell genug die Daten in Echtzeit zu verarbeiten.

von M. K. (sylaina)


Lesenswert?

nordman schrieb:
> Mittlerweile bin ich dazu übergegangen 16-point FFTs zu machen. Der
> Prozessor ist schnell genug die Daten in Echtzeit zu verarbeiten.

Na dafür ist der locker schnell genug. Ich mach ja gar eine 128er FFT in 
Echtzeit. Während er die FFT berechnet werden mittels Interrupt schon 
die nächsten Werte gesampelt. Für die FFT braucht mein Atmega328 7,3 ms, 
fürs Samplen der 128 Eingangswerte braucht er ~13 ms. Das klappt locker 
in Echtzeit.

von Falk B. (falk)


Lesenswert?

@ Michael Köhler (sylaina)

>Na dafür ist der locker schnell genug. Ich mach ja gar eine 128er FFT in
>Echtzeit.

Bei einer handvoll Hz Samplerate ist das auch keine Kunst ;-)

von beric (Gast)


Lesenswert?

Michael K. schrieb:
> Wie er hier genau darauf kommt dann nur jeden 7. 61. und 446. ADC-Wert
> zu benötigen kann ich aktuell auch noch nicht verifizieren.

Scheint mir ziemlich unmöglich. Ich poste hier mal drei gesamplete 
Werte:
{ 0, 13, 42 }. Damit darf mir der OP erzählen welche Tasten ich auf 
meinem Klavier gedrückt halte.

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.