Forum: Mikrocontroller und Digitale Elektronik FIR Filter auf PIC


von Max M. (maxmicr)


Lesenswert?

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
unsigned char buffer[Ntap];
13
14
int coeffs[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
void interrupt __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
    long sum = 0;
44
    for(unsigned char i = 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(unsigned char n = 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
void initADC(){
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
void initTimer0(){
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
void initDAC(){
88
    DAC1CON0bits.DAC1EN = 1;    //Enable DAC
89
    DAC1CON0bits.DAC1OE1 = 1;   //Tie voltage level to DAC1OUT1 pin (RA2)
90
    
91
    DAC1CON0bits.PSS = 0b00;   //Source is Vdd
92
}
93
94
void initOscillator(){
95
    OSCCON1bits.NOSC = 0b110;   //Select HFINTOSC
96
    OSCCON1bits.NDIV = 0b0000;
97
    OSCFRQbits.HFFRQ = 0b110;     //32 MHz
98
}
99
100
void main(void) {
101
    initOscillator();
102
    initDAC();
103
    initADC();
104
    initTimer0();
105
    while(1){
106
    }
107
}

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

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.

von Stefan K. (stefan64)


Lesenswert?

Du rotierst Deine Coeffizienten statt den Buffer:
1
    buffer[0] = ADRESH; //8 MSBs from ADC conversion
2
    long sum = 0;
3
    for(unsigned char i = 0; i < Ntap; i++){
4
        sum += buffer[i] * coeffs[i];
5
    }
6
        
7
    DAC1CON1 = sum>>7; //WinFilter tells me to divide sum by 128
8
    
9
    //rotate array
10
    for(unsigned char n = Ntap-1; n > 0; n--)
11
        coeffs[n] = coeffs[n-1];
Die Werte in buffer[1 .. Ntap-1] werden nie beutzt und sind durch den C 
startup immer 0.

Wahrscheinlich wolltest Du schreiben:
1
    for(unsigned char n = Ntap-1; n > 0; n--)
2
        buffer[n] = buffer[n-1];

Viele Grüße, Stefan

von Max M. (maxmicr)


Lesenswert?

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:
1
    for(unsigned char n = Ntap-1; n > 0; n--)
2
        buffer[n] = buffer[n-1];

von Stefan K. (stefan64)


Lesenswert?

Es ist eine schlechte Idee, innerhalb einer isr zu warten:
1
    
2
void interrupt __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

von Max M. (maxmicr)


Lesenswert?

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?

: Bearbeitet durch User
von Volker S. (vloki)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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?

von Dergute W. (derguteweka)


Lesenswert?

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

von c-hater (Gast)


Lesenswert?

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.

von THOR (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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.

von Dergute W. (derguteweka)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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

von Volker S. (vloki)


Lesenswert?

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

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

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

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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?

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

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.

von Volker S. (vloki)


Angehängte Dateien:

Lesenswert?

Max M. schrieb:
> (anscheinend kann der
> Simulator keine 32MHz simulieren da rechts unten immer "Instruction Freq
> = 1MHz" steht)

Das kann/muss man einstellen...

von Dergute W. (derguteweka)


Lesenswert?

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

von Frank K. (fchk)


Lesenswert?

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

: Bearbeitet durch User
von ADC (Gast)


Lesenswert?

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.

von Max M. (maxmicr)


Lesenswert?

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
unsigned char buffer[Ntap] = {127,64,255,87,50};
2
char coeffs[Ntap] = {-3,7,-31,-9,83,};

Die erste Multiplikation 127 * (-3) = -381 = 1111 1110 1000 0011 
(0xFE83), wenn ich das im Simulator mache:
1
int result = buffer[0] * coeffs[0];

erhalte ich 0x7D83. Hab ich was übersehen?

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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
void interrupt __isr_handler(void) {
2
    PORTAbits.RA0 = 1;
3
    
4
    buffer[0] = ADRESH;
5
    int sum = 0;
6
    for(unsigned char i = 0; i < Ntap; i++){
7
        int result = buffer[i] * coeffs[i];
8
        sum += result;
9
    }
10
        
11
    DAC1CON1 = sum>>11;
12
    //DAC1CON1 = ADRESH>>3;
13
    
14
    for(unsigned char n = 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 :(

von Dergute W. (derguteweka)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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:
1
            int coeffVal = coeffs[0];
2
            int result = buffer[0] * coeffVal;

von Dergute W. (derguteweka)


Lesenswert?

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

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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?

: Bearbeitet durch User
von Thomas E. (picalic)


Lesenswert?

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.

von Stefan K. (stefan64)


Lesenswert?

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

von Hmmhmm (Gast)


Lesenswert?

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.

von Dergute W. (derguteweka)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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.

von Volker S. (vloki)


Lesenswert?

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.

von Thomas E. (picalic)


Lesenswert?

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.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

So in der Art koennte man z.B. ein FIR bauen, ohne "richtig" 
multiplizieren zu muessen - wie schon mal erwaehnt: Uebersichtlich geht 
anders...
1
#include <stdio.h>
2
#include <inttypes.h>
3
#include <string.h>
4
5
6
int8_t fir(int8_t x) {
7
    static int8_t z[11];
8
    int16_t sum;
9
10
    memmove(z,z+1,10);
11
    z[10]=x;
12
    //index:  0  1  2  3  4  5  6  7  8  9 10
13
    //coeff: [1  0 -2  0  5  8  5  0 -2  0  1] / 16
14
15
    // LSB
16
    sum =z[ 0];
17
    sum+=z[ 4];
18
    sum+=z[ 6];
19
    sum+=z[10];
20
    sum >>=1;
21
    // 2. Bit
22
    sum-=z[2];
23
    sum-=z[8];
24
    sum >>=1;
25
    // 3. Bit
26
    sum+=z[4];
27
    sum+=z[6];
28
    sum >>=1;
29
    // 4. Bit
30
    sum+=z[5];
31
    sum >>=1;
32
    return sum;
33
}
34
35
int main() {
36
37
int i;
38
int8_t x,y;
39
    for (i=0;i<20;i++) {
40
       x=0;
41
       if (i==3) x=16;
42
       y=fir(x);
43
       printf("%d\n",y);
44
   }
45
}




Gruss
WK

von Max M. (maxmicr)


Lesenswert?

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"

von Patrick B. (p51d)


Lesenswert?

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!

von Volker S. (vloki)


Lesenswert?

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 ;-)

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

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'

von Thomas E. (picalic)


Lesenswert?

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

von Patrick B. (p51d)


Lesenswert?

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.html
https://ch.mathworks.com/de/products/dsp-system.html
https://ch.mathworks.com/help/simulink/ug/tutorial-integrating-matlab-code-with-a-simulink-model-for-filtering-an-audio-signal.html
https://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!).

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

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

von Max M. (maxmicr)



Lesenswert?

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?

: Bearbeitet durch User
von Patrick B. (p51d)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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
void interrupt __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?

: Bearbeitet durch User
von Patrick B. (p51d)


Lesenswert?

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?

: Bearbeitet durch User
von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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?

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

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

von Patrick B. (p51d)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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?

von Thomas E. (picalic)


Lesenswert?

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.

von Max M. (maxmicr)


Lesenswert?

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 :(

von Thomas E. (picalic)


Lesenswert?

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

von Patrick B. (p51d)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

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.

: Bearbeitet durch User
von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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

: Bearbeitet durch User
von Joe F. (easylife)


Angehängte Dateien:

Lesenswert?

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.

von Max M. (maxmicr)


Lesenswert?

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 :(

: Bearbeitet durch User
von Joe F. (easylife)


Lesenswert?

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.

: Bearbeitet durch User
von Patrick B. (p51d)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

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.

von Max M. (maxmicr)


Lesenswert?

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?

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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.

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

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

von Patrick B. (p51d)


Lesenswert?

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.

von Max M. (maxmicr)


Lesenswert?

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

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

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

von Max M. (maxmicr)


Lesenswert?

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.

von Patrick B. (p51d)


Lesenswert?

Max M. schrieb:
> Board ist das MPLAB Xpress PIC16F15376, dazu finde ich leider keinen
> Schaltplan

ca. 5min suchen:
https://www.microchip.com/mplab/mplab-xpress
http://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB%20Xpress.pdf

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

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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:
1
//Pin D4 is TX
2
void initUART2(){
3
    //Route UART2-TX to D4
4
    ANSELDbits.ANSD4 = 0; //Make D4 a digital Pin
5
    TRISDbits.TRISD4 = 0; //Make D4 an output
6
    RD4PPS = 0x11;  //Route UART2-TX to D4
7
    
8
    SP2BRGL = 4; // Formula: x=Frequency / (16 * (BaudRate + 1))
9
    SP2BRGH = 0;
10
    TX2STAbits.BRGH = 1; //High Speed UART
11
    BAUD2CONbits.BRG16 = 0; //8-bit BaudRate Generator
12
    
13
    RC2STAbits.SPEN = 1; //enable
14
    TX2STAbits.SYNC = 0; //Async
15
    TX2STAbits.TX9 = 0; //8-bit data transmission
16
    TX2STAbits.TXEN = 1; //transmit enable
17
}

Ich hab das UART Signal nun mal mit Logic aufgezeichnet, wenn ich als 
Analyzer einen UART mit 460.800 Baud hinzufüge, erkennt dieser auch nur 
3 :(

: Bearbeitet durch User
von FloMann (Gast)


Lesenswert?

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.

von Thomas E. (picalic)


Lesenswert?

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.

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von FloMann (Gast)


Lesenswert?

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.

von Max M. (maxmicr)


Lesenswert?

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?

: Bearbeitet durch User
von Thomas E. (picalic)


Lesenswert?

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.

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

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 :(

: Bearbeitet durch User
von Patrick B. (p51d)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

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:
1
>> data=timeseries(Input,time);
2
Error using timeseries.utreshape (line 846)
3
Data and time dimensions are incompatible.
4
5
Error in timeseries/init (line 280)
6
       [data,quality] = timeseries.utreshape(lenTime,data,quality);
7
8
Error in timeseries (line 324)
9
                  this = init(this,varargin{:});

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
1
time=0:1/31400:4;

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

Mit dem "To Audio Device" funktioniert alles perfekt, wenn ich dieses 
durch das neuere "Audio Device Writer" ersetze, bekomme ich Kratzen als 
Ton :(

: Bearbeitet durch User
von Patrick B. (p51d)


Lesenswert?

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 ;)

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

Ich find keine Lösung, wieso entfernen die ein Tool aus ihrer Software 
und bringen dann ein neues, das dem Funktionsumfang des alten nicht 
entspricht?

von Joe F. (easylife)


Lesenswert?

Das entspricht dem Zeitgeist (ALG2, VoIP, Trump...)

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.