Forum: Mikrocontroller und Digitale Elektronik VU-Meter mit XMEGA


von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von Dergute W. (derguteweka)


Lesenswert?

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

von Harry L. (mysth)


Lesenswert?

Ich hab sowas mal mit nem BluePill-Board gemacht:
https://www.youtube.com/watch?v=aDdWhyNQf3o

von Jacko (Gast)


Lesenswert?

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???

von Alexx (Gast)


Lesenswert?

>> 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...

von jzjjf (Gast)


Lesenswert?

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

von jzjjf (Gast)


Lesenswert?

zu schnell auf abesenden...

Der XMEGA hat zwar I2S ... daher wäre heir ein externer SPDIF receiver 
nötig.
der dann I2S ausgibt.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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
von H-J-H (Gast)


Lesenswert?

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

von Dergute W. (derguteweka)


Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von Dergute W. (derguteweka)


Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von Dergute W. (derguteweka)


Lesenswert?

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

von Horst M. (horst)


Lesenswert?

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").

von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von Dergute W. (derguteweka)


Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Angehängte Dateien:

Lesenswert?

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

von Johnny B. (johnnyb)


Lesenswert?

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?

von Johnny B. (johnnyb)


Lesenswert?

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"?

von Michael B. (laberkopp)


Lesenswert?

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.

von jzjjf (Gast)


Lesenswert?

das wäre scheinbar zu einfach gewesen

von jzjjf (Gast)


Lesenswert?

ich hätte einen STM32F4 genommen.

der hat I2S(SAI) interface und genug rechenpower

hätte man sogar ne FFT machen können ...

von Hans-Jörg H. (h-j-h)


Angehängte Dateien:

Lesenswert?

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

von Horst M. (horst)


Lesenswert?

Du arbeitest ja nur mit 16-Bit-Samples.
Muß alles wirklich mit 32-Bit-Genauigkeit verarbeitet werden, würden da 
nicht 24 Bit reichen?

von Dergute W. (derguteweka)


Lesenswert?

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

von Michael B. (laberkopp)


Lesenswert?

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
von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von Horst M. (horst)


Lesenswert?

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
von Michael B. (laberkopp)


Lesenswert?

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.

von Dergute W. (derguteweka)


Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von Dergute W. (derguteweka)


Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Angehängte Dateien:

Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

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

von Dergute W. (derguteweka)


Lesenswert?

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

von Hans-Jörg H. (h-j-h)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.