Hallo,
ich bin gerade dabei die Lichtorgel nach folgendem Projekt nachzubauen:
Beitrag "[C] AVR-Lichtorgel per FFT MEGA8 32 644"
Diese verwendet (wie wahrscheinlich bekannt), die FFT von Elm-Chan:
http://elm-chan.org/works/akilcd/report_e.html
Der Unterschied zu dem Projekt ist, dass ich das Board ATxmega256A3BU
verwende, welches ich mit 32MHz laufen lasse.
Den Code nach dem Lichtorgel Projekt habe ich nach bestem Wissen
umgeschrieben in die xMega-Syntax. Jedoch funktioniert es noch nicht.
Was bisher funktioniert:
Das Mikro und die Analogschaltung habe ich angeschlossen bzw. aufgebaut.
Die Verstärkerschaltung habe ich mit dem Mikrofoneingang am PC getestet,
sie funktioniert.
Den ADC-Kanal, über den der Ausgang der OP-Schaltung eingelesen wird,
liefert je nach Spannung (0V - 3.3V) einen Wert zwischen -1100 und ca.
32753. Diesen Wert lasse ich mir am Display meines Boards ausgeben. Auch
kann ich sehen, dass dieser Wert schwankt, je nachdem wie fest ich in
das Mikrofon puste. Ist es ruhig, so liefert der ADV-Wandler einen Wert
von ca. 26300.
Die 6 LEDs steuere ich direkt über die Outports an, also nicht über eine
Transistorschaltung. Wenn ich zum Test mal alle 6 "Kanäle" der FFT mit
Werten belege, so leuchten auch alle LEDs.
Was passiert ist folgendes: die 1. Led leuchtet im ca. 1 Sekunden-Takt
gnz kurz auf. Die anderen LEDs leuchten alle nicht.
Ich habe bereits die Verstärkung der Mikrofon-Schaltung aufgedreht,
sowie den THRESHOLD im Code herabgesetzt. Nichts hat geholfen. An F_PWM
sowie PWM_STEPS habe ich nichts geändert. An den Routinen ffft.h,
mydefs.h, ffft.S habe ich nichts geändert, bis auf die Anpassung der
Ports.
Meine Vermutung ist, dass ich den ADC-Wert nicht im richtigen
Datenformat habe, wie er sein sollte.
Welcher Datentyp müsste er denn sein und welchen Wert müsste er liefern,
wenn ich meine Schaltung mit 3.3V versorge und der OP im Mittel 1.65V am
Ausgang (bzw. ADV Eingang) liefert? Welchen Wert erwartet die Routine
dann als ADC-Wert?
Weiterhin kann ich mir vorstellen, dass ich nicht überall im Code die
32Mz berücksichtigt habe. An welchen Stellen muss ich dafür eine
Veränderung vornehmen?
Anbei der Quelltext der größeren Codepassagen, die ich verändert habe.
Original (atmega8) mit 16Mhz:
Highii H. schrieb:> Den ADC-Kanal, über den der Ausgang der OP-Schaltung eingelesen wird,> liefert je nach Spannung (0V - 3.3V) einen Wert zwischen -1100 und ca.> 32753. Diesen Wert lasse ich mir am Display meines Boards ausgeben. Auch> kann ich sehen, dass dieser Wert schwankt, je nachdem wie fest ich in> das Mikrofon puste. Ist es ruhig, so liefert der ADV-Wandler einen Wert> von ca. 26300.
Das kann nicht sein.
Der ADC hat 12 Bit Ausflösung. Damit können sich die Werte nur von 0 bis
4095 bewegen. Deine Werte sind daher nicht plausibel. Da musst du noch
mal ran.
> Im Moment seh ich da den Sinn noch nicht.
Vermutlich will er den Nullpunkt verschieben. Kann davon abhaengen was
der AD-Wandler an Daten liefert.
Olaf
ADLAR gesetzt und kriegt damit das Ergebnis linksbündig ausgerichtet.
Damit ist klar, warum er 32768 abzieht: Er verschiebt das Ergebnis in
den Bereich -32768 bis +32767, wobei nicht alle 16 Bit benutzt werden,
sondern nur die 10 höchtwertigen Bits zählen.
Wenn du am XMega ADC das Ergebnis nicht linksbündig ausrichten lässt ist
klar, dass du dann Unsinn im Ergebnis bekommst, wenn du genau dasselbe
machst. Entscheidend ist hier das ADLAR Bit.
Edit:
Hmm. eigentlich hast du ja LEFT12BIT gesetzt. Trotzdem sehen deine
Werte mies aus. Eigentlich sollte sich da ein schön symetrischer Bereich
ergeben, wenn du (zb mit einem Poti) dem ADC Spannungen von 0 bis zur
Referenzspannung anbietest.
Karl H. schrieb:> Der ADC hat 12 Bit Ausflösung. Damit können sich die Werte nur von 0 bis> 4095 bewegen. Deine Werte sind daher nicht plausibel. Da musst du noch> mal ran.
Mh, komisch. Auf dem Display bekomme ich aber 32753 (bei 3.3V)
angezeigt.
Karl H. schrieb:> Hmm. eigentlich hast du ja LEFT12BIT gesetzt. Trotzdem sehen deine> Werte mies aus. Eigentlich sollte sich da ein schön symetrischer Bereich> ergeben, wenn du (zb mit einem Poti) dem ADC Spannungen von 0 bis zur
Ich bin davon ausgegangen, dass durch das ADLAR-Bit, aus dem ADV Werte
zwischen 0 und 65536, für 0V bzw. +5V, herauskommen. Und Elm-Chan mit
-32768 diesen ADV-Wert zwischen -32768 bis +32767 verschiebt.
Was macht eigentlich der Befehl
1
*buffer++=ADC-32768;
Zieht er 32768 von ADC ab, und geht danach im buffer-array eins weiter?
Oder zieht er vom aktuellen Buffer-Wert 32768 ab und schreibt den neuen
Wert wieder in den Buffer?
Highii H. schrieb:> Ich bin davon ausgegangen, dass durch das ADLAR-Bit, aus dem ADV Werte> zwischen 0 und 65536, für 0V bzw. +5V, herauskommen.
Ersetzte die 5V durch "Referenzspannung" und wir sind genau dort.
Aber das hast du ja nicht, du sprichst von -1100 bis 32tausend
irgendwas. Das ist dann nicht "symetrisch".
Hast du denn deinen ADC getestet, indem du mit einem Poti Spannungen
zwischen 0V und der Referenzspannung eingeschleust hast und dir die
Werte angesehen hast, oder hast du einfach mal ein Audiosignal
draufgeklopft in der Hoffnung, dass schon alles irgendwie funktionieren
wird?
> Zieht er 32768 von ADC ab, und geht danach im buffer-array eins weiter?
Genau so.
> Oder zieht er vom aktuellen Buffer-Wert 32768 ab und schreibt den neuen> Wert wieder in den Buffer?
kommt 'buffer' auf der rechten Seite der Zuweisung irgendwie vor?
Nein
Also wird wohl der aktuelle Inhalt von buffer keine Rolle spielen.
Karl H. schrieb:> Aber das hast du ja nicht, du sprichst von -1100 bis 32tausend> irgendwas. Das ist dann nicht "symetrisch".
Ich habe einen kleinen Fehler bei der Anzeige gemacht. Die Werte gehen
von -112 bis 32752.
ADV mal an GND mal an Vcc (3.3V) gehalten.
Highii H. schrieb:> Karl H. schrieb:>> Aber das hast du ja nicht, du sprichst von -1100 bis 32tausend>> irgendwas. Das ist dann nicht "symetrisch".>> Ich habe einen kleinen Fehler bei der Anzeige gemacht. Die Werte gehen> von -112 bis 32752.
Ist immer noch nicht symetrisch.
Wenn der Eingang auf GND liegt, muss am letzten OpAmp die halbe Spannung
der Referenzspannung anliegen und dein ADC muss (nach der Umrechnerei)
eine glatte 0 (oder nahe drann) auswerfen.
> ADV mal an GND mal an Vcc (3.3V) gehalten.
So gehts auch. Trotzdem muss das Ergebnis symetrisch rund um 0 sein!
Highii H. schrieb:> Karl H. schrieb:>> So gehts auch. Trotzdem muss das Ergebnis symetrisch rund um 0 sein!> Also ist -112 noch zu weit entfernt!?
Wenn du 16 Bit linksbündig bist (unsigned) UND 32767 abziehst und in
einer signed Variablen speicherst, dann muss das Ergebnis den kompletten
Bereich -32768 bis +32767 abdecken!
Highii H. schrieb:> Anbei der Quelltext der größeren Codepassagen, die ich verändert habe.
Atmega8 und ATXMega unterscheiden sich recht ordentlich - da kann man
aus wenigen "angepassten" Code-Passagen nicht auf irgendwelche Fehler
schließen.
Weiß ich auch Erfahrung :-/
Ich habe mein ATMega-Original in großen Teilen "vergessen" und mit
ATXMega nahezu neu angefangen. Eine "einfache" Portierung halte ich für
"unwahrscheinlich", lasse mich aber gerne eines Besseren belehren.
Kurz: Schau Dir das Prinzip an und baue es neu auf. Ist nebenbei
ungemein lehrreich :-)
Dieter F. schrieb:> Kurz: Schau Dir das Prinzip an und baue es neu auf. Ist nebenbei> ungemein lehrreich
Das mache ich eigentlich auch immer so. Aber durch die FFT blicke ich
nicht ganz durch. Vor allem was in ASM geschrieben ist.
Dieter F. schrieb:> Ich habe mein ATMega-Original in großen Teilen "vergessen" und mit> ATXMega nahezu neu angefangen. Eine "einfache" Portierung halte ich für> "unwahrscheinlich", lasse mich aber gerne eines Besseren belehren.
Solange es nur um den Core geht, ist der Xmega zu 99% kompatibel. Ich
habe selbst schon größere Assemblerprojekte portiert. Die
Peripheriefunktionen musste man halt austauschen.
avr schrieb:> Solange es nur um den Core geht, ist der Xmega zu 99% kompatibel. Ich> habe selbst schon größere Assemblerprojekte portiert. Die> Peripheriefunktionen musste man halt austauschen.
Ok. Ich schaue es mir nochmal an.
avr schrieb:> Solange es nur um den Core geht, ist der Xmega zu 99% kompatibel
Fällt mir schwer, das zu glauben. Kannst Du das gezielt an Beispielen
(Timer, externe Interrupts, USART, SPI. I2C etc.) belegen?
Oder gehören zu Deinen "Core-Funktionen" nur Register-Operationen etc.
und Sprünge?
Dieter F. schrieb:> Oder gehören zu Deinen "Core-Funktionen" nur Register-Operationen etc.> und Sprünge?
Zu Core gehört der AVR-Core. Das drum herum ist Peripherie. Dazu gehören
auch Timer, SPI... Die Treiber dafür zu schreiben kostet in der Regel
auch vergleichsweise wenig Zeit.
Nur Registeroperationen ist gut. Das was ich portiert habe, war immerhin
ein komplexes Programm. Die Änderungen sind übrigens die gleichen die
man auch in einem C-Programm machen hätte müssen. Aber wenn man das
Programm sauber von Peripheriezugriffen trennt, dann geht die Portierung
sehr schnell.
avr schrieb:> Aber wenn man das> Programm sauber von Peripheriezugriffen trennt, dann geht die Portierung> sehr schnell.
Blah, blubb - in der Peripherie liegt der Schmackes. Ohne IO geht
nichts. Da kann der Core die 1.238 te Wurzel aus 5 berechnen - ohne
Ausgabe spielt das keine Rolle ...
Dieter F. schrieb:> avr schrieb:>> Aber wenn man das>> Programm sauber von Peripheriezugriffen trennt, dann geht die Portierung>> sehr schnell.>> Blah, blubb - in der Peripherie liegt der Schmackes. Ohne IO geht> nichts.
Schon richtig.
Aber bei der (in Assembler geschriebenen) FFT sind laut avr-s Aussage
kaum Probleme zu erwarten.
Daher muss er sich jetzt erst mal darauf konzentrieren, den ADC in den
Griff zu kriegen. Solange der miese Werte liefert, ist nicht zu
erwarten, dass die FFT da irgendwas vernünftiges draus macht.
Karl H. schrieb:> Daher muss er sich jetzt erst mal darauf konzentrieren, den ADC in den> Griff zu kriegen. Solange der miese Werte liefert, ist nicht zu> erwarten, dass die FFT da irgendwas vernünftiges draus macht.
So, den ADC habe ich nun in den Griff bekommen. Der xMega läuft mit
3.3V. Die mittlere Spannung am ADC ist 1.65V. Der ADC liefert nun bei 0V
am Eingang einen Wert von -32768. Bei 1.65V liefert er 0 und bei 3.3V
liefert er +32767.
Leider geht es immernoch nicht. Keine der LED leuchtet auf.
Gibt es jemanden, der bereit wäre, meinen Code mal durchzuschauen?
Ich werde mir jetzt mal die Logik der FFT Routine anschauen. Vielleicht
verstehe ich ja was sie macht. Leider habe ich absolut keine Ahnung von
ASM.
Ah, jetzt geht es (fast). Ich habe aus unerklärlichen Gründen die
Definition der LED-Ports als Ausgang rausgeschmissen. Dann kann ja auch
gar keine LED leuchten.
Jedenfalls geht sie die FFT jetzt. Ich muss jetzt nur noch an der
Verstärkung schrauben. Wenn ich Musik aufdrehe, leuchten die LEDs nur
sehr schwach, bewegen sich aber zum Beat. Wenn ich jedoch Frequenzen
direkt auf das Mikro spiele (mit einer einfachen Handy-App), dann
leuchten sie perfekt auf.