Ich versuche aktuell, ein Musiksignal über einen ADC einzulesen, die
Samples mit einem FIR Filter zu belegen und das Ergebnis auf einen DAC
auszugeben, das funktioniert aber irgendwie nicht so, wie ich mir das
vorstelle. Von der Geschwindigkeit her wird es schon etwas eng, aber das
sollte machbar sein. Ich benutze einen 8-bit Timer, der mit 8 MHz läuft
(32MHz Basistakt / 4), d.h. pro Sekunde werden ~31300 Samples erzeugt.
Ich habe mir die Koeffizienten für einen Bandpass von 1kHz - 10kHz mit
diesem Programm (http://www.winfilter.20m.com/) erzeugen lassen, der
Kurve nach sollten Frequenzen, die nicht innerhalb von 1 - 10 kHz
liegen, stark gedämpft sein, die Musik, die rauskommt, hört sich aber
fast nicht mehr wie Musik an :(
Hier mein Code:
1
/*
2
* RA2 = DAC1OUT1
3
*/
4
5
#include<xc.h>
6
#include<pic16f15376.h>
7
8
#pragma config WDTE = OFF // WDT operating mode (WDT Disabled, SWDTEN is ignored)
9
10
#define Ntap 20
11
12
unsignedcharbuffer[Ntap];
13
14
intcoeffs[Ntap]={
15
-2,
16
-3,
17
-3,
18
-5,
19
-4,
20
-8,
21
-3,
22
-18,
23
24,
24
106,
25
24,
26
-18,
27
-3,
28
-8,
29
-4,
30
-5,
31
-3,
32
-3,
33
-2,
34
-2
35
};
36
37
voidinterrupt__isr_handler(void){
38
ADCON0bits.GO=1;//Start ADC conversion
39
while(ADCON0bits.GO!=0)//Wait until conversion is done
40
;
41
42
buffer[0]=ADRESH;//8 MSBs from ADC conversion
43
longsum=0;
44
for(unsignedchari=0;i<Ntap;i++){
45
sum+=buffer[i]*coeffs[i];
46
}
47
48
DAC1CON1=sum>>7;//WinFilter tells me to divide sum by 128
49
50
//rotate array
51
for(unsignedcharn=Ntap-1;n>0;n--)
52
coeffs[n]=coeffs[n-1];
53
54
PIR0bits.TMR0IF=0;//Clear interrupt flag
55
}
56
57
// Read from: RD7
58
voidinitADC(){
59
// Configure RD7
60
WPUDbits.WPUD7=0;//Disable pull-up
61
TRISDbits.TRISD7=1;//Disable output driver
62
ANSELDbits.ANSD7=1;//Analog input
63
64
ADCON0bits.CHS=0b011111;//ADC Value is read from RD7
65
ADCON1bits.ADPREF=0b00;//Vref is connected to Vdd
66
ADCON1bits.ADCS=0b101;//Fosc/16
67
68
ADCON1bits.ADFM=0;//Left justified
69
70
71
ADCON0bits.ADON=1;//Enable ADC
72
}
73
74
voidinitTimer0(){
75
T0CON1bits.T0CS=0b011;//HFINTOSC
76
T0CON1bits.T0CKPS=0b0010;//4 Prescaler
77
T0CON0bits.T016BIT=0;//8bit Timer
78
79
PIR0bits.TMR0IF=0;//Clear overflow interrupt bit
80
81
PIE0bits.TMR0IE=1;//Enable overflow interrupt
82
INTCONbits.GIE=1;//Enable global interrupts
83
84
T0CON0bits.T0EN=1;//Enable Timer 0
85
}
86
87
voidinitDAC(){
88
DAC1CON0bits.DAC1EN=1;//Enable DAC
89
DAC1CON0bits.DAC1OE1=1;//Tie voltage level to DAC1OUT1 pin (RA2)
Max M. schrieb:> for(unsigned char i = 0; i < Ntap; i++){> sum += buffer[i] * coeffs[i];> }
Hast du mal geguckt, wie lange dies Schleife dauert?
> //rotate array> for(unsigned char n = Ntap-1; n > 0; n--)> coeffs[n] = coeffs[n-1];
Wie restaurierst du dein Koeffizientenarray für die nächsten Durchlauf.
In der Schleife wird es schrittweise gnadenlos mit coeffs[0] gefüllt.
Wolfgang schrieb:> Hast du mal geguckt, wie lange dies Schleife dauert?
Hm, irgendwie enttäuschend lange :(
Im Simulator (mit Instruction Freq = 1MHz) ca 1.5ms, bei 32MHz wären das
dann 50us
Wolfgang schrieb:> Wie restaurierst du dein Koeffizientenarray für die nächsten Durchlauf.> In der Schleife wird es schrittweise gnadenlos mit coeffs[0] gefüllt.
Ups, ja das sollte natürlich so aussehen:
Es ist eine schlechte Idee, innerhalb einer isr zu warten:
1
2
voidinterrupt__isr_handler(void){
3
ADCON0bits.GO=1;//Start ADC conversion
4
while(ADCON0bits.GO!=0)//Wait until conversion is done
5
;
Besser ist es, den ADC am Ende der isr zu starten. Bis zum nächsten isr
hast Du dann das nächste Ergebnis ganz ohne warten.
Noch besser ist es, den ADC durch die Hardware selber zu starten, um
einen Jitter auszuschliessen. Ob das bei Deinem PIC (welcher?) möglich
ist, weiss ich nicht.
Viele Grüße, Stefan
Stefan K. schrieb:> Ob das bei Deinem PIC (welcher?) möglich> ist, weiss ich nicht.
Es ist ein PIC16F15376
Also die Musik durchschleifen funktioniert, von daher gehe ich davon
aus, dass Jitter kein Problem ist?
Wenn die Schleife für die Summe der Faktoren 50us braucht, wären nur
noch 20.000 Samples pro Sekunde möglich, der Timer läuft aber mit
31.000, daher hab ich das nun mit einem Prescaler von 8 auf 15.700
reduziert, damit sollte eigentlich jedes Sample erwischt werden, oder?
Ich bin mir nicht sicher, was ich mit der Summe mache, da der DAC nur
5bit benutzt, muss ich im Prinzip den long Wert um 27 Stellen nach
rechts schieben, um die 5 MSBs zu erwischen, oder (ein long hat 32 Bit:
http://www.hobbytronics.co.uk/tutorials-code/tutorials-microchip/c18-data-types)?
Ich verstehe auch nicht, warum mir WinFilter erzählt, man müsse die
Summe durch 128 teilen?
Stefan K. schrieb:> Noch besser ist es, den ADC durch die Hardware selber zu starten, um> einen Jitter auszuschliessen. Ob das bei Deinem PIC (welcher?) möglich> ist, weiss ich nicht.
-> Data Sheet 20.2.5 AUTO-CONVERSION TRIGGER
Da bekommt/nutzt man dann den IR, wenn der Wert fertig zum abholen
ist...
Volker S. schrieb:> -> Data Sheet 20.2.5 AUTO-CONVERSION TRIGGER> Da bekommt/nutzt man dann den IR, wenn der Wert fertig zum abholen> ist...
Hm ich weiß nicht ob es tatsächlich ein Problem ist aber ich sehe da
erstmal eines, und zwar hat dieser PIC nur einen Interrupt Vector, d.h.
ich müsste in der IR erstmal prüfen, woher der Interrupt kommt und ggf
verpasse ich dann einen Sample wenn mit dem Timer0 Overflow die ADC
Conversion getriggert wird?
Moin,
Mal so ganz allgemein: Solche Geschichten wuerd' ich nicht auf solchen
Prozessoren in C machen. Oder hoechstens dann. wenn man sich sehr genau
anguckt, was der Compiler draus fuer Assembler macht und wie lange das
dann in der Ausfuehrung dauert (was macht denn z.B. der Compiler aus der
"unsigned char" * "int" Multiplikation).
Mein olles VU-Meter aufm Attiny13a hatte ich mal ganz kurz in C
angefangen und hab's nach Blicken in die .o files schnell wieder sein
lassen und bin auf Assembler umgestiegen...
Gruss
WK
Dergute W. schrieb:> Mal so ganz allgemein: Solche Geschichten wuerd' ich nicht auf solchen> Prozessoren in C machen.
Genau so sieht's aus. Denn hier bringt der Einsatz von C exakt NULL
Vorteile, nur einen Haufen Nachteile, von denen der Schlimmste halt ist,
dass man nicht einmal gut genug abschätzen kann, ob das System überhaupt
noch den Durchsatz schaffen kann, das muss man erst messen oder
alternativ das Compilat disassemblieren und dann dort die Takte
zählen...
Von den Latenzen mal ganz zu schweigen. Denn die können, selbst wenn der
Durchsatz theoretisch noch recht solide passt, immer noch dafür sorgen,
dass nur Gülle rauskommt. Das ist natürlich ein Problem, was man in Asm
genauso hat, aber da hat man eben auch quasi direkt die nötigen
Informationen, um zu erkennen, an welcher Stelle man drehen muss, um die
Sache insgesamt doch noch passend zu machen. Denn dabei geht es
eigentlich nur noch um "Umverteilung" von Rechenzeit. Dazu muss man aber
im Detail wissen, was GENAU welche Rechenzeit benötigt. Und bei sowas
ist eine Hochsprache so nützlich wie ein Loch im Kopf, wenn schon die
nächste Version des verschissenen Compilers oder eine andere Einstellung
der Optimierung katastrophal abweichende Kompilate ergeben kann...
Nö, für alles wirklich Zeitkritische gibt's nur eins: Asm. Wer das nicht
begreift, ist ein Idiot.
c-hater schrieb:> Nö, für alles wirklich Zeitkritische gibt's nur eins: Asm. Wer das nicht> begreift, ist ein Idiot.
Ich hab das Projekt vom TE als Studienarbeit gemacht, in C. Erfolgreich.
Man muss halt wissen was man tut.
THOR schrieb:> Ich hab das Projekt vom TE als Studienarbeit gemacht, in C. Erfolgreich.
Dann war's wohl nicht wirklich zeitkritisch... Bei Übungsaufgaben für
zukünftige C-dioten kann man wohl nicht damit rechnen, dass eine Aufgabe
gestellt wird, die in C (allein) tatsächlich nicht zu lösen ist (in Asm
aber schon)...
Wenn ich das in ASM mach, hab ich Angst vor 32-bit Multiplikation und
die 2er Komplement-Sache :(
THOR schrieb:> Man muss halt wissen was man tut.
Wie bei so ziemlich allen Sachen, ich weiß nicht, warum es nicht
funktioniert, eigentlich dachte ich, ich hätte es verstanden.
Moin,
Hm, kanns sein, dass der Apparat gar keinen HW-Multiplizierer hat?
Das waeren nicht grad' die besten Voraussetzungen um da lustige FIRs mit
beliebig "krummen" Koeffizienten laufen zu lassen. Auch nicht in asm.
Gruss
WK
Dergute W. schrieb:> Hm, kanns sein, dass der Apparat gar keinen HW-Multiplizierer hat?> Das waeren nicht grad' die besten Voraussetzungen um da lustige FIRs mit> beliebig "krummen" Koeffizienten laufen zu lassen. Auch nicht in asm.
Ja, der kann nur Addieren und Subtrahieren...
Max M. schrieb:> ich müsste in der IR erstmal prüfen, woher der Interrupt kommt und ggf> verpasse ich dann einen Sample wenn mit dem Timer0 Overflow die ADC> Conversion getriggert wird?
Du hast doch dann wieder nur eine IR Quelle, nämlich den vom ADC.
Den TIMERx IR aktivierst du natürlich nicht!
(Es ist doch völlig uninteressant, zu welchem Zeitpunkt die Wandlung
gestartet wird)
PS: Falls du XC8 Free verwendest und die IR Latenz immer noch so grottig
ist, wie bei den ersten Versionen, dann solltest du dir das anschauen:
http://www.microchip.com/forums/FindPost/753619
Moin,
Max M. schrieb:> Ja, der kann nur Addieren und Subtrahieren...
Ojojoj, dann wirds sehr ambitioniert.
Mal so als Pi*Daumen ein paar Werte, mit denen ich beim atmega (und der
hat einen Multiplizierer) rechne - aber eben auf Assemblerbasis:
z.B. Takt: 16MHz; Abtastrate DAC: 32KHz -> Macht also 500 Takte Zeit pro
Sample.
Ausschnitte aus einem FIR:
1
;
2
ldi r18, 9 ;1
3
ldd r19, Y+2 ;2
4
mulsu r19,r18 ;2
5
sub r14,r0 ;1
6
sbc r15,r1 ;1
7
ldd r19, Y+12 ;2
8
mulsu r19,r18 ;2
9
sub r14,r0 ;1
10
sbc r15,r1 ;1
11
12
...
13
14
ldd r14,Y+2; ;2
15
st Y+,r14; ;2
16
ldd r14,Y+2; ;2
17
st Y+,r14; ;2
18
ldd r14,Y+2;
19
st Y+,r14;
20
ldd r14,Y+2;
Das sind 2 MAC Operationen (mit dem selben Koeffizienten (9 in R18)) und
die Schieberei der Samples. Dafuer brauch' ich also 13+8=21 Takte. Also
ueber 10 Takte fuer ein FIR-Tap. Also krieg' ich nur deutlich <50 Taps
hin - es muss ja auch noch irgendwas anderes gemacht werden als MACs und
Sampleschiebereien. Und dabei hab' ich schon alle loops un-ge-rollt
(wenn einer noch was weiss zum Zyklensparen - immer her damit)...
Wenn du keinen Multiplizierer hast, musst du unbedingt die
Multiplikationen vermeiden, bzw. hoechstens welche mit Zweierpotenzen -
und dann in C auf den Compiler hoffen...
Gruss
WK
Ich hab gemessen (im Simulator), dass die Schleife für 20 Taps 50us
dauert, d.h. ich kann maximal mit 20kHz samplen, da es keinen adäquaten
Prescaler für den Timer gibt, bin ich bei 32MHz / (255 * 8) = 15686 kHz,
damit hab ich wohl genügend Zeit zwischen 2 Samples. Wenn ich das nun
richtig verstanden habe, kann ich damit maximal Frequenzen bis 15686 / 2
= 7.84kHz messen?
Vielleicht generiert mir WinFilter auch die falschen oder für mein
Problem nicht passende Koeffizienten?
Edit: Okay, ich hab nochmal gemessen: Die Summen-Schleife zusammen mit
der Rotier-Schleife benötigt bei 1MHz Taktfrequenz (anscheinend kann der
Simulator keine 32MHz simulieren da rechts unten immer "Instruction Freq
= 1MHz" steht) und 5 Taps 573us, das reicht für 10 Taps bei 32MHz aus,
besonders für einen einfachen Bandpass, wie ich in gerade erstellt hab,
oder?
Max M. schrieb:> Ich hab gemessen (im Simulator), dass die Schleife für 20 Taps 50us> dauert
Dann guck doch mal, was passiert, wenn du dem Compiler verrätst, dass
deine Koeffizienten in Wirklichkeit nur 8 Bit habe. Vielleicht hat er
dafür eine passendere Multiplikation in der Hinterhand.
Max M. schrieb:> (anscheinend kann der> Simulator keine 32MHz simulieren da rechts unten immer "Instruction Freq> = 1MHz" steht)
Das kann/muss man einstellen...
Moin,
Bei der Simulation sollten auch irgendwelche "echten" Daten verrechnet
werden; ich schaetz' mal stark, dass die Multiplikationsroutinen je nach
Zahlen unterschiedlich lange dauern.
Ob deine Filterkoeffizienten passen? Keine Ahnung - aber im ersten Post
ist das Filter nicht symmetrisch, da fehlt einmal -2 Soll das so?
So auf die Schnelle ein 21 Tap FIR Bandfilter fuer 15kHz Sampling
frequenz und 3 und 6 kHz Bandgrenzen wuerd ich das vorschlagen:
[ -1 2 11 -13 -4 -2 7 40 -61 -29 100 -29
-61 40 7 -2 -4 -13 11 2 -1]
Das macht eine Verstaerkung von 256 im Durchlassbereich, d.h. da muss
man nicht mehr viel Schmerzen in eine Division stecken.
Gruss
WK
Max M. schrieb:> Edit: Okay, ich hab nochmal gemessen: Die Summen-Schleife zusammen mit> der Rotier-Schleife benötigt bei 1MHz Taktfrequenz (anscheinend kann der> Simulator keine 32MHz simulieren da rechts unten immer "Instruction Freq> = 1MHz" steht) und 5 Taps 573us, das reicht für 10 Taps bei 32MHz aus,> besonders für einen einfachen Bandpass, wie ich in gerade erstellt hab,> oder?
Warum nimmst Du keinen dsPIC oder PIC32? Die sind deutlich geeigneter
für Dein Vorhaben. ZB dsPIC33FJ64GP802 mit Codec (I2S) Interface und 14
Bit Stereo Audio DAC.
Oder geht es nicht um das Ziel, sondern darum, die Zeit sinnlos
totzuschlagen?
fchk
Frank K. schrieb:> Oder geht es nicht um den Weg, sondern darum, die Zeit sinnlos> totzuschlagen?
Solange Zeit für leere ADC-Ready Warteschleifen in der ISR ist ...
Zumindest könnte man sich im Betrieb mal die Aufenthaltszeit in der ISR
auf einen Pin legen und mit real streuenden Daten die ISR-Auslastung
nachmessen.
Wolfgang schrieb:> Dann guck doch mal, was passiert, wenn du dem Compiler verrätst, dass> deine Koeffizienten in Wirklichkeit nur 8 Bit habe.
Hm ich versteh nicht ganz?
Ich hab mal einen Test gemacht:
1
unsignedcharbuffer[Ntap]={127,64,255,87,50};
2
charcoeffs[Ntap]={-3,7,-31,-9,83,};
Die erste Multiplikation 127 * (-3) = -381 = 1111 1110 1000 0011
(0xFE83), wenn ich das im Simulator mache:
ADC schrieb:> Zumindest könnte man sich im Betrieb mal die Aufenthaltszeit in der ISR> auf einen Pin legen und mit real streuenden Daten die ISR-Auslastung> nachmessen.
1
voidinterrupt__isr_handler(void){
2
PORTAbits.RA0=1;
3
4
buffer[0]=ADRESH;
5
intsum=0;
6
for(unsignedchari=0;i<Ntap;i++){
7
intresult=buffer[i]*coeffs[i];
8
sum+=result;
9
}
10
11
DAC1CON1=sum>>11;
12
//DAC1CON1 = ADRESH>>3;
13
14
for(unsignedcharn=Ntap-1;n>0;n--)
15
buffer[n]=buffer[n-1];
16
17
ADCON0bits.GO=1;
18
19
PIR0bits.TMR0IF=0;//Clear interrupt flag
20
21
PORTAbits.RA0=0;
22
}
Irgendwie unerwartet lange? Ich versteh gar nichts mehr :(
Moin,
Ich bin da nicht so ganz sattelfest, aber ich vermute mal stark, dass in
C bei einer char*char Multiplikation auch nur wieder ein char rauskommt
und nicht automatisch ein (u)int16_t.
Gruss
WK
Dergute W. schrieb:> Moin,>> Ich bin da nicht so ganz sattelfest, aber ich vermute mal stark, dass in> C bei einer char*char Multiplikation auch nur wieder ein char rauskommt> und nicht automatisch ein (u)int16_t.>> Gruss> WK
Vielen Dank für den Hinweis, das stimmt tatsächlich, so kommt das
richtige Ergebnis raus:
Moin,
Max M. schrieb:> Irgendwie unerwartet lange? Ich versteh gar nichts mehr :(
Nee, das koennte schon hinhauen. So grob uebern Daumen gepeilt brauchst
du bei einer 8x8 Multiplikation ja 8x schieben, 8x gucken, ob's carry
gesetzt ist, ggf. addieren und Ergebnis schieben. Je nach Assembler
kommt man da bei entsprechend bloeden Zahlen locker auf 30..50 Takte.
Fuer eine einzige, popelige 8x8 Multiplikation...
Gruss
WK
Das ist irgendwie ernüchternd...
Ich versteh auch grad meinen Timer nicht mehr, ich hab den jetzt so
konfiguriert:
1
T0CON1bits.T0CS=0b011;//HFINTOSC
2
T0CON1bits.T0CKPS=0b0100;//16 Prescaler
3
T0CON0bits.T016BIT=0;//8bit Timer
4
5
PIR0bits.TMR0IF=0;//Clear overflow interrupt bit
6
7
PIE0bits.TMR0IE=1;//Enable overflow interrupt
8
INTCONbits.GIE=1;//Enable global interrupts
9
10
T0CON0bits.T0EN=1;//Enable Timer 0
Der Prozessor läuft mit 32MHz, durch den 1:16 Prescaler läuft der Timer
mit 2MHz, mit jedem Takt wird das 8-bit Register inkrementiert, bei 255
auf "256" findet ein Überlauf und der Interrupt statt, also alle
0.1275ms findet ein Interrupt statt, oder? Weil 32*10^6MHz / (255 * 16)
= 7843Hz, also alle 0.1275ms (oder 127.5us)?
Wenn ich in der Interrupt-Routine nur den Pin A0 ein und wieder
ausschalte, messe ich allerdings den Anhang mit Saleae Logic?
Servus,
hier mal ein paar Sachen, die mit so beim Überfliegen des Threads
aufgefallen sind:
- Die Taktfrequenz-Einstellung im Simulator ist per Default auf 1 MHz,
lässt sich aber in den Projekt-Einstellungen ändern: (vor dem Start des
Debugging, sonst sind die Einstellungen gelockt) Project
Properties->Conf.->Simulator,
Auswahl "Oscillator Options". Dort aber dann nicht die Clock-Frequenz
=32 MHz einstellen, sondern die Instruction Cycle Frequenz, die ist bei
Deinem PIC Fosc/4, also bei 32 MHz Clock dann 8 MHz.
- Dein Timer0 bzw. dessen Prescaler läuft auch nicht mit der
Oszillatorfrequenz, sondern mit der Instruction Cycle Frequenz (Fcyc) =
Fosc/4 = 8 MHz.
Max M. schrieb:> Im Simulator (mit Instruction Freq = 1MHz) ca 1.5ms, bei 32MHz wären das> dann 50us
Deine Rechnung auf 50 µs scheint mir ein Irrtum zu sein. Ich würde mit
1,5ms/8, also knapp unter 200µs rechnen.
Also um mal ganz ehrlich zu sein:
Mit diesem mc wirst kein auch nur annähernd zufriedenstellendes Ergebnis
bekommen:
* 8 Bit ADC ist viel zu wenig, selbst die allererste Digital-Telefonie
setzte bereits auf 10 Bit.
* 5 Bit DAC sind unterirdisch, selbst wenn das Signal hervorragend
ausgesteuert wäre.
* Ein 8 Bit PIC ohne HW Multiplier benötigt für Dein FIR Filter viel
zu lange.
Von so Sachen wie Analogfilter vor dem ADC und nach dem DAC, Jitter etc.
müssen wir da gar nicht erst reden.
Dieser mc ist für kleine Steuerungen gedacht und in diesem Bereich
sicher ganz gut, für Deine Anwendung taugt er leider nicht.
Gruß, Stefan
Stefan K. schrieb:> Also um mal ganz ehrlich zu sein:> Mit diesem mc wirst kein auch nur annähernd zufriedenstellendes Ergebnis> bekommen:>> * 8 Bit ADC ist viel zu wenig, selbst die allererste Digital-Telefonie> setzte bereits auf 10 Bit.> * 5 Bit DAC sind unterirdisch, selbst wenn das Signal hervorragend> ausgesteuert wäre.> * Ein 8 Bit PIC ohne HW Multiplier benötigt für Dein FIR Filter viel> zu lange.>> Von so Sachen wie Analogfilter vor dem ADC und nach dem DAC, Jitter etc.> müssen wir da gar nicht erst reden.>> Dieser mc ist für kleine Steuerungen gedacht und in diesem Bereich> sicher ganz gut, für Deine Anwendung taugt er leider nicht.>> Gruß, Stefan
Schließe mich an.
Mein Vorschlag ist ein PIC32MX, einige haben nämlich I2S in Hardware.
Dazu benötigt man noch I2S ADC und DAC.
Ich schlage mal folgenden Typen vor: PIC32MX150F128B:
https://www.reichelt.de/PIC-32-Controller/32MX150F128B-ISP/3/index.html?ACTION=3&LA=446&ARTICLE=121326&GROUPID=4509&artnr=32MX150F128B-ISP&SEARCH=PIC32MX150
Es gibt ihn im THT-Bastler-freundlichen DIL-Gehäuse, man kann ihn bei
Reichelt kaufen, 2xI2S in Hardware und DMA (sehr nützlich für Audio!)
ist mit drin.
Programmieren kannst du ihn wie gewohnt mit MPLABX und einem PICkit3,
der Umstieg vom 8-Bit-PIC ist einfacher als du denkst - viele Konzepte
sind gleich, bis hin zu den Registern.
Du musst ledigleich den XC32 installieren.
Ich habe schon einen UDA1334 an einem PIC32MX470 betrieben (MP3 und
WAV-Widergabe mit 16-Bit-Stereo, 44,1kHz). Die Qualität ist
hervorragend.
Moin,
Hmm, ueber Nacht nochmal um den Faktor 4 langsamer geworden. Naja,
irgendwie kann ich meine Vorredner da schon verstehen.
Ich mach' den Kram auf'm AVR ja auch nur in dem vollen Bewusstsein, dass
das eigentlich keine Platform fuer DSP ist.
Man wird auch auf dem Prozessor ein FIR ans Laufen kriegen, aber der
Code dafuer wird voellig anders (unuebersichtlich und unintuitiv und
ohne Schleifen) aussehen. Also eher nix, um mal erste Gehversuche mit
digitalen Filtern zu machen.
Gruss
WK
Stefan K. schrieb:> 8 Bit ADC ist viel zu wenig, selbst die allererste Digital-Telefonie> setzte bereits auf 10 Bit.
Also der uC hat einen 10bit ADC aber ich weiß nicht, in wiefern es was
bringt, die letzte 2 Bit noch mit zu speichern wenn der DAC eh nur 5bit
hat? Da würde ich dann nur wieder ein int-Array benötigen und das dauert
dann wieder länger bei Multiplikation.
Stefan K. schrieb:> Ein 8 Bit PIC ohne HW Multiplier benötigt für Dein FIR Filter viel> zu lange.
Ja, das sehe ich nun auch :(
Stefan K. schrieb:> Dieser mc ist für kleine Steuerungen gedacht und in diesem Bereich> sicher ganz gut, für Deine Anwendung taugt er leider nicht.
Es ging mir in erster Linie nicht darum, ob das Ergebnis gut oder
zufriedenstellend wird, sondern das es überhaupt funktioniert bzw.
machbar ist.
Thomas E. schrieb:> Dein Timer0 bzw. dessen Prescaler läuft auch nicht mit der> Oszillatorfrequenz, sondern mit der Instruction Cycle Frequenz (Fcyc) => Fosc/4 = 8 MHz.
Wirklich? Ich hab den Timer so konfiguriert:
1
T0CON1bits.T0CS=0b011;//HFINTOSC
Fosc/4 wäre 0b010
Trotzdem verstehe ich nicht, wie ich nun auf die Anzahl der
Overflow-Interrupts pro Sekunde komme, da das gemessene nicht mit meiner
Rechnung übereinstimmt.
Max M. schrieb:> Trotzdem verstehe ich nicht, wie ich nun auf die Anzahl der> Overflow-Interrupts pro Sekunde komme, da das gemessene nicht mit meiner> Rechnung übereinstimmt.
Wenn die Abarbeitung des Codes im IR noch nicht beendet ist, wenn ein
neuer IR käme, dann kommt der eben erst, wenn der vorherige fertig ist.
Kommentiere doch mal die ganzen Berechnungen aus und setzt nur den Pin.
Dann schau nochmal.
Stefan K. schrieb:> 8 Bit ADC ist viel zu wenig, selbst die allererste Digital-Telefonie> setzte bereits auf 10 Bit.
Klar, daß der µC für die o.a. Aufgabe nicht geeignet ist, ist natürlich
richtig. Allerdings hat er tatsächlich einen 10-Bit ADC.
Stefan K. schrieb:> 5 Bit DAC sind unterirdisch, selbst wenn das Signal hervorragend> ausgesteuert wäre.
Den könnte man durch eine der reichlich vorhandenen 10-Bit PWMs
ersetzen.
Dann wäre auch die Ausgabe nicht mehr ganz so unterirdisch.
(in meiner Jugend galt eine Dynamik von 60 dB schon als "HiFi", wenn ich
mich recht erinnere...)
Freilich, die Rechenpower ist und bleibt u.a. durch fehlenden
HW-Multiplizierer beschränkt. Sinn macht das Projekt mit so einem
Controller durchzuziehen also nur als sportliche Herausforderung, es
trotzdem hinzubekommen (mit ASM?), in einer angemessenen Qualität.
c-hater schrieb:> Nö, für alles wirklich Zeitkritische gibt's nur eins: Asm. Wer das nicht> begreift, ist ein Idiot.
Das ist jetzt aber ein bischen dolle... ich würde sogar sagen, wenn es
wirklich zeitkritisch ist, gibt's nicht anderes als ein kleines FPGA.
Schneller geht nicht mehr!
Max M. schrieb:> die Musik, die rauskommt, hört sich aber> fast nicht mehr wie Musik an :(
8Bit ADC und 5Bit DAC kann man auch nicht mehr wirklich als Musik
bezeichnen.
BTW, bist du Student? Dann würde ich das ganze ev. mal mit Matlab und
Simulink anschauen. Daten direkt über Simulink aufzeichnen und dann auf
dem PC rechnen. Dann kannst du dein System abstimmen, aber ich denke mit
dieser HW wird das nichts!
Max M. schrieb:> Volker S. schrieb:>> Kommentiere doch mal die ganzen Berechnungen aus und setzt nur den Pin.>> Dann schau nochmal.>> Hab ich, siehe Beitrag "Re: FIR Filter auf PIC"> Wenn ich in der Interrupt-Routine nur den Pin A0 ein und wieder> ausschalte, messe ich allerdings den Anhang mit Saleae Logic?
Sorry, habe ich übersehen ;-)
Hast du vielleicht auch das Löschen des IR-Flags raus genommen?
(Dann wäre das was man da sieht die Latenz des IR ;-)
Patrick B. schrieb:> BTW, bist du Student? Dann würde ich das ganze ev. mal mit Matlab und> Simulink anschauen. Daten direkt über Simulink aufzeichnen und dann auf> dem PC rechnen. Dann kannst du dein System abstimmen, aber ich denke mit> dieser HW wird das nichts!
Bin ich und ich hab auch Zugang zu Matlab, wie läuft das Aufzeichnen ab?
Den Analog-Wert per UART an den PC schicken? Hab mit Matlab leider noch
gar nichts gemacht, das kommt erst in den nächsten Semestern, aber hab
jetzt auch genügend Zeit um mich da einzuarbeiten :D
Volker S. schrieb:> Hast du vielleicht auch das Löschen des IR-Flags raus genommen?
Hab ich tatsächlich, oh :( 'in Boden versink'
Max M. schrieb:> Thomas E. schrieb:>> Dein Timer0 bzw. dessen Prescaler läuft auch nicht mit der>> Oszillatorfrequenz, sondern mit der Instruction Cycle Frequenz (Fcyc) =>> Fosc/4 = 8 MHz.>> Wirklich? Ich hab den Timer so konfiguriert:> T0CON1bits.T0CS = 0b011; //HFINTOSC
Ups - sorry, hast Recht, der Timer0 ist offenbar modernisiert worden
und man kann bei dem Controller nun auch tatsächlich den Oszillator
direkt als Clock-Source benutzen! Hätte ich mir wohl besser genauer
angucken sollen...
Max M. schrieb:> Bin ich und ich hab auch Zugang zu Matlab, wie läuft das Aufzeichnen ab?> Den Analog-Wert per UART an den PC schicken? Hab mit Matlab leider noch> gar nichts gemacht, das kommt erst in den nächsten Semestern, aber hab> jetzt auch genügend Zeit um mich da einzuarbeiten :D
Da gibt es mehrere Varianten:
1 (und einfachste)) In Simulink eine Audio-Quelle hinzufügen (wird
meistens dein Mikrofon des PC sein), FIR-Filter-Block mit deinen
Koeffizienten, und als Ausgabe kannst du auf einen Lautsprecher gehen.
Parallel dazu kannst du die Daten in Workspace-Variablen speichern, und
diese dann in Matlab wieder verwenden. So kannst du dort FFT, Plots etc.
machen.
So könntest du den Unterschied zwischen 16Bit, 12Bit oder 8Bit Rohdaten
sofort erkennen, und was sie für eine Auswirkung auf das ganze System
haben. Das selbe gilt natürlich auch für den Ausgang, hier kannst du die
Auflösung auch wieder entsprechend deiner HW reduzieren.
2) Manche Hersteller bieten für Matlab/Simulink Plugins oder
Bibliotheken an, damit man ihre Devices direkt ansteuern kann. Wenn du
ein entsprechendes Board hast, kannst du hier analog zu Variante 1
einfach die Quelle anpassen. Stichwort "Processor in the Loop".
3) Daten über UART an PC senden und in XLS oder CSV speichern. Das
kannst du dann bequem in Matlab einlesen und wieder nach Lust und Laune
bearbeiten.
Im "realen" Leben würde ich beim Entwickeln auch so vorgehen: Daten mit
der HW aufzeichnen (also Variante 2 oder 3) und dann meine Algorithmen
auf dem PC mit der Double berechnen lassen. Parallel kannst du dann
einen HW-Optimierten Pfad aufbauen (z.B. wenn du ein FPGA nutzt mit
Fix-Punkt Werten) um die nötigen Bit-Breiten bei jeder Stelle zu
analysieren und am Schluss den Fehler mit der "idealen" Umgebung
abzugleichen. Bei korrektem Vorgehen hast du am Schluss deine Schaltung
wirklich begriffen und weisst was passiert, wenn du an irgend einem Ort
etwas änderst -> Optmierungsvorschläge machen
Hier findest du ein paar Infos:
https://ch.mathworks.com/help/audio/examples.htmlhttps://ch.mathworks.com/de/products/dsp-system.htmlhttps://ch.mathworks.com/help/simulink/ug/tutorial-integrating-matlab-code-with-a-simulink-model-for-filtering-an-audio-signal.htmlhttps://ch.mathworks.com/help/dsp/ref/fromaudiodevice.html
BTW: Matlab/Simulink unterstützt direkte Code-Generierung (ok, sieht
nicht immer super lesbar aus, aber funktioniert perfekt). Bei einem FPGA
kannst du auch VHDL Files erstellen lassen. Und falls du Xilinx hast,
kannst du mittels System Generator in Simulink die optimierten
Xilinx-Blöcke verwenden und auf deine Ziel-HW compilieren (hat mir bei
meiner Bachelor-Arbeit sehr geholfen!).
Vielen Dank, Patrick! Ich denke, in die Matlab Welt muss ich mich noch
einarbeiten. Was mich aber interessieren würde: Kann ich die
eingelesenen ADC-Daten, die ich dann als CSV in Matlab importiere und
mit einem FIR-Filter belege, auch wieder ausgeben? Als gibt es da sowas
wie einen DAC Output-Block? Das wäre natürlich genial :D
Ich hab die Messwerte des ADC nun in eine CSV Datei des folgenden
Formats übertragen (so will es Matlab anscheinend:
https://de.mathworks.com/help/simulink/slref/fromspreadsheet.html):
aufsteigendeNummer;Messwert
...
Dazu hab ich den "From Spreadsheet" Block benutzt, zur Ausgabe einen
"Audio Device Writer" Block, mein Timer hat einen Prescaler von 8, d.h.
eine Samplerate von ca. 31400Hz, das hab ich auch in dem Audio Device
Writer eingestellt, ich hab 62800 Samples gespeichert, d.h. 2s Audio.
Ich hab das mit einem C#-Programm gemacht, das Ganze hat allerdings ca.
5s zum Aufzeichnen gedauert (für 62800 Samples), jetzt weiß ich nicht,
ob Windows intern einen Puffer für die serielle Schnittstelle hat oder
ob mein PC nicht so schnell aufzeichnen kann, wie gesendet wird (Baud
Rate: 230400)?
Wenn ich mir das nun anhöre über Simulink, hör ich nur Geknacke und
erkenn die Musik überhaupt nicht mehr, als ob das was komplett anderes
wäre? Was hab ich falsch gemacht?
Max M. schrieb:> Ich denke, in die Matlab Welt muss ich mich noch> einarbeiten
Tja, diese Welt ist gross, aber sehr sehr interessant. Und um ehrlich zu
sein vermisse ich Matlab in meinem Betrieb schon...
Aber ich denke du wirst es im Studium noch lieben lernen.
> Ich hab das mit einem C#-Programm gemacht, das Ganze hat allerdings ca.> 5s zum Aufzeichnen gedauert (für 62800 Samples), jetzt weiß ich nicht,> ob Windows intern einen Puffer für die serielle Schnittstelle hat oder> ob mein PC nicht so schnell aufzeichnen kann, wie gesendet wird (Baud> Rate: 230400)?
Kommt ganz auf dein Format/Protokoll drauf an. Mit dieser Baudrate
könntest du ~23040 Bytes/s (je nach UART Einstellungen) übertragen ->
was für Rohdaten schon zu langsam ist. Hast du aber ein Printf drin und
formatierst die Zahlen als String, wird das halt noch länger dauern...
Voraussetzung ist, dass du die Daten auf dem Prozessor zwischenspeichern
kannst.
> Wenn ich mir das nun anhöre über Simulink, hör ich nur Geknacke und> erkenn die Musik überhaupt nicht mehr, als ob das was komplett anderes> wäre? Was hab ich falsch gemacht?
Mhm, sind deine Zahlen im CSV irgendwie formatiert? Matlab/Simulink
rechen jeweils mit double.
Ich habe rasch ein Beispiel zusammegeklickt, indem ich das Mikrofon als
Quelle benutze, dann den originalen FIR-Block und direkt auf die
Lautsprecher. Zusätzlich noch ein Scope zur visualisierung. Die Daten
könntest du in Matlab wiederum für Plots verwenen (musst sie aus dem
Objekt extrahieren):
1
Input = RawData.Data;
2
Output = FilteredData.Data;
So hast du dann direkt die Vektoren wieder.
Kannst ja mal mit dem Beispiel spielen und die Zahlenwerte jeweils
vergleichen (glaube der Lautsprecher benötigt Werte von -1 bis 1).
Eventuell ist hier das Problem.
Patrick B. schrieb:> Kommt ganz auf dein Format/Protokoll drauf an. Mit dieser Baudrate> könntest du ~23040 Bytes/s (je nach UART Einstellungen) übertragen ->> was für Rohdaten schon zu langsam ist. Hast du aber ein Printf drin und> formatierst die Zahlen als String, wird das halt noch länger dauern...> Voraussetzung ist, dass du die Daten auf dem Prozessor zwischenspeichern> kannst.
Ich hab das mit UART gemacht und die 8 MSBs des ADCs gesendet, das ist
meine ISR:
1
voidinterrupt__isr_handler(void){
2
TX2REG=ADRESH;//Send 8-bit Data
3
ADCON0bits.GO=1;//Start new ADC conversion
4
PIR0bits.TMR0IF=0;//Clear interrupt flag
5
}
Mit Saleae Logic gemessen feuert die ISR in einem Takt von 31.4kHz, also
31.4kByte pro Sekunde, da sind 230400 Baud vllt. dann tatsächlich knapp,
hab ich nun auf 460.800 Baud erhöht, jetzt dauert das Aufzeichnen von
3*31400 Bytes auch ziemlich genau 3s (2993ms)!
Patrick B. schrieb:> Mhm, sind deine Zahlen im CSV irgendwie formatiert? Matlab/Simulink> rechen jeweils mit double.
Ich hab in der ersten Spalte eine aufsteigende Nummer (der Block "From
Spreadsheet" benötigt das anscheinend), dann ein Semikolon als
Trennzeichen und in einer zweiten Spalte die gemessenen Werte vom ADC.
Patrick B. schrieb:> Ich habe rasch ein Beispiel zusammegeklickt
Vielen Dank dafür, werde ich mir mal genauer anschauend. Trotzdem wäre
es interessant zu wissen, wie ich das Mikrofon durch meine CSV Datei
ersetzen kann.
Patrick B. schrieb:> (glaube der Lautsprecher benötigt Werte von -1 bis 1).> Eventuell ist hier das Problem.
Im Block "To Audio Device" kann man in der Zeile "Device data type" auch
"8-bit Integer" auswählen?
Max M. schrieb:> Vielen Dank dafür, werde ich mir mal genauer anschauend. Trotzdem wäre> es interessant zu wissen, wie ich das Mikrofon durch meine CSV Datei> ersetzen kann.
Ich habe leider nur Matlab R2015a, und somit fehlt mir die "From
Spreadsheet" Funktion. Aber die Formatierung im csv sieht gut aus.
Sollte also klappen.
Max M. schrieb:> Ich hab das mit UART gemacht und die 8 MSBs des ADCs gesendet, das ist> meine ISR:
Mhm, sind die Daten "Left aligned"? ansonsten sendest du nur die
obersten 2 Bits (10 und 9 des 10 Bit ADC Wertes).
> Patrick B. schrieb:>> (glaube der Lautsprecher benötigt Werte von -1 bis 1).>> Eventuell ist hier das Problem.>> Im Block "To Audio Device" kann man in der Zeile "Device data type" auch> "8-bit Integer" auswählen?
Ja, sollte auch gehen. Wenn du unter "Display -> Signals & Ports -> Port
Data Types" einschaltest, siehst du auf deinem Schema gleich wo welche
Datentypen sind, und ob du dort einen Fehler hast. Oft merkt Simulink
das zwar selber.
Ich habe rasch deine Daten im Matlab eingelesen und als Plot
dargestellt, und gebe dir recht, dass das nicht wirklich nach Musik
aussieht. Kann es sein dass dein Musik-Signal 0-5V ist und du am ADC das
als Unsigned behandelst?
Wenn ja, dann müstest du zwischen "From Spreadsheet" und deinem nächsten
Element noch ein "Sub-Block" machen, bei dem du 128 abziehst. So
erhällst du dann im restlichen System einen wirklichen signed Wert (-128
bis 128).
Ausserdem sieht es nach einem Fehler zwischen ADC und CSV aus: Ich sehe
keine Werte, die grösser als 128 sind. Hier gehen die Daten in
Sättigung.
Zusätzlich sieht es noch nach einem Übersteuern des ADC aus. Ich würde
die Lautstärke des Ursprungs mahl zurückdrehen. Oder gleich einen
Signalgeni mit definierter Frequenz (z.B. 1kHz, 2.5V Offset und 1Vpp)
nehmen. Dann weisst du auch welche Werte du zu erwarten hast.
Wie sieht dein Aufbau aus? Woher nimmst du die Musik? Kannst du mal ein
Schema posten?
Patrick B. schrieb:> Zusätzlich sieht es noch nach einem Übersteuern des ADC aus.
Wie kommst du darauf? Da das 8-bit Register des ADC eben Werte bis 255
zulässt würde ich eher erwarten, solange keine Werte im Bereich 180 -
250 auftreten, übersteuert der ADC eben nicht?
Patrick B. schrieb:> Wie sieht dein Aufbau aus? Woher nimmst du die Musik? Kannst du mal ein> Schema posten?
Spotify -> Soundkarte (Cinch) -> An Analog Port -> im µC messen ->
Ausgabe am UART Port -> Einlesen am PC mit UART / USB Converter
Patrick B. schrieb:> Kann es sein dass dein Musik-Signal 0-5V ist und du am ADC das> als Unsigned behandelst?
Das ist richtig
Patrick B. schrieb:> Ausserdem sieht es nach einem Fehler zwischen ADC und CSV aus: Ich sehe> keine Werte, die grösser als 128 sind. Hier gehen die Daten in> Sättigung.
Ich hab den Ausgang meiner Soundkarte auf 100% gedreht, wenn ich den
Pegel reduziere, werden die gemessenen Zahlen noch kleiner, ich dachte,
umso höher der Ausgangspegel der Quelle, umso weniger Rauschen /
Messfehler?
Patrick B. schrieb:> Wenn ja, dann müstest du zwischen "From Spreadsheet" und deinem nächsten> Element noch ein "Sub-Block" machen, bei dem du 128 abziehst. So> erhällst du dann im restlichen System einen wirklichen signed Wert (-128> bis 128).
Wenn ich das wie im Anhang mache, bekomme ich die Meldung:
"Error in 'FIRFilter/Audio Device
Writer': The block input must be a uint8, int16, int32, or
floating-point data type."
Also doch unsigned?
Dein "To Audio Device" finde ich im Library Browser nicht :(
Ich bin mir auch unsicher, was ich im Feld "Sample Time" von "From
Spreadsheet" eingeben soll, ist das 1 / 31400?
Dergute W. schrieb:> Ich bin da nicht so ganz sattelfest, aber ich vermute mal stark, dass in> C bei einer char*char Multiplikation auch nur wieder ein char rauskommt> und nicht automatisch ein (u)int16_t.
Wenn das so wäre (es ist aber nicht so!) dann wäre das Ergebnis zwar
hübsch klein, aber auch völlig sinnlos, jedenfalls in der weit
überwiegenden Zahl der möglichen Fälle...
Max M. schrieb:> Patrick B. schrieb:>> Zusätzlich sieht es noch nach einem Übersteuern des ADC aus.>> Wie kommst du darauf? Da das 8-bit Register des ADC eben Werte bis 255> zulässt würde ich eher erwarten, solange keine Werte im Bereich 180 -> 250 auftreten, übersteuert der ADC eben nicht?
Ja, aber so wie die Daten aussehen...
> Patrick B. schrieb:>> Wie sieht dein Aufbau aus? Woher nimmst du die Musik? Kannst du mal ein>> Schema posten?>> Spotify -> Soundkarte (Cinch) -> An Analog Port -> im µC messen ->> Ausgabe am UART Port -> Einlesen am PC mit UART / USB Converter
Mhm, die Soundkarte gibt dir irgendwas +-V aus. Wenn der ADC Eingang
ganz normal aufgebaut ist, wirst du hier mit den negativen Spannungen
Probleme bekommen.
Oder hast du eine OP Amp Schaltung mit kapazitiver einkopplung, damit du
dein 0V Soundsignal bei 2.5V des ADC zu liegen kommt.
> Patrick B. schrieb:>> Wenn ja, dann müstest du zwischen "From Spreadsheet" und deinem nächsten>> Element noch ein "Sub-Block" machen, bei dem du 128 abziehst. So>> erhällst du dann im restlichen System einen wirklichen signed Wert (-128>> bis 128).>> Wenn ich das wie im Anhang mache, bekomme ich die Meldung:
Ok, da kommen diverse Datentypen zusammen. Wechsle mal beim deiner
Konstante auf einen Int16. Zusätzlich einen Convert-Block um deine Werte
aus UInt8 auf Int16 für die Subtraktion umzuwandeln. Falls nötig kannst
du das vor deiner Ausgabe wieder auf Int8 limitieren.
> Dein "To Audio Device" finde ich im Library Browser nicht :(
Wie gesagt, ich habe nur R0215a.
> Ich bin mir auch unsicher, was ich im Feld "Sample Time" von "From> Spreadsheet" eingeben soll, ist das 1 / 31400?
Mhm, ich würde auch 1/31400 verwenden. Zusätzlich würde ich im CSV der
Index in der ersten Spalte auf x*1/31400 ändern. So ists überall gleich
Patrick B. schrieb:> Mhm, die Soundkarte gibt dir irgendwas +-V aus. Wenn der ADC Eingang> ganz normal aufgebaut ist, wirst du hier mit den negativen Spannungen> Probleme bekommen.> Oder hast du eine OP Amp Schaltung mit kapazitiver einkopplung, damit du> dein 0V Soundsignal bei 2.5V des ADC zu liegen kommt.
Hab ich nicht :(
D.h. das kann sowieso nichts werden weil die Soundkarte Wechselspannung
ausgibt?
Max M. schrieb:> D.h. das kann sowieso nichts werden weil die Soundkarte Wechselspannung> ausgibt?
Mach halt einen Kondensator zur DC-Entkoppelung dazwischen (wenn der
nicht sowieso schon in der Soundkarte eingebaut ist) und einen relativ
hochohmigen Spannungsteiler (z.B. 2x10kOhm) vor den AD-Wandler, um hier
den DC-Level auf die halbe Versorgungsspannung zu ziehen.
Ich kann irgendwie nicht ganz nach vollziehen, warum die Soundkarte eine
Wechselspannung ausgeben sollte, wenn doch der Verstärker und der PC mit
Gleichspannung funktionieren?
Was genau verändert da ein Kondensator, wird der in Reihe oder parallel
geschalten?
Als ich das Audio-Signal "durchgeschleift" habe (also die 5 MSBs des
ADCs auf den DAC), hat sich das eigentlich nach dem vollständigen Lied
angehört, nicht so, als ob die Hälfte da wegen Wechselspannung fehlen
würde?
Irgendwie verwirrt mich das gerade :(
Max M. schrieb:> warum die Soundkarte eine> Wechselspannung ausgeben sollte,
damit man etwas hört? Gleichspannung enthält nun mal (fast) keine
Information und auch keine Musik!
Max M. schrieb:> wenn doch der Verstärker und der PC mit> Gleichspannung funktionieren?
Dein Lautsprecher würde sich mit hübschen Rauchzeichen bedanken, wenn
der mit Gleichspannung betriebene Verstärker diese an ihn weitergeben
würde!
Max M. schrieb:> Was genau verändert da ein Kondensator, wird der in Reihe oder parallel> geschalten?
In Reihe! Einfach ausgedrückt, lässt der Kondensator keinen Gleichstrom
durch, denn es fleißt ja nur solange Strom, bis der Kondensator auf die
angelegte Spannung aufgeladen ist. Wechselstrom wird aber (je nach
Frequenz und Größe des Kondensators) mehr oder weniger gut
durchgelassen, weil der Kondensator dabei immer ein wenig ge- und
entladen wird. Deshalb sollte er eine angemessene Kapazität haben, damit
auch die Bässe noch ohne nennenswerte Verluste übertragen werden. Bei
einem Eingangswiderstand von einigen kOhm reichen meist 10µF (-3dB
Grenzfrequenz = 1/(2*PI*R*C)).
Max M. schrieb:> Ich kann irgendwie nicht ganz nach vollziehen, warum die Soundkarte eine> Wechselspannung ausgeben sollte, wenn doch der Verstärker und der PC mit> Gleichspannung funktionieren?
Ups, dann fehlen dir ein paar Grundlagen.
Deine Verstärker auf dem PC werden zwar alle mit DC versorgt, aber das
Audio-Signal ist zwangsläufig ein AC. Lautsprecher vertragen keine DC
Signale.
Ein Lautsprecher ist im Prinzip auch nichts anderes als eine Spule,
welche eine Membran zum schwingen bringt.
Max M. schrieb:> D.h. das kann sowieso nichts werden weil die Soundkarte Wechselspannung> ausgibt?
Wie Thomas schon gesagt hat, muss du nur 3 Elemente hinzufügen damit es
funktioniert.
http://www.avrfreaks.net/sites/default/files/AC%20Coupled%20Op%20Amp.jpg
Hier musst du den Op Amp einfach durch deinen AVR ersetzen. Zudem musst
du bei deinem Soundkarten-Signal darauf achten, dass es <5VPP ist.
Warum eigentlich FIR?
Mit 20 Taps bekommst du doch nur einen krass schlechten Filter hin
(Ripple).
Für Audio sehr empfehlenswert sind daher IIR Filter (BiQuad).
Ein High-Pass bei 1 KHz und ein Low-Pass bei 10 KHz, auch mit 2. oder 4.
Ordnung benötigt bei IIR nur wenige Multiplikationen, hat einen schön
gleichmäßigen Frequenzgang und auch weniger Latenz als FIR.
Patrick B. schrieb:> Hier musst du den Op Amp einfach durch deinen AVR ersetzen
So?
Ich will mir mit einem anderen µC, der einen besseren ADC und DAC hat
(und eine Multiplikationseinheit hat) ein Board dafür designen. Hab mir
da einen aus der EFM8LB1 Serie ausgesucht, hab schon ein Board mit einem
EFM8BB1 erstellt und mit der IDE, dem Compiler und Programmer sehr gute
Erfahrungen gemacht, der EFM8LB1 läuft mit max. 72MHz, 14-bit ADC und
12-bit DAC, zur IDE bekommt man kostenlos eine Lizenz des Keil 8051
C-Compilers dazu.
Joe F. schrieb:> Warum eigentlich FIR?
Es erschien mir das Einfachste von der Umsetzung her, einfach eine
Schleife über ein Array mit Multiplikationen, mit IIR müsste ich mich
dann noch beschäftigen, es geht jetzt auch nicht primär um den Filter
sondern darum, dass ich das alles erstmal richtig verdrahtet bekomme.
Ich versuche erstmal, an mein PIC16F15376 Dev-Board einen
Spannungsteiler hinzufriemeln und dann nochmal die ADC-Werte
aufzuzeichnen, vllt. klappt das dann auch mit Matlab :D
Max M. schrieb:> So?
Nein.
So.
Die 1.8K und der 10nF bilden schonmal einen Tiefpass 1. Ordnung mit
Grenzfrequenz 8.8 KHz.
Einen solchen Tiefpass sollte man vor jeden ADC setzen, denn alle
Signalanteile oberhalb der halben Samplingfrequenz kann man nach dem ADC
in Software nicht mehr herausfiltern.
Warum jetzt auf einmal 100k und 4.7µF?
Wie macht ihr das eigentlich mit dem anpassen eurer Schaltung an euer
Projekt? Ich hab keine Ahnung wie ich das alles vor meinen ADC auf dem
Dev-Board löten soll :(
Max M. schrieb:> Warum jetzt auf einmal 100k und 4.7µF?
So würde ich es halt machen.
Du kannst auch 10uF und 2x 10K für den Eingangs-Hochpass nehmen, mir ist
das eben zu niederohmig.
Wenn die Quelle z.B. 20K Ausgangsimpedanz hat, nehmen die 2x10K deutlich
Pegel weg.
Aber wie gesagt, das geht auch.
Die 1.8K und 10n kann man auch durch etwas anderes ersetzen, z.B. 18K
und 1nF, hauptsache die Grenzfrequenz des Tiefpasses liegt etwas unter
10 KHz.
> Wie macht ihr das eigentlich mit dem anpassen eurer Schaltung an euer> Projekt? Ich hab keine Ahnung wie ich das alles vor meinen ADC auf dem> Dev-Board löten soll
Ach, das geht, 5 Bauteile ist gar nix...
Ein Weg ist "Luftverdrahtung".
Besser: Bauteile auf kleines Lochraster-PCB und daran Kabel anlöten.
Joe F. schrieb:> Die 1.8K und 10n kann man auch durch etwas anderes ersetzen, z.B. 18K> und 1nF, hauptsache die Grenzfrequenz des Tiefpasses liegt etwas unter> 10 KHz.
10kHz?
Es wird mit 31.4kHz abgetastet, also würde ein Tiefpass mit 15.7kHz
schon reichen. (Stichwort "Anti-Aliasing Filter")
Ich würde 10kOhm und 1nF als RC-Tiefpass nehmen.
Max M. schrieb:> Wie macht ihr das eigentlich mit dem anpassen eurer Schaltung an euer> Projekt? Ich hab keine Ahnung wie ich das alles vor meinen ADC auf dem> Dev-Board löten soll
Kommt auf das Dev-Board an. Entweder nimmt man als Hilfe eine
Lochraster-Plate oder man bastelt das halt auf das Dev-Board... gibt
schlimmeres.
Patrick B. schrieb:> 10kHz?> Es wird mit 31.4kHz abgetastet, also würde ein Tiefpass mit 15.7kHz> schon reichen. (Stichwort "Anti-Aliasing Filter")
Der RC Tiefpass ist ja sehr flach (1st Order) und hat bei seiner
Grenzfrequenz gerade mal -3dB.
Daher ist es gut, die Grenzfrequenz so niedrig wie möglich anzusetzen,
und da offenbar hinterher die Frequenzen oberhalb 10 KHz eh
rausgefiltert werden
sollen, kann man den Filter vor dem ADC ruhig so tief ansetzen.
Ich hab den Spannungsteiler mit 10kOhm drangelötet, ich dachte, ich
müsste jetzt ~512 als Wert bekommen, wenn kein Signal angeschlossen ist
(also die Hälfte von 1024 wegen der Hälfte der Versorgungsspannung),
allerdings messe ich jetzt, auch wenn ich nur die 8 MSBs übertrage,
immer 3?
Moin,
Max M. schrieb:> der EFM8LB1 läuft mit max. 72MHz, 14-bit ADC und> 12-bit DAC, zur IDE bekommt man kostenlos eine Lizenz des Keil 8051> C-Compilers dazu.
Weiaweia, da wuerd' ich aber mal ganz genau gucken, was da so ein FIR,
wie's dir vorschwebt an Zyklen frisst. Klar hat der 8051 einen
HW-Multiplizierer, aber halt nur 8x8bit. D.h. fuer 16x16 Bit
Multiplikationen sind 4 8x8Multiplikationen und noch minumum 3
Additionen noetig,etc. bla.
Nimm mal deinen Code, lass den vom C-Compiler assemblieren und zaehl'
mal die Zyklen. Ich vermute mal, dass du da schneller als dir lieb ist,
auch wieder an Grenzen stoesst. (Und ich persoenlich wuerd' mich
heutzutage nicht mehr auf so "kostenlose Lizenzen" einlassen. Im
Zweifelsfall ist man dann immer der Angeschmierte.
Ohne dass ich's selber schon gemacht haette, scheint mir irgendein
Billigboard mit irgendeinem STM32 oder was entsprechendem (und eben auch
GCC-Unterstuetzung) da erheblich "sicherer".
Achja: Von IIRs wuerd' ich erstmal schwer abraten; da gibts viel mehr
Malheur mit Arithmetikproblemen (Rundung, Ueberlauf...) als bei FIRs.
Gruss
WK
Dergute W. schrieb:> scheint mir irgendein> Billigboard mit irgendeinem STM32 oder was entsprechendem (und eben auch> GCC-Unterstuetzung) da erheblich "sicherer".
Ich hab eins von diesen Boards mit einem STM32F103C8T6 hier, allerdings
hat der weder einen DAC noch I2S oder sowas :(
Dergute W. schrieb:> Weiaweia, da wuerd' ich aber mal ganz genau gucken, was da so ein FIR,> wie's dir vorschwebt an Zyklen frisst. Klar hat der 8051 einen> HW-Multiplizierer, aber halt nur 8x8bit. D.h. fuer 16x16 Bit> Multiplikationen sind 4 8x8Multiplikationen und noch minumum 3> Additionen noetig,etc. bla.> Nimm mal deinen Code, lass den vom C-Compiler assemblieren und zaehl'> mal die Zyklen.
Hm, okay :(
Edit: Ich hab mal die Baudrate von 460.800 auf 57.600 reduziert und
siehe da, nun erhalte ich den Wert 131 (wenn ich nur die 8 MSBs
berücksichtige) standardmäßig wenn ich kein Signal an den ADC-Pin
anlege, was kann dieser Controller eigentlich? Mit 57.600 bekomme ich
die Daten nicht in Echtzeit übertragen.
Moin,
Max M. schrieb:> was kann dieser Controller eigentlich?
Wahrscheinlich keine allzugenaue Bitrate bei kleinen Teilerwerten. Was
haengt denn da fuer ein Quarz dran? Kann aus dessen Frequenz die
Baudrate ueberhaupt vernueftig geteilt werden?
Was du da treibst ist halt schon etwas exotisch. Also - kann man schon
machen, aber es lauern halt ueberall Fallstricke...
Gruss
WK
Max M. schrieb:> nun erhalte ich den Wert 131 (wenn ich nur die 8 MSBs> berücksichtige)
Das klingt schon mal vernünftig, aber aus meiner Sicht bist du da
trotzdem noch ziemlich ungenau. Hast du die Spannung mit einem
Mulitmeter am Pin mal gemessen? Wenn bei einem "vernünftigen" 10Bit ADC
nur 8Bit verwendet werden, müsste das schon bei 128 zu liegen kommen.
Max M. schrieb:> Ich hab mal die Baudrate von 460.800 auf 57.600 reduziert
Hast du echtes RS232 oder gehst du direkt vom uC auf einen FT232?
Kannst du mal dein Board (Schema, Bezeichnung...) posten?
Max M. schrieb:> Ich hab eins von diesen Boards mit einem STM32F103C8T6 hier, allerdings> hat der weder einen DAC noch I2S oder sowas :(
STM24F4 Discovery hat das alles und gibts für <30 Euro. Ausserdem hat
das eine FPU, 32Bit Architektur und läuft mit flotten 168MHz. Zusätzlich
werden dir die DMA-Funktionen hier sehr viel Arbeit abnehmen.
Zum Basteln würde ich lieber ein Board nehmen, welches ein paar Faktoren
überdimensioniert ist.
Patrick B. schrieb:> Hast du echtes RS232 oder gehst du direkt vom uC auf einen FT232?
Ja, so mach ich das aktuell.
Dergute W. schrieb:> Wahrscheinlich keine allzugenaue Bitrate bei kleinen Teilerwerten. Was> haengt denn da fuer ein Quarz dran? Kann aus dessen Frequenz die> Baudrate ueberhaupt vernueftig geteilt werden?
Die Formel ist: CPU-Takfrequenz(bei mir 32MHz) / (16 * (BaudRate + 1)),
bei BaudRate = 460.800 ist der Wert 4.340, man kann aber nur 4.0 in das
Register schreiben, also sind das ~460.828 Baud, selbst wenn ich damit
auf den COM-Port connecte, erhalte ich auch nur die 3 :(
Patrick B. schrieb:> Kannst du mal dein Board (Schema, Bezeichnung...) posten?
Board ist das MPLAB Xpress PIC16F15376, dazu finde ich leider keinen
Schaltplan
Patrick B. schrieb:> Hast du die Spannung mit einem> Mulitmeter am Pin mal gemessen?
1.67V
Moin,
Ja, dann ist's ja klar, dass das mit den hohen Baudraten nix werden
kann. Kannst hoechsten probieren, deinen PIC etwas zu uebertakten, wenn
du einen 36.864MHz Quarz dranhaengst. Dann klappts auch mit dem
Teilen...
Gruss
WK
Dergute W. schrieb:> Ja, dann ist's ja klar, dass das mit den hohen Baudraten nix werden> kann. Kannst hoechsten probieren, deinen PIC etwas zu uebertakten, wenn> du einen 36.864MHz Quarz dranhaengst. Dann klappts auch mit dem> Teilen...
Ich verstehe nicht, selbst wenn ich mich mit der Baudrate verbinde, die
laut der Formel mit dem Wert 4 rauskommen müsste, erhalte ich immer
noch einen falschen Wert über UART.
Max M. schrieb:> Board ist das MPLAB Xpress PIC16F15376, dazu finde ich leider keinen> Schaltplan
ca. 5min suchen:
https://www.microchip.com/mplab/mplab-xpresshttp://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB%20Xpress.pdfMax M. schrieb:> CPU-Takfrequenz(bei mir 32MHz)
Mhm, dann muss wohl intern mit PLLs gearbeitet werden, weil ich sehe
keinen Quarz im Schema.
Max M. schrieb:> Ich verstehe nicht, selbst wenn ich mich mit der Baudrate verbinde, die> laut der Formel mit dem Wert 4 rauskommen müsste, erhalte ich immer> noch einen falschen Wert über UART.
Du hast einen PIC als USB-UART Brücke. Ich denke dieser kann nicht mit
"Sonder-" Baudraten gearbeitet wird.
Patrick B. schrieb:> Du hast einen PIC als USB-UART Brücke. Ich denke dieser kann nicht mit> "Sonder-" Baudraten gearbeitet wird.
Ich gebe den UART über einen extra Pin aus:
Deine Baudrate stimmt nicht die ist bei 400000, schaue nochmal ins db
und dir genau die Formeln zum bdrate Generator an. Für 460800 wären es
mit 32mhz und prescale 16 =3.34.
Eventuell macht deine usb uart Bridge die 400000 ja mit kann man mal
probieren.
Dann hängt es gff. noch an der Toleranz der taktquelle.
Max M. schrieb:> Die Formel ist: CPU-Takfrequenz(bei mir 32MHz) / (16 * (BaudRate + 1)),> bei BaudRate = 460.800 ist der Wert 4.340, man kann aber nur 4.0 in das> Register schreiben, also sind das ~460.828 Baud, selbst wenn ich damit> auf den COM-Port connecte, erhalte ich auch nur die 3 :(
Als erstes würde ich da mal den EUSART so konfigurieren, daß der
Baudraten-Clock Fosc/4 ist, dann kannst Du schon eine wesentlich
korrektere Baudrate einstellen!
Außerdem ist die Formel falsch. Der BRG-Registerwert ist
X = (Fosc/Baudrate)/T-1
T ist der Teilerfaktor des Baudraten-Generators (4|16|64, je nach BRG16
und BRGH-Bitsetting). Also: setze BRG16 und BRGH Bits auf 1, dann ist
T=4, und für Deine 460800 Bd kommt raus:
(32MHz/460800)/4-1=16.36 -> 16 ins BRG-Register laden.
Gegenprobe: Baudrate = Fosc/(T*(BRG+1) = 32E6/68 = 470588 -> knappe 2%
daneben.
Thomas E. schrieb:> Außerdem ist die Formel falsch. Der BRG-Registerwert ist> X = (Fosc/Baudrate)/T-1>> T ist der Teilerfaktor des Baudraten-Generators (4|16|64, je nach BRG16> und BRGH-Bitsetting). Also: setze BRG16 und BRGH Bits auf 1, dann ist> T=4
Meine Formel ist nicht falsch, für die von dir angegebenen BRG16 und
BRGH Bits stimmt deine Formel, für meine BRG16 und BRGH Bits stimmt aber
meine Formel genauso!
1
TX2STAbits.BRGH=1;//High Speed UART
2
BAUD2CONbits.BRG16=0;//8-bit BaudRate Generator
Also BRGH = 1 und BRG16 = 0
FloMann schrieb:> schaue nochmal ins db> und dir genau die Formeln zum bdrate Generator an.
Hab ich doch, zeig mir dann bitte die Formel, mit der du auf 400.000
Baud kommst.
Thomas E. schrieb:> für Deine 460800 Bd kommt raus:> (32MHz/460800)/4-1=16.36 -> 16 ins BRG-Register laden.
Bin ich blind oder stimmt deine Formel nicht mit der vom Datenblatt
überein?
32*10^6 / [4 * (460800 + 1)]
Irgendwie verwirrt ihr mich gerade, ich dachte eigentlich, ich kann das
Datenblatt lesen und die Formel richtig interpretieren.
Nein deine Formel ist falsch, Thomas hat dir die richtige
aufgeschrieben.
Steht genau so mit rechenbeispiel im db bei der Baudraten Generator
Beschreibung. Den Prescaler auf vier wäre ein Mittel genauer auf die
Baudrate
zu kommen aber z.b. die typischen ftdi 232 usb uart Bridges können es
noch besser,
z.b. 232x mit 14Bit plus 3Bit fraktionell Teiler. Die 400000 als
beispiel gehen genau auf.
FloMann schrieb:> Nein deine Formel ist falsch, Thomas hat dir die richtige> aufgeschrieben.
Was genau macht dann die Formel in der von mir hochgeladenen Tabelle
(https://www.mikrocontroller.net/attachment/337296/uart_config.PNG)? In
der Spalte steht sogar "Baud Rate Formula"?
Auf Seite 479 steht die Formel "X = (FOSC/BaudRate/64) - 1", aber
nirgends steht etwas von "T" oder was "T" ist?
FloMann schrieb:> Den Prescaler auf vier wäre ein Mittel genauer auf die> Baudrate> zu kommen
Welchen Prescaler denn? Wenn ich mit PDF-Search suche, finde ich im
gesamten EUSART-Kapitel nirgends das Wort "Prescaler"
FloMann schrieb:> zu kommen aber z.b. die typischen ftdi 232 usb uart Bridges können es> noch besser,> z.b. 232x mit 14Bit plus 3Bit fraktionell Teiler. Die 400000 als> beispiel gehen genau auf.
Hab ich nicht, ich hab einen mit CH340, der hat aber schon einen ESP8266
mit über 400.000 Baud geflashed, also hält er das Tempo anscheinend aus.
Ich versteh nicht, wo ihr diese Formeln her habt, ich seh die im
Datenblatt nicht, und warum ist die Formel, die auch im Datenblatt in
einer Tabelle steht, nun auf einmal falsch?
Max M. schrieb:> Auf Seite 479 steht die Formel "X = (FOSC/BaudRate/64) - 1", aber> nirgends steht etwas von "T" oder was "T" ist?
Das "T" ist nicht aus dem Datenblatt, sondern von mir - incl. der
Erklärung, daß es den Teilerfaktor 4, 16 oder 64 darstellt.
Max M. schrieb:> Was genau macht dann die Formel in der von mir hochgeladenen Tabelle> (https://www.mikrocontroller.net/attachment/337296/uart_config.PNG)? In> der Spalte steht sogar "Baud Rate Formula"?
Sie errechnet die Baudrate aus der Oszillator-Frequenz und dem Wert (n),
der in das BRG-Register (BRGH,BRGL) geschrieben wird. Und genau diese
Formel (die aus der Tabelle rechts unten, mit T=4) habe ich benutzt, um
die Baudrate auszurechnen (ok, ich habe nicht "n" für den Wert des
BRG-Registers geschrieben, sondern "BRG"):
Baudrate = Fosc/[4(n+1)] = Fosc/(T*(BRG+1)) = 32E6/(4*(16+1)) = 32E6/68
Wie Du siehst, habe ich keine andere Formel benutzt, als im DB steht und
natürlich ist die Formel im DB richtig!
Max M. schrieb:> Bin ich blind oder stimmt deine Formel nicht mit der vom Datenblatt> überein?>> 32*10^6 / [4 * (460800 + 1)]
Diese Formel steht nicht im Datenblatt - jedenfalls nicht als Formel, um
aus einer gewünschten Baudrate den Registerwert zu errechnen! Du hast
offensichtlich die Formel zur Berechnung der Baudrate vom
BRGH/BRGL-Registerwert benutzt und da einfach den Registerwert durch die
Baudrate ersetzt.
Wenn Du also 460800 in das BRG-Register lädst, sendet der UART mit
17,361 Baud, wofür die Formel auch tatsächlich korrekt ist!
Um den Registerwert für eine vorgegebene Baudrate zu errechnen, musst Du
die Formel, wie auf Seite 479 "Example 33-1" gezeigt, nach X (= BRG
Registerwert) umstellen. Für mein "T=4" lautet die Formel dann:
X = ((FOSC/BaudRate)/4) - 1
Und genau diese Formel habe ich auch verwendet!
Mit Deinen Werten (TX2STAbits.BRGH = 1 und BAUD2CONbits.BRG16 = 0)
kannst Du die Baudrate aber nur entweder auf 400000 Baud oder 500000
Baud einstellen - ist beides zu weit weg von 460800, um zu
funktionieren.
Vielen, vielen Dank Thomas, für die ausführliche Erklärung! Jetzt habs
auch ich geschnallt :D
Bei einer Baud-Rate von 500.000 und mit BRG16 = 1 und BRGH = 1 (ergibt
dann 15 als Registerwert), erhalte ich nun auch 131 als 8-bit AD-Wert!
Edit: Ich hab nun nochmal 4s Musik aufgenommen, allerdings hört sich das
immer noch nur nach Rauschen in Matlab an :(
So schlecht klingt das jetzt aber nicht.
Ok, habe natürlich wieder nur R2015a benutzt, daher habe ich ein paar
Tricks angewendet um deine Daten abspielen zu können:
1) In Matlab einlesen und als Timeseries-Object umwandlen
1
M=xlsread('Captured.csv');
2
plot(M(:,1),M(:,2));
3
4
% Daten zusammenstellen
5
Input = M(:,2);
6
time=1:1/31400:4;
7
time=time(1:end-1);
8
data=timeseries(Input,time);
2) Simulink-Blöcke für double-Version zusammengeklickt (ist
auskommentiert).
3) Int8 als Datenquelle verwendet
Viel Spass dabei noch.
Vielen Dank Patrick, für deine Hilfe. Leider hab ich keinen Plan von
Matlab, ich hab das jetzt mal alles so in das Command Window eingegeben,
beim letzten Befehl erhalte ich die Fehlermeldung:
Bei mir ist M 125600 Elemente und time 94200 Elemente groß, ist das
möglicherweise das Problem?
Edit: Okay, so gehts dann:
1
time=1:1/31400:5;
Hörst du zu Beginn auch so ein Piepsen? Aber jetzt hör ich tatsächlich
die Musik :D
Erstaunlich, was man dafür alles zusammenbauen muss in Simulink, auf so
was wär ich nicht gekommen...
Das Piepsen kommt wahrscheinlich davon, dass ich 125600 time-Spalten
habe, die allerdings bis 5 gehen obwohl ich nur 4s aufgenommen hab.
Edit_2: Okay, so gehts nun :D
Max M. schrieb:> Edit_2: Okay, so gehts nun :Dtime=0:1/31400:4;
Sorry, ich hatten den gleichen Fehler gemacht und dann die falsche Zeile
kopiert.
Max M. schrieb:> Erstaunlich, was man dafür alles zusammenbauen muss in Simulink, auf so> was wär ich nicht gekommen...
Man gewöhnt sich daran. Dafür erhälst du praktisch unbegrenzte
Möglichkeiten.
Eventuell geht es ja mit den neuen Versionen besser.
Max M. schrieb:> Mit dem "To Audio Device" funktioniert alles perfekt, wenn ich> dieses durch das neuere "Audio Device Writer" ersetze, bekomme ich> Kratzen als Ton :(
Mhm, vergleich die doch mal. Unterschiedliche Datentypen, andere
Samplingrate, sonst andere Einstellungen?
Ansonsten kannst du aktuell die alte Version verwenden und den Fehler
bei mehr Zeit suchen.
BTW. Ich habe rasch die Doku zum Device Weiter überflogen: wenn du
diesen in meinem Beispiel ersetzen willst, musst du darauf achten, dass
er auch wirklich Int16 als Datentyp akzepiert (sonst selber vorgeben),
oder die Daten entsprechend vorher skalieren.
So, jetzt aber ins weekend ;)