Hallo, hat schon mal jemand versucht, ein (wirklich sinnvolles) VU-Meter mit einem XMEGA zu realisieren? Mit VU-Meter meine ich einen Pegelmesser mit dB-Skala für digitale Audiosignale. H-J-H
Moin, Nein, nicht mit einem xmega, aber mit Analogeingang mit einem attiny13a: Beitrag "VU-Meter mit Attiny13a statt LM3916" Hat der xmega irgendeine HW-Unterstuetzung fuer "digitale Audiosignale" (Was willst du denn koennen, I2S, SPDIF, Mehrkanalgedoense, wie Dolby oder komprimiert)? Gruss WK
Wie schon gezeigt, braucht man dafür keinen XMEGA, sondern nur etwas Hirnschmalz. Was ist denn das "wirklich Sinnvolle", wofür du es dir nicht unter XMEGA vorstellen kannst???
>> Wie schon gezeigt, braucht man dafür keinen XMEGA, sondern
nur etwas Hirnschmalz.
Beim Xmega braucht man etwas weniger Gehirnschmalz - und man kann noch
sehr vieles nebenher machen...
Vorschlag:
- nutze ADC A & B für rechts und links
- evtl. jeweils ein DMA-Kanal die ADC-Werte in Array übertragen lassen
(Ringpuffer!)
- ADCs mit einem Timer über Eventsystem triggern.
- mit ADC-/DMA-Interrupt Werte lesen "gleichrichten" (Nullunkt?), RMS
mitteln, Peak-Funktion und beides in dB umrechnen...
Er möchte DAS: Hans-Jörg H. schrieb: > Mit VU-Meter meine ich einen Pegelmesser mit dB-Skala für digitale > Audiosignale. Daher ADC egal Alexx schrieb: > Vorschlag: > - nutze ADC A & B für rechts und links > - evtl. jeweils ein DMA-Kanal die ADC-Werte in Array übertragen lassen > (Ringpuffer!) > - ADCs mit einem Timer über Eventsystem triggern. > - mit ADC-/DMA-Interrupt Werte lesen "gleichrichten" (Nullunkt?), RMS > mitteln, Peak-Funktion und beides in dB umrechnen... http://www.st.com/content/ccc/resource/technical/document/application_note/group0/c5/67/84/35/7e/4c/4c/19/DM00431633/files/DM00431633.pdf/jcr:content/translations/en.DM00431633.pdf
zu schnell auf abesenden... Der XMEGA hat zwar I2S ... daher wäre heir ein externer SPDIF receiver nötig. der dann I2S ausgibt.
Die Frage ist die nach der Anzeige. Ein Plasma Bargraph ist deutlich komplizierter anzusteuern als z.B. ein DOGM LCD. Es geht aber auch z.B. ein HD44780 LCD, bei dem man sich die unteren 8 frei definierbaren Zeichen zunutze macht. Allerdings ist ein XMega hier fast schon Overkill, denn Anzeigeraten, die schneller als ein paar ms sind, braucht hier niemand.
:
Bearbeitet durch User
Hallo, da sich inzwischen doch ein paar Reaktionen angesammelt haben, will ich meine Vorstellungen ein wenig präzisieren. Mit "sinnvoll" meine ich ein Instrument, das den gängigen Studio-Normen möglichst nahe kommt. - mindestens 100 Anzeigesegmente pro Kanal - exakte dB-Skala - Skalenspreizung (zur besseren Ablesbarkeit) in Richtung Nullpunkt - Anzeigebereich bis mindestens -50dB (besser -60dB)) Daraus ergeben sich folgende Forderungen: - Balkenanzeige mit True RMS (quadratischer Mittelwert) - Integrationszeit ca. 5ms (ist auch gleich die Reaktionszeit) - Rücklaufverhalten des Balkens 1.7s/20dB - Peak-Anzeige - zuschaltbare Peak-Hold-Anzeige Da ich digitale Audiosignale anzeigen will, wird die dB-Skala keinen positiven Bereich haben (mehr als 0 dB ist nicht möglich) Als Eingangssignal soll ein I2S Datenstrom verwendet. Als Anzeigeelemente sollen LEDs der Bauform 0603 zum Einsatz kommen. Der XMEGA hat keine I2S Schnittstelle, aber ich habe in Versuchen herausgefunden, dass man die SPI Schnittstelle "zweckentfremden" kann. H-J-H
Moin, Das sollte sich alles machen lassen. Das einzige, wo ich Probleme sehen taete, waere eben, wie man das digitale Audio in den Controller bringen kann. Aber wenn du 'ne SPI-Unit so hinbiegen kannst, dass die dir die Samples irgendwohin schreibt und einen Interrupt ausloest... Wenn das Ding mit 16MHz laeuft und du mit 48kHz Audiosamplingfrequenz arbeitest, hast du immer 333 Takte Zeit fuer deine Berechnungen. Klingt fuer mich schon machbar. Halt vielleicht nicht in Java mit ner SQL-Datenbank im Backend... Gruss WK
Hallo WK, wie kommst Du auf 333 Takte bei 16MHz? Ich muss nehmen, was mir I2S anliefert. - das sind immer 2 Kanäle - 44.1kHz oder 48kHz Samplingfrequenz (höhere Frequenzen kann man wohl vergessen) - 8...32bit Wortbreite (1...4Byte) Meine Rechnung für den worst case geht wie folgt: Der Soundcatcher der Zeitschrift c't liefert z.B. 32bit Daten. SPI triggert nach jedem empfangenen Byte einen Interrupt. Kleinere Portionen als 8bit werden ignoriert, gehen also verloren. Wenn also 17bit ankommen, können nur 16 genutzt werden.
Bei 32MHz Taktfrequenz vergehen also durchschnittlich 83.3 Takte zwischen zwei Interrupts. H-J-H
Moin, Hans-Jörg H. schrieb: > wie kommst Du auf 333 Takte bei 16MHz? Das waren einfach 16Mhz/48kHz. Das mit dem SPI ist natuerlich arg doof, dass das dann nach jedem Byte schon Alarm gibt und nicht erst nach einem Samplepaeaerchen oder gar Buffer. Wenns unbedingt der xmega sein muss, und kein Prozessor mit "richtiger" I2S Hardware, dann koennt's schon noch immernoch gehen, aber wird wahrscheinlich kein Spass. Man muss ja nicht alle 83 Takte wirklich viel machen, sondern eben nur das Byte in einen Ringpuffer schreiben. Kriegst du denn das Alignment dann irgendwie zuverlaessig raus, also wenn da z.B. 12 Byte aus dem SPI rausgepurzelt sind, weisst du dann, wo ein neues Paar Samples losgeht, wie lang die dann sind, etc.? Alle z.B. 4 bzw. 8 Interrupts kann man dann halt mal das Rechnen anfangen; das ist hauptsaechlich eine (fuer stereo 2) 16x16 signed Multiplikation(en) (=Quadrieren des Samples), die Peak und VU Werte bisschen filtern, ggf. das Quadrat draufaddieren bzw. Peak durch's Quadrat ersetzen, und dann mal alle paar zig samples sich um's Display kuemmern; also Multiplex eines weiterschalten etc. Wenn man das alles in Assembler macht, kann man am IRQ-Handler schon ordentlich sparen; ggf. muss man hoechstens das Flagregister irgendwo (zB. in einem anderen Register) retten und keine weiteren Register. Im IRQ lohnt sich's dann schon mit jedem Takt zu geizen ;-) Gruss WK
Hallo WK, ich stimme dir weitgehend zu. Das SPI Interface muss man nehmen, wie es ist. Der XMEGA C3 hat zwei davon. Das hat den Vorteil, dass man linken und rechten Kanal getrennt erfassen kann. Man verwendet einfach das LRCLK-Signal des I2S Datenstroms als /SS Select. LOW = Links, HIGH = Rechts. Beim rechten Kanal muss man es im zugehörigen Port-Pin invertieren. Da der linke Kanal immer zuerst gesendet wird, hat man nach dem Empfang des rechten Kanals immer ein zusammengehöriges Paar. Außerdem sperre ich nach 2 Bytes den Empfang, um so auch die Anzahl der Interrupts bei 32bit Samples von vier auf zwei zu reduzieren. 16bit sind mehr als ausreichend für 60dB. Beim Befüllen des Ringpuffers wird es ziemlich eng, da jedes Sample erst einmal quadriert werden muss (wg. RMS). Daraus resultieren 4 Bytes pro Sample. Das Vorzeichen spielt keine Rolle, da der Anzeigebalken ohnehin keine Aussage darüber macht. Für den gleitenden Mittelwert muss nun noch das älteste Sample im Puffer von der laufenden Summe subtrahiert und das neueste aufaddiert werden. Was jetzt noch fehlt ist eine Division durch die Anzahl der Puffereinträge. Hierfür habe ich mir folgende Lösung ausgedacht: Die Puffergröße muss so bemessen sein, dass die Durchlaufzeit etwa den geforderten 5ms entspricht. 240 Samples bei 48kHz 206 Samples bei 41.1kHz Ich habe der Einfachheit halber ein Größe von 256 gewählt. Das ist zwar ein bischen zu groß, aber der Unterschied ist minimal und fällt nicht auf. Hiermit erspare ich mir die Division. Der aufsummierte Mittelwert ist max. 5 Byte groß. Die Division durch 256 ergibt sich von selbst, wenn ich nur die oberen 4 Byte verwende. Das alles ist bereits ausprobiert und funktioniert tadellos. Ich bin zuversichtlich, dass es doch zu schaffen ist. H-J-H
Moin, Ja, wenn man genau mit so guenstigen Zahlen und Vereinfachungen arbeiten kann, dann koennt' das schon hinhauen. Die Logarithmiererei fuer die dB zerfaellt dann auch in einen harmlosen Haufen Vergleiche und Bitschiebereien. Gut ist, dass du bei dem digitalen Audio nicht aufpassen musst, ob dir da Stoerungen vom LED-Multiplex reinpfeifen. Gruss WK
Beim XMEGA müßte es doch auch möglich sein, die empfangenen Bytes mittels DMA in einen Puffer schreiben zu lassen (auch abwechselnd in zwei Puffer). Ob's die damit verringerte Interruptlast am Ende rausreißt, vermag ich aber auf die Schnelle nicht zu beurteilen. Rechenleistung sollte eigentlich genügend zur Verfügung stehen (gerade mit 32 MHz), wenn man's richtig macht, geht damit sogar MP3-Decoding in Software (Beitrag "Software MP3 decoder for ATmega/ATxmega").
Hallo Horst, DMA wäre ideal, ist hier aber leider nicht anwendbar, da die Daten erst noch bearbeitet werden müssen (quadrieren, aufsummieren, Peak suchen), bevor sie abgespeicher werden können. H-J-H
Moin, Also wenn das Dingens DMA kann, ist's auch hier anwendbar. Das quadrieren,etc. kann doch prima auch in Grueppchen ablaufen. Dann wird der Peak halt z.B. erst <128 Samples spaeter "entdeckt" - wen kratzt's? Das Display wird sowieso langsamer upgedatet... Gruss WK
Hallo, die nächste Woche werde ich erst mal kein Internet haben. Da bleibt mir jede Menge Zeit über das gesagte nachzudenken. Ich werde am Ball bleiben, da ich das Gerät auf jeden Fall bauen werde. Schaltplan und Platine habe ich auch schon fast fertig entwickelt, aber noch nicht beauftragt. Ich melde mich dann wieder. Vielen Dank an alle und Gruß H-J-H
Hallo, ich bin wieder online. Die Platinen sind inzwischen fertig, die Programmierung in vollem Gange. Wer gemeint hat, ein XMEGA sei Overkill für diese Aufgabe, der liegt total daneben. Es handelt sich hier eben nicht um ein 08/15-Gerät, sondern um eine (fast) studiotaugliche Aussteuerungsanzeige. Allein die Interrupt-Routinen für den Empfang und die Aufbereitung der Audiodaten belegen fast 90% der Rechenzeit. Bleiben also nur 10% für die dB-Kovertierung, die Rücklaufberechnung und die Anzeige. Mit einem einzelnen Kanal funktioniert es. Um beide Kanäle zu verarbeiten muss ich den XMEGA übertakten. Hier noch ein paar technische Daten:
1 | Skalenlänge: 130mm |
2 | Anzeigeelemente: 2 x 104 LEDs, grün, Baugröße 0603 |
3 | Anzeigeumfang: 0...-61dB |
4 | Anzeigefrequenz: 100Hz |
5 | Skalenspreizung: 0... -6dB: 0.25dB-Schritte |
6 | -6...-30dB: 0.5 dB-Schritte |
7 | -30...-61dB: 1 dB-Schritte |
8 | Rücklaufzeit: 1.7s je 20dB |
9 | Peak-Anzeige: ja |
10 | PeakHold-Funktion: ja |
11 | Mittelwertbildung: True RMS (Effektivwert, quadratischer Mittelwert) |
12 | Integrationsintervall: 5.3ms/48kHz, 6.2ms/41.1kHz (leichte Abweichung vom Normwert 5ms) |
13 | Eingangssignal: I2S Protokoll |
Ich verwende als Datenquelle einen Raspberry Pi Model 2B mit dem Volumio-Player. Die Ausgabe erfolgt über einen HiFiBerry DAC+. Wetere Bilder folgen. H-J-H
Hans-Jörg H. schrieb: > Empfang und die Aufbereitung der Audiodaten belegen fast 90% der > Rechenzeit Hat der XMega keine Möglichkeit, die Audiodaten per DMA einzulesen?
Hans-Jörg H. schrieb: > Ich verwende als Datenquelle einen Raspberry Pi Model 2B mit dem > Volumio-Player. Warum machst Du die Audioverarbeitung nicht komplett auf dem Raspberry und benutzt den XMega nur noch als "Displaytreiber"?
Hans-Jörg H. schrieb: > Allein die Interrupt-Routinen für den Empfang und die Aufbereitung der > Audiodaten belegen fast 90% der Rechenzeit. > Mit einem einzelnen Kanal funktioniert es. Um beide Kanäle zu > verarbeiten muss ich den XMEGA übertakten. Tja, hättest du den code gepostet, hätte man vielleicht was dazu sagen können.
ich hätte einen STM32F4 genommen. der hat I2S(SAI) interface und genug rechenpower hätte man sogar ne FFT machen können ...
Hallo, für alle diejenigen, die sich mit AVR-Assembler auskennen habe ich hier mal den Source-Code der Interruptroutine für den linken Kanal angehängt. Ich habe das PNG-Format gewählt, da sonst das Syntax Highlighting verloren geht. Dieses ist sehr hilfreich beim Lesen. Ich verwende eine Unmenge von Assembler-Macros (blau) und Preprocessor-Funktionen (lila) um damit den Befehlssatz des XMEGA (rot) zu ergänzen. Die wichtigsten Register (diejenigen, die Immediate Addressing beherrschen, r16...r25) sind in A...J umbenannt, die anderen Register r3..r15 nennen sich dementsprechend K...W. Zusätzlich gibt es 11 Word-Register z.B. AW = AH:AL = B:A = r17:r16 und natürlich 5 Long-Register z.B. AG = AWH:AWL = CW:AW = CH:CL:AH:AL = D:C:B:A = r19:r18:r17:16 Passend zu den "neuen" Datentypen gibt es dann auch neue Befehle, z.B.
1 | ldsw: |
2 | #define ldsw(rp, ma) /* load register pair rp from memory at address ma */ \ |
3 | lds rp##L, (ma) \ |
4 | lds rp##H, (ma+1) |
5 | |
6 | ldsl: |
7 | #define ldsl(rp, ma) /* load register group rg from memory at address ma */ \ |
8 | lds rp##L, (ma) \ |
9 | lds rp##H, (ma+1) \ |
10 | lds rp##H, (ma+1) \ |
11 | lds rp##H, (ma+1) |
12 | |
13 | pshsr: |
14 | .macro pshsr ; push CPU status register and register A onto stack |
15 | push A |
16 | in A, CPU_SREG |
17 | push A |
18 | .endmacro |
19 | |
20 | popsr |
21 | .macro popsr ; pop CPU status register and register A from stack |
22 | pop A |
23 | out CPU_SREG, A |
24 | pop A |
25 | .endmacro |
26 | |
27 | Alle Definitionen zusammen sind ca. 1500 Zeilen lang. |
28 | |
29 | |
30 | Eine Long-Addition sieht somit recht übersichtlich aus (4 Zeilen statt 16): |
31 | ldsl (AG, BufferPointer) |
32 | ldli (EG, 0x1234) |
33 | adl (AG, EG) |
34 | stsl (BufferPointer, AG) |
Ich hoffe, dass diese kurze Einführung einigermaße verständlich war. Aus dem Listing geht auch hervor, warum DMA hier nichts nützt. Die Daten müssen nämlich erst aufbereitet werden, bevor sie abgespeichert werden können. Wollte man das nachträglich machen, müssten diese erst wieder geladen, verarbeitet und erneut abgespeichert werden. H-J-H
Du arbeitest ja nur mit 16-Bit-Samples. Muß alles wirklich mit 32-Bit-Genauigkeit verarbeitet werden, würden da nicht 24 Bit reichen?
Moin, Hans-Jörg H. schrieb: > Allein die Interrupt-Routinen für den Empfang und die Aufbereitung der > Audiodaten belegen fast 90% der Rechenzeit. > Bleiben also nur 10% für die dB-Kovertierung, die Rücklaufberechnung und > die Anzeige. Also bau' doch alles in den IRQ-Handler rein, dann kannst du als "Hauptprogramm" sowas wie main: rjmp main hernehmen und musst im IRQ-Handler keine Register mehr sichern/herstellen, nicht mal mehr die Flags. Dann hast du sicherlich noch weiteres Einsparpotential im IRQ-Handler. Du rufst da noch Unterprogramme (z.B. fuer die Multiplikation) auf. Das kostet doch alles viel Zeit... Quetsch' noch ein bisschen, dann wird das schon passen. Gruss WK
Hans-Jörg H. schrieb: > Ich hoffe, dass diese kurze Einführung einigermaße verständlich war. Nun, es ist in Assembler, du nutzt Atmels Hardware-Multiplier, aus irgendeinem Grund vermisse ich sqrt. Und dass der erste Interrupt kurz und der nächste Interrupt lange dauert ist egal weil sie abwechselnd kommen. Meiner Meinung nach könnte man rectify weglassen weil eh x*x gebildet wird (dann eben signed), und daß der Peak dann nur positive Halbwellen erfasst ist egal weil Audio symmetrisch ist, aber das halbiert die Laufzeit nicht.
:
Bearbeitet durch User
Hallo, @ Michael: die Wurzel wird in jedem Anzeigeintervall (10ms) nur einmal berechnet, daher findet deren Berechnung an anderer Stelle statt. Die beiden Interrupts (kurz und lang) benötigen etwa 30 + 270 Taktzyklen (worstcase). Die Gleichrichtung ist nur für den Peak-Wert erforderlich, da der nicht aus den Quadraten gebildet wird, sonst müsste ich noch eine weitere Wurzel ziehen. Audio ist auf Abtastebene keineswegs symmetrisch. Das trifft nur auf größere Zeiträume zu (gleichspannungsfrei). Wäre es symmetrisch, könnte man sich die Hälfte der Abtastungen sparen. @ WK: das funktioniert leider nicht, da der nächste Interrupt bereits nach ca. 10.5µs kommt. In der kurzen Zeit ist das nicht zu schaffen. Der IRQ würde sich dann ständig selbst unterbrechen, bis der Stack überläuft... Außerdem habe ich noch andere Interrupt-Quellen (den rechten Kanal, Timer für die Anzeige, Timer für den Rücklauf). @ Horst: 24 Bit sind 3 Byte, eine unschöne Größe in der Assemblerprogrammierung, aber eine Überlegung wert. Ich werde darüber nachdenken. Ich möchte noch hinzufügen, dass das gesamte Programm in Assembler geschrieben ist. Gruß H-J-H
Hans-Jörg H. schrieb: > Ich möchte noch hinzufügen, dass das gesamte Programm in Assembler > geschrieben ist. Na, dann hast Du ja volle Kontrolle über alles. Mit einem exklusiv reservierten Register könntest Du Dir z.B. das Push/Pop in den pshsr/popsr-Macros schenken (spart 6 Zyklen pro Interrupt auf dem Xmega). Einen Quantensprung in der Optimierung wirst Du wohl nicht erreichen können, aber Kleinvieh macht auch Mist...
:
Bearbeitet durch User
Horst M. schrieb: > Einen Quantensprung in der Optimierung wirst Du wohl nicht erreichen > können, Na ja, Quanten machen die kleinsten Sprünge die denkbar sind. 256 Byte buffer erlaubt incrementierung alleine von Pointer#L wenn man den Buffer auf 256-byte-Grenzen legt ohne auf den Überlauf zu achten. Damit man dann 4 byte speichern kann, wird man nicht 4 Indexregister verwenden und 256,512,768 byte offset kann der XMega wohl nicht, aber das #H Register incrementieren. Ob das schneller wird ? Hans-Jörg H. schrieb: > #define ldsl(rp, ma) /* load register group rg from memory at > address ma */ \ > lds rp##L, (ma) \ > lds rp##H, (ma+1) \ > lds rp##H, (ma+1) \ > lds rp##H, (ma+1) Echt, alles in rp##H ? Kommt mir komisch vor, Xmega-Assembler habe ich aber noch nicht benutzt.
Moin, Hans-Jörg H. schrieb: > die Wurzel wird in jedem Anzeigeintervall (10ms) nur einmal berechnet, > daher findet deren Berechnung an anderer Stelle statt. Ist nicht dein Ernst? Wozu eine Wurzelberechnung, wenn du danach eh' "logarithmierst"? In Anfuehrungszeichen, denn richtiges logarithmieren kann man sich da auch schenken, weil's Ergebnis ja nur recht ungenau sein muss - 100 LEDs sind ja nichtmal 7 bit Genauigkeit. Hans-Jörg H. schrieb: > das funktioniert leider nicht, da der nächste Interrupt bereits nach ca. > 10.5µs kommt. > In der kurzen Zeit ist das nicht zu schaffen Mimimi - Alles alternativlos... Nein ist es nicht. Hans-Jörg H. schrieb: > Außerdem habe ich noch andere Interrupt-Quellen (den rechten Kanal, > Timer für die Anzeige, Timer für den Rücklauf). Ja Hilfe, was denn noch alles? Wozu denn die Timer? Verschiedene Interrupts - das gibt doch Raceconditions ohne Ende. Der I2S-Interrupt ist doch "die Mutter allen Timings". Aus dem kannst du deine ganzen anderen Geschichten ableiten. Gibts irgendwo ein Stueckchen (Asm)Codefragment, was zeigt, wie mit dem verhauten SPI Interface, was du da hast, I2S empfangen wird - moeglichst L und R? Moeglichst auch mit DMA, wenn sowas geht? Gruss WK
Hallo, @ Michael: guter Hinweis! Ich werde die Abfrage auf Buffer Overrun entsprechend anpassen. Und da hast du ebenfalls recht: "ldsl" ist natürlich so definiert:
1 | #define ldsl(rp, ma) /* load register group rg from memory at address ma */ \ |
2 | lds rp##LL, (ma) \ |
3 | lds rp##LH, (ma+1) \ |
4 | lds rp##HL, (ma+2) \ |
5 | lds rp##HH, (ma+3) |
@ WK: eine Logarithmierung findet bei mir nicht statt. Stattdessen verwende ich eine Lookup Table mit 104 Einträgen. Aber du hast recht, man könnte statt der Sample-Werte deren Quadrat eintragen, was zum selben Ergebnis führt. Auf diese Weise spare ich mir das Wurzelziehen. Der einzige Unterschied ist der, dass man dann 32bit- statt 16bit-Einträge hat. Aber Programmspeicher ist ja genug vorhanden. Allerdings ist der Einsparungseffekt nicht sehr groß, da die Wurzel nur 2mal in 10ms beechnet werden muss. Genaugenommen: 1170 von 32000 Taktzyklen (< 3.7%) Andererseits ist es immer sinnvoll Überflüssiges zu eliminieren. >Gibts irgendwo ein Stueckchen (Asm)Codefragment, was zeigt, wie mit dem >verhauten SPI Interface, was du da hast, I2S empfangen wird - moeglichst >L und R? Moeglichst auch mit DMA, wenn sowas geht? Ja, genau das gibt es, ist in einem meiner vorherigen Postings angehängt. Siehe oben. Der rechte Kanal wird über das zweite SPI empfangen. Der Code sieht genauso aus, nur L ist durch R ersetzt. Gruß H-J-H
Moin, Hans-Jörg H. schrieb: > Der einzige Unterschied ist der, dass man dann 32bit- statt > 16bit-Einträge hat. Aber Programmspeicher ist ja genug vorhanden. Von den 32bit bist du mit 24bit schon mehr als gut dabei. ( 61dB Anzeigeumfang => (61/10))/log10(2)=20.26 bit ) also gut 3 bit Reserve. D.h. worst-case waeren dann 7 (2⁷ > 104) Vergleiche zu machen, wo jeweils 2 24 Bit Zahlen verglichen werden muessen, um danach zu wissen wieviele LEDs leuchten sollen. In den meisten Faellen wirds deutlich schneller gehen. Man muss fast nie alle 3 byte der beiden Zahlen miteinander vergleichen; sind die Zahlen gleichverteilt, ist schon in (1-1/256)*100%= 99.6% aller Faelle der Keks nach dem ersten 8 bit Vergleich gelutscht, und es ist klar, ob die Zahl groesser oder kleiner ist. Das ist ja grad' das schoene am Assembler, dass man auch mit so "krummen" Operandenlaengen rechnen kann und mauscheln und vereinfachen, wo's geht. > Allerdings ist der Einsparungseffekt nicht sehr groß, da die Wurzel nur > 2mal in 10ms beechnet werden muss. > Genaugenommen: 1170 von 32000 Taktzyklen (< 3.7%) Ich weiss nicht, was du da alles anstellst in den 32000 Taktzyklen, aber mich beschleicht das unbestimmte Gefuehl, dass man da an sehr vielen Stellen noch ziemlich heftig vereinfachen kann... > Ja, genau das gibt es, ist in einem meiner vorherigen Postings > angehängt. Siehe oben. > Der rechte Kanal wird über das zweite SPI empfangen. Der Code sieht > genauso aus, nur L ist durch R ersetzt. Hm - ok, ich dacht' da eher an irgendeine "offizielle" Appnote. Wenns da so garnix gibt, ist's natuerlich mutig, da selber was zu basteln, um mit Gewalt den ollen Prozessor ohne I2S Hardware zu nehmen. Um so mehr muss man dann halt beim Rest der Programmierung um jeden Zyklus und jedes Bit Rechengenauigkeit feilschen. Und nicht am Java Backend die Datenbank anflanschen ;-) Gruss WK
Hallo, die Mühe hat sich gelohnt. Inzwischen läuft der XMEGA auch mit der Nominalfrequenz von 32MHz. Da das Übertakten aber so unproblematisch war, lasse ich ihn jetz ständig mit 50MHz laufen. Die Bilder zeigen ein paar Testsignale, Sinus mit einer Amplitude (Peak) von -1dB, -12dB und -40dB. Man sieht hier sehr schön, dass der Effektivwert immer 3dB niedriger ist. So soll es ja auch sein. Die Skala ist ein simpler Papierstreifen, mit dem Tintendrucker bedruckt. Die verwendeten LEDs sind dermaßen hell, dass sie problemlos durch das Papier leuchten. Der LED-Strom dürfte bei etwa 10mA liegen. Dank Multiplexing leuchtet zu jedem Zeitpunkt nur immer eine einzige LED. Die Gesamtstromaufnahme ist daher sehr niedrig und somit für den RasPi kein Problem. Gruß H-J-H
Hallo WK, zum Thema I2S und SPI: I2S liefert im Wesentlichen 3 Signale: - BCLK, Bit-Clock - LRCLK, Links/Rechts Unterscheidung, low = links - DATA, die eigentlichen Audiosamples im 2er-Komplement I2S ist zur Kommunikation innerhalb von Geräten (z.B. CD Player) gedacht, also nicht zur Übertragung über längere Kabel. Bei jedem Flankenwechsel von LRCLK wird zuerst ein leeres Synchronisationsbit gesendet und sofort danach ohne Abstand Das Audiosample. Die Audiosamples können theoretisch beliebige Wortlänge haben, üblich sind jedoch 8...32bit. Das MSB wird immer zuerst gesendet. Ein Empfänger empfängt immer nur so viele Bits, wie er verarbeiten kann. Den Rest ignoriert er. Damit ist sichergestellt, dass Sender und Empfänger sich in jedem Falle verstehen, auch wenn sie für veschiedene Wortlängen ausgelegt sind. SPI ist sehr ähnlich. Nachteilig ist, dass man bei der Wortlänge auf Bytegröße festgelegt ist. Als Slave konfiguriert kann nach jedem empfangenen Byte ein Interrupt ausgelöst werden. Nach zwei Bytes sperre ich das Interface, um eventuell nachfolgende Bytes daran zu hindern weiter Interrupts auszulösen. SPI wird durch LRCLK über seinen !SS-Eingang aktiviert. Da dieser LOW-aktiv ist, wird immer nur der linke Kanal empfangen. Daher verwende ich das zweite SPI für den rechten Kanal, indem ich den Port-Pin für !SS invertiere. Da das erste Bit ein Synchronisationsbit ist und das zweite Bit das Vorzeichenbit, habe ich letztendlich nur 14 Bits zu Verfügung. Das ist aber immer noch mehr als genug für den vorgesehenen Anzeigeumfang von -60dB. Ich hoffe das trägt etwas zum Verständnis bei. Gruß H-J-H
Hans-Jörg H. schrieb: > Inzwischen läuft der XMEGA auch mit der Nominalfrequenz von 32MHz Das ist schön. Hans-Jörg H. schrieb: > Der LED-Strom dürfte bei etwa 10mA liegen. Dank Multiplexing leuchtet zu > jedem Zeitpunkt nur immer eine einzige LED. Die Gesamtstromaufnahme ist > daher sehr niedrig und somit für den RasPi kein Problem. Das weniger. Du hast 104 LEDs. Würdest du wirklich Multiplexing einsetzen, hättest du deine mechanisch in einer linearen Reihe angeordneten LEDs beispielsweise elektrisch gesehen in einer Matrix von 8 (Zeilen) x 13 (Spalten) verdrahtet, und wenn tatsächlich ein mittlerer Strom von 10mA/104 = 100uA dir ausreicht die Spalten mit einem 3k3 Vorwiderstand für 0.8mA ausgestattet. Dann leuchten je 13 LEDs auf ein Mal, und das zeitlich in 8 Gruppen nacheinander. Der Vorteil wäre klar eine geringe Anzahl von Anschlüssen, 21 reichen, also 3 ICs a 8 Ausgängen, bei Charlyplexing sogar 14, also 2 IC. Du hast aber 13 20 polige ICs, Typennummer unlesbar, sieht aber aus wie 8 bit paralleles Latch. Damit hast du 104 Ausgänge und jede LED einzeln verbunden. Multiplexing ist dabei weder nötig noch möglich, die andere Seite der LED ist nämlich dauerhaft angeschlossen, sei es an plus oder Masse. Ich denke, bei dir leuchtet gar nicht nur 1 LED zu einer Zeit. Einerseits weil 10mA/104 = 100uA gar nicht so hell wäre, zum anderen weil das Flimmern mit einer 104 mal kleineren Grundfrequenz wohl auffallen würde. wahrscheinlich (oder hoffentlich) setzt du nur jede LED einzeln ins Latch, sie leuchtet dann aber dauerhaft simultan mit den 103 anderen was zu bis zu 1.04A Stromaufnahme führen würde (und sicher hell genug ist, auch durch ein Papier). Wenn es aber WIRKLICH gemultiplext wird, dann entferne von den 13 20 poligen IC mal 11, und lass 2 x74HC595 übrig mit 3k3 pullup für 1mA Pulsstrom = 100uA mittleren Strom um es im Charlyplexing zu betreiben. https://www.maximintegrated.com/en/app-notes/index.mvp/id/1880
Moin, Sieht schick aus! Ich kenn' die beiden Interfaces - kleiner Tipp: Das ist kein Syncbit beim I2S, sondern das LSB des vorhergehenden Samples. Was aber beim Anzeigeumfang keine Rolle spielt. Du hast also alle 166 Takte einen Interrupt und musst bei jedem 2. Interrupt nix machen, ausser den Wert speichern. Also ca. (333-X) Takte/Audiosampleverarbeitung, wenn das Interruptgedoens X Takte frisst und du nicht uebertaktest (was ich nicht tun wuerde, wenn sich's irgendwie vermeiden laesst. Denn die Chiphersteller wissen schon, warum sie eben den Chip nur mit niedrigerer Frequenz laufen lassen wollen. Du weisst das nicht.) Ich vermut' mal, dass bei "real World" Audiosignalen deine feine 0.25dB/Segment-Aufloesung im oberen Bereich nicht so oft zum Tragen kommen wird, normale Quellen sollten afair nur mit Spitzenpegeln im Signal von -12...-18 dBFS daherkommen. Gruss WK
Hallo MaWin, da ich der Urheber der Schaltung bin, darfst du mir ruhig glauben, dass jederzeit wirklich nur eine einzige LED leuchtet. Die Schaltung besteht aus 13 Gruppen zu je 8 LEDs. Dazu gibt es 13 + 8 Portleitungen. Zusätzlich gibt es noch 2 Leitungen für die Kanäle. Die Treiber sind 74FCT540 2x4bit inverted buffers. Die beiden Kanäle werden zeitlich nacheinander angesteuert. Die 13 Gruppenleitungen schalten über !OE jeweils immer nur ein IC durch. In jedem IC ist über die 8 LED-Leitungen immer nur ein einziger Buffer aktiviert. Wäre es anders würde meine Software nicht funktionieren. Und dass sie funktioniert, ist mit Sicherheit kein Zufallsergebnis. Der Strom beträgt ca. 20mA (nicht wie von mir behauptet 10mA) und die Leuchtdauer ist ca. 43µs/10ms. Die LEDs sind mit 1400mcd/20mA spezifiziert. Durch geschickteres Multiplexing sind sicher noch Leitungen einzusparen, aber die gewählte Konfiguration war für mich übersichtlicher. Vielen Dank für den interessanten Hinweis auf Charlieplexing. Damit werde ich mich noch befassen. Gruß H-J-H
Hi
>Die Treiber sind 74FCT540 2x4bit inverted buffers.
Eher ein 8Bit inverted Puffer mit 2 Freigabesignalen.
MfG Spess
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.