Forum: Mikrocontroller und Digitale Elektronik STM32 µC Board und DAC


von MIrco (Gast)


Lesenswert?

Hallo Leute,

ich habe mir hier das STM32F411 Board gekauft und habe dahinter einen 
DAC geschaltet (DAC7811). Über die SPI schnittstelle kann ich eine 
DC-Ausgangsspannung vom DAC einstellen. SOweit so gut.
http://www.ti.com/lit/ds/symlink/dac7811.pdf


Im nächsten Schritt würde ich an stelle der DC Spannung einen Sinus 
ausgeben. Hierfür habe ich mir ein 8 bit Array mit Sinuswerten erzeugt 
und diese sollen nun ausgegeben werden.

Am AUsgang des DACs habe ich einen OPA2277 Buffer mit anschließendem 
Filter 4. Ordnung(fg=3 MHz).

So nun zu meinen Parametern:

F_SCLK = 25 MHz -> Samplingrate -> F_SCLK/16 = 1,56MHZ


Mein Problem ist , ich bekomme irgendwie keinen Sinus am Ausgang der 
Schaltung. Ich habe selbst das AUsgangsfilter schon durchgemessen und 
selbst das passt mit den Berechnungen überein.

Hier mein Programmcode:
1
#include "mbed.h"
2
3
double m_sinus[] = {0.500000,0.512319,0.524630,0.536926,0.549200,0.561444,0.573651,0.585813,0.597923,0.609973,0.621957,0.633867,0.645695,0.657435,0.669079,0.680621,0.692053,0.703368,0.714560,0.725622,0.736547,0.747328,0.757959,0.768433,0.778745,0.788887,0.798854,0.808639,0.818237,0.827642,0.836848,0.845849,0.854641,0.863217,0.871572,0.879702,0.887602,0.895266,0.902690,0.909870,0.916801,0.923479,0.929900,0.936060,0.941955,0.947582,0.952937,0.958017,0.962819,0.967340,0.971577,0.975528,0.979191,0.982562,0.985641,0.988424,0.990911,0.993100,0.994990,0.996579,0.997867,0.998853,0.999535,0.999915,0.999991,0.999763,0.999232,0.998398,0.997261,0.995822,0.994083,0.992043,0.989705,0.987069,0.984138,0.980913,0.977396,0.973589,0.969494,0.965115,0.960453,0.955511,0.950293,0.944802,0.939041,0.933013,0.926722,0.920172,0.913367,0.906311,0.899009,0.891464,0.883681,0.875666,0.867422,0.858956,0.850272,0.841374,0.832270,0.822964,0.813462,0.803769,0.793893,0.783837,0.773610,0.763216,0.752663,0.741956,0.731102,0.720108,0.708980,0.697726,0.686351,0.674863,0.663269,0.651576,0.639791,0.627921,0.615974,0.603956,0.591875,0.579738,0.567553,0.555326,0.543066,0.530780,0.518476,0.506160,0.493840,0.481524,0.469220,0.456934,0.444674,0.432447,0.420262,0.408125,0.396044,0.384026,0.372079,0.360209,0.348424,0.336731,0.325137,0.313649,0.302274,0.291020,0.279892,0.268898,0.258044,0.247337,0.236784,0.226390,0.216163,0.206107,0.196231,0.186538,0.177036,0.167730,0.158626,0.149728,0.141044,0.132578,0.124334,0.116319,0.108536,0.100991,0.093689,0.086633,0.079828,0.073278,0.066987,0.060959,0.055198,0.049707,0.044489,0.039547,0.034885,0.030506,0.026411,0.022604,0.019087,0.015862,0.012931,0.010295,0.007957,0.005917,0.004178,0.002739,0.001602,0.000768,0.000237,0.000009,0.000085,0.000465,0.001147,0.002133,0.003421,0.005010,0.006900,0.009089,0.011576,0.014359,0.017438,0.020809,0.024472,0.028423,0.032660,0.037181,0.041983,0.047063,0.052418,0.058045,0.063940,0.070100,0.076521,0.083199,0.090130,0.097310,0.104734,0.112398,0.120298,0.128428,0.136783,0.145359,0.154151,0.163152,0.172358,0.181763,0.191361,0.201146,0.211113,0.221255,0.231567,0.242041,0.252672,0.263453,0.274378,0.285440,0.296632,0.307947,0.319379,0.330921,0.342565,0.354305,0.366134,0.378043,0.390027,0.402077,0.414187,0.426349,0.438556,0.450800,0.463074,0.475370,0.487681,0.500000}; 
4
   
5
void write_out(int SPI_value);
6
7
8
double voltage = 0.5;
9
int f=49000000;       //entspricht einer Clockfrequenz von 25 MHz
10
11
12
int t =0;
13
DigitalOut Enable(D9);      // Um den DAC über CS anzusprechen
14
15
16
//SPI device(SPI_MOSI, SPI_MISO, SPI_SCK);
17
SPI device(D11, D12, D13);  //definiert die Pins für miso mosi und sck
18
19
int main() {
20
21
    voltage =(4095/3.61)*voltage;// 
22
    int i = 4096+voltage;
23
     
24
    Enable = 1;
25
    device.frequency(f);   // definiert die Clock Frequency des SPI 
26
    device.format(16,0);   //MIt der erstem Zahl wird die Bit des SPI eingestellt entweder 8 oder 16 mit der zweiten zahl kann die Phase und der Modus eingestellt werden mit der SPI laufen soll,
27
                 /*
28
                 //CPOL (Clock Polarity)
29
                 0: Takt ist in Ruhe LOW, ein Wechsel auf HIGH zählt als steigende Taktflanke
30
                 1: Takt ist invertiert: in Ruhe HIGH, ein Wechsel auf LOW zählt als steigende Taktflanke
31
                    CPHA (Clock Phase)
32
                 0: Daten werden bei steigender Taktflanke (=abh. von CPOL) eingelesen, bei fallender ausgegeben
33
                 1: Daten werden bei fallender Taktflanke eingelesen, bei steigender ausgegeben
34
                 */
35
    
36
    write_out(40960); // Clock data to shift register on rising Edge
37
    wait_us(1);
38
          
39
    while(1) {
40
        
41
      i = voltage*(m_sinus[t]);
42
      i = (4095/3.61)*i;
43
      
44
      write_out(i+4096);
45
      //wait_us(1);
46
      t = t+1;
47
      if(t>250)
48
        t = 0;
49
50
         
51
    }
52
}
53
 
54
 void write_out(int SPI_value)
55
 {   
56
        Enable = 0;
57
        device.write(SPI_value);     
58
        Enable = 1;     
59
 }

von Noch einer (Gast)


Lesenswert?

Ein Test wäre, erst mal ganz langsam ablaufen lassen. Dass du am Ausgang 
eine Treppe von Gleichspannungen bekommst. Und kontrollieren, ob vor und 
nach dem Filter die richtigen Spannungen ankommen.

von MIrco (Gast)


Lesenswert?

Noch einer schrieb:
> Ein Test wäre, erst mal ganz langsam ablaufen lassen. Dass du am Ausgang
> eine Treppe von Gleichspannungen bekommst. Und kontrollieren, ob vor und
> nach dem Filter die richtigen Spannungen ankommen.

Das habe ich auch schon probiert, leider ergeben sich dabei auch nicht 
die gewünschten Treppenstufen. Das finde ich ja das Merkwürdige!!!!

Wenn ich nur einen Bestimmten DC-Wert festlege, funktioniert der ganze 
kram :/

von MIrco (Gast)


Lesenswert?

Wenn ich in die While SChleife z.B. ein Dreieck Signal erzeuge, wird 
dieses wunderbar am Ausgang angezeigt.

von Noch einer (Gast)


Lesenswert?

Copy&Paste in eine Tabellenkalkulation? Kontrollieren, ob die Zahlen 
überhaupt einen Sinus ergeben?

von MIrco (Gast)


Lesenswert?

Noch einer schrieb:
> Copy&Paste in eine Tabellenkalkulation? Kontrollieren, ob die Zahlen
> überhaupt einen Sinus ergeben?

Ich erzeuge die Werte mit Matlab und speicher mir diese Werte in eine 
txt file^^

von Walter T. (nicolas)


Lesenswert?

MIrco schrieb:
> Ich erzeuge die Werte mit Matlab

Dann plotte doch mal in Matlab, ob floor(i+4096) immer noch einen 
schönen Sinus ergibt, der unter INT_MAX bleibt.

von Noch einer (Gast)


Lesenswert?

Hab das berechnete i ausgegeben und eine Grafik erzeugt.

Ist zwar ein Sinus, die Werte sind aber viel zu groß, liegen zwischen 0 
und 0x9d067.

Und das t>250 ergibt einen Sprung im Sinus.

von Mirco (Gast)


Lesenswert?

Ja, danke sehr schon einmal für  die Mühe.

Das mit t=250 habe ich nur aus testzwecken mal eingetragen. 
In.wirklichkeit müsste ich bis maximal 255 gehen.

Die Werte die angegeben.habe, sollen später  in meinem programm einfach 
nur prozenangabe der Amplitude sein.

von Mirco (Gast)


Lesenswert?

Ich habe meinen.fehler gerade glaub ich selber gefunden.

In der setup routine berechne.ich den sinus noch richtig. Nachher in.der 
loop caste ich den amplitudenwert auf einen.integer wert! Dan ist es 
logisch das da nichts rauskommt

von Jim M. (turboj)


Lesenswert?

Da ist was mit dem Wertebereich von i kaputt. Hast Du Dir mal die 
Zwischenwerte von i im Debugger angesehen?
1
double voltage = 0.5;
2
//...
3
int i;
4
voltage =(4095/3.61)*voltage; // (1)
5
//...
6
i = voltage*(m_sinus[t]);     // (2)
7
i = (4095/3.61)*i; // <--- doppelte Skalierung (3)
8
write_out(i+4096); // (4)


Ein paar Anmerkungen: Der STM32F4 unterstützt nur float und nicht double 
in Hardware, die Berechnungen sind also recht lahm in Software.

Die Skalierung in (1) ist eine gute Idee, wenn voltage Typ float wäre.
Die Skalierung in (3) ist eine eher schlechte Idee: Ohne die Skalierung 
von voltage in (1) würde da nur Null heraus kommen.

Mit beiden Skalierungen zusammen läuft Dir aber der Wertebereich von i 
über, was gar lustige Werte im DAC zur Folge hat.

Übrigens kennt dieser DAC keine negativen Werte, und die Berechnung in 
(4) mit Addition klappt nur wenn i >= 0 ist.

STM32F4 hat das unter Cortex M übliche Debugging Interface, damit kann 
man sich die Zwischenwerte von i mal anschauen.

: Bearbeitet durch User
von temp (Gast)


Lesenswert?

Das sieht nach ziemlichen Kauderwelsch aus das ganze.
1. Dein F4 hat eine FPU ist die an?
2. Welche Zeiten willst du haben?
3. Wenn dir 1-2us für die sinus Berechnung reichen, dann würde ich keine 
Tabelle benutzen sonder sinf() oder arm_sin_f32() aus der dsplib.
4. Wenn schon FPU dann peinlich aufpassen bei Konstanten 123.65f zu 
schreiben und nicht 123.65 damit der Compiler keine double Berechnungen 
einstreut.
5. Am Listing oder im Debugger kontrollieren dass der Compiler keine 
double-Berechnungen ausführt. Das kostet sehr viel Zeit.
6. Man kann nicht davon ausgehen, dass alle Rechenoperationen immer die 
selbe Zeit brauchen. Schon gar nicht wenn die FPU aus ist. Deshalb muss 
hier ein Timer den Takt vorgeben.
7. Die Zeit die du hier fragst hättest du besser erst mal mit dem 
Debugger  verbracht. Der zeigt einem so manches Brett vorm Kopf und 
bewahrt einen vor dummen Sprüchen und Naserümpfen im Forum.

von Helmut S. (helmuts)


Lesenswert?

> Am AUsgang des DACs habe ich einen OPA2277 Buffer mit anschließendem
Filter 4. Ordnung(fg=3 MHz).


Der OPA2227 hat nur ein GBW von 1MHz. Damit kannst du sinnvoll nur bis 
20kHz arbeiten. Die 3MHz sind völlig daneben bei diesem Opamp.

von MIrco (Gast)


Lesenswert?

Jim M. schrieb:
> Ein paar Anmerkungen: Der STM32F4 unterstützt nur float und nicht double
> in Hardware, die Berechnungen sind also recht lahm in Software.
>
> Die Skalierung in (1) ist eine gute Idee, wenn voltage Typ float wäre.
> Die Skalierung in (3) ist eine eher schlechte Idee: Ohne die Skalierung
> von voltage in (1) würde da nur Null heraus kommen.

Ja, danke schon einmal.

Helmut S. schrieb:
>> Am AUsgang des DACs habe ich einen OPA2277 Buffer mit anschließendem
> Filter 4. Ordnung(fg=3 MHz).
>
> Der OPA2227 hat nur ein GBW von 1MHz. Damit kannst du sinnvoll nur bis
> 20kHz arbeiten. Die 3MHz sind völlig daneben bei diesem Opamp.

Ja, das ist mir dann auch aufgefallen, da habe ich das Filter nicht 
gerade gut ausgelegt.

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


Lesenswert?

Wozu machst du das rumgemurkse mit floats? Davon versteht dein DAC 
nichts und du musst erst mühselig Float wieder in Int zurückwandeln.
Nimm gleich int Werte und schick die per Timer ISR zum DAC, damit du 
auch auf vorhersehbare Sampleraten kommst. Die ISR kann auch gleich die 
Tabellenzeiger behandeln, so das das praktisch im Hintergrund läuft.

Die Sinustabelle kannst du dir mit nahezu beliebigen Parametern hier 
berechnen lassen:
http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml

und simpel per Copy&Paste in dein Programm übernehmen.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

temp schrieb:
> 5. Am Listing oder im Debugger kontrollieren dass der Compiler keine
> double-Berechnungen ausführt. Das kostet sehr viel Zeit.

Matthias S. schrieb:
> Wozu machst du das rumgemurkse mit floats? Davon versteht dein DAC
> nichts und du musst erst mühselig Float wieder in Int zurückwandeln.

Immer wieder diese panische Angst vor float/double, die nur durch 
Vorurteile begründet ist. Hier ist von einem STM32F411 die Rede und 
nicht von AVR-GCC auf einem AVR oder einem BASIC-Interpreter mit 8051.
Macht konkrete Zeitangaben in ns für Eure Behauptungen, dann kann jeder 
selber entscheiden, ob der Weltuntergang bevorsteht oder eben doch 
wieder nicht.

von temp (Gast)


Lesenswert?

m.n. schrieb:
> Immer wieder diese panische Angst vor float/double, die nur durch
> Vorurteile begründet ist. Hier ist von einem STM32F411 die Rede und
> nicht von AVR-GCC auf einem AVR oder einem BASIC-Interpreter mit 8051.

Stop Kollege, so kann man das nicht stehen lassen! Float mit FPU auf 
einem F4 ist völlig in Ordnung. Im Gegenteil es ist oft schneller als 
eine Festkommaarithmetik. Da wo man früher noch mit vielen Tricks 
rumherhampeln musste um schnelle interrupttaugliche Berechnungen machen 
zu können, bietet sich da heute float als Alternative an. Aber nur 
solange nicht intern wieder float to double Wandlungen und zurück 
erfolgen bzw. Berechnungen in double. Da kann dann schon mal ein Faktor 
10 in der Zeit rauskommen. Klar wenn es auf die Zeit nicht ankommt 
spielt das alles keine Rolle.
Es kommt wie immer darauf an was man macht. Eine FOC Motorreglung 
komplett in float ist heute kein Ding mehr und oft leichter zu handhaben 
als mit int32 oder einem Festkommatyp zu arbeiten. Die Zeiten sind auch 
gut, und dabei wird fast alles im Interrupt der PWM gemacht. Aber wehe 
es schleichen sich double Berechnungen ein und der Compiler benutzt die 
Lib und nicht die FPU dafür. Dann werden aus 5 us Interruptlaufzeit 
schnell mal 20 und mehr.
Wenn man dann aber mit float arbeitet, sollte man auch keine starren 
Sinustabellen mehr verwenden. Seht euch mal die arm_sin_f32 aus der 
CMSIS dsp-lib an. Der Sinus wird da mit Tabelle und linearer oder 
cubischer Interpolation in <1us berechnet. Das lässt sich auch für 
andere Kurvenformen verwenden. Der große Vorteil davon ist, dass man die 
Tabellen nicht an PWM Zyklen und Auflösung bzw. Schrittweiten u.ä. 
anpassen muss.

von m.n. (Gast)


Lesenswert?

temp schrieb:
> Dann werden aus 5 us Interruptlaufzeit schnell mal 20 und mehr.

Das schreibst Du so daher. Glaub ich nicht - will ich sehen.

temp schrieb:
> Eine FOC Motorreglung
> komplett in float ist heute kein Ding mehr und oft leichter zu handhaben
> als mit int32 oder einem Festkommatyp zu arbeiten.

Das liest sich doch schon besser.

Matthias S. schrieb:
> und du musst erst mühselig Float wieder in Int zurückwandeln.

Um das noch einmal aufzugreifen: der Befehl zur Wandlung float32 -> 
int32 heißt VCVT und braucht einen Takt, was beim genannten F411 10 ns 
sind.
Weder mühselig (macht der Compiler) noch zeitverschwenderisch (macht der 
Prozessor) ;-)

von temp (Gast)


Lesenswert?

m.n. schrieb:
> Das schreibst Du so daher. Glaub ich nicht - will ich sehen.

Ob du das glaubst oder nicht ist mir ziemlich egal. Wenn du es genau 
wissen willst probier es an einem Beispiel aus.

Mal eins von mir:

1
  // das voaltile steht hier nur damit der Compiler 
2
  // die Schleife nicht wegoptimiert
3
  volatile float f=1.0f;
4
  while (1)
5
    {
6
    aLed.Toggle();
7
    for (int n=0; n<1000000; n++)
8
      {
9
      f*=3.1345f;  // das f am Ende der konstanten ist extrem wichtig!
10
      }
11
    }
12
13
Das ist aus dem Debugger kopiert und man sieht sehr schon die FPU 
14
Befehle    
15
    
16
for (int n=0; n<1000000; n++)
17
    2300        movs r3, #0
18
    657B        str r3, [r7, #0x54]
19
    E00A        b 0x08000F52
20
--- main.cpp -- 683 ----------------------------------------
21
{
22
f*=3.1345f;
23
    EDD77A14    vldr s15, [r7, #0x50]
24
    ED9F7A08    vldr s14, 0x08000F64
25
    EE677A87    vmul.f32 s15, s15, s14
26
    EDC77A14    vstr s15, [r7, #0x50]
27
--- main.cpp -- 685 ----------------------------------------
28
for (int n=0; n<1000000; n++)
29
    6D7B        ldr r3, [r7, #0x54]
30
    3301        adds r3, #1
31
    657B        str r3, [r7, #0x54]
32
--- main.cpp -- 683 ----------------------------------------
33
for (int n=0; n<1000000; n++)
34
    6D7B        ldr r3, [r7, #0x54]
35
    4A04        ldr r2, 0x08000F68
36
    4293        cmp r3, r2
37
    DDF0        ble 0x08000F3C

Für 2 Durchläufe werden ca. 1 sec gebraucht
So jetzt nochmal das ganze mit der selben Konstanten ohne dem f am Ende:

1
  volatile float f=1.0f;
2
  while (1)
3
    {
4
    aLed.Toggle();
5
    for (int n=0; n<1000000; n++)
6
      {
7
      f*=3.1345;  // hier jetzt ohne f
8
      }
9
    }
10
11
hier sieht man deutlich dass schon der erzeugte Code nicht schnell sein
12
kann
13
14
for (int n=0; n<1000000; n++)
15
    2300        movs r3, #0
16
    657B        str r3, [r7, #0x54]
17
    E017        b 0x08000F70
18
--- main.cpp -- 683 ----------------------------------------
19
{
20
f*=3.1345;
21
    6D3B        ldr r3, [r7, #0x50]
22
    4618        mov r0, r3
23
    F000FEAC    bl 0x08001CA0 <__extendsfdf2>
24
    4602        mov r2, r0
25
    460B        mov r3, r1
26
    4610        mov r0, r2
27
    4619        mov r1, r3
28
    A30B        adr r3, 0x08000F80
29
    E9D32300    ldrd r2, r3, [r3, #0]
30
    F001F841    bl 0x08001FDC <__muldf3>
31
    4602        mov r2, r0
32
    460B        mov r3, r1
33
    4610        mov r0, r2
34
    4619        mov r1, r3
35
    F000FEB9    bl 0x08001CD8 <__float64_to_float32>
36
    4603        mov r3, r0
37
    653B        str r3, [r7, #0x50]
38
--- main.cpp -- 685 ----------------------------------------
39
for (int n=0; n<1000000; n++)
40
    6D7B        ldr r3, [r7, #0x54]
41
    3301        adds r3, #1
42
    657B        str r3, [r7, #0x54]
43
--- main.cpp -- 683 ----------------------------------------
44
for (int n=0; n<1000000; n++)
45
    6D7B        ldr r3, [r7, #0x54]
46
    4A07        ldr r2, 0x08000F90
47
    4293        cmp r3, r2
48
    DDE3        ble 0x08000F40

2 Durchläufe bei dieser Variant brauchen ca. 5s!

So und jetzt Du...

von m.n. (Gast)


Lesenswert?

Gerne.
Bei der double Version braucht jeder Schleifendurchlauf 2,5 µs, was doch 
in Ordnung ist. 2,5 µs sind ja schneller, als Du oben für Deine 
float-ISR angesetzt hattest. Und das, obwohl Du durch "volatile float f" 
noch eine Bremse eingebaut hast ;-)

Daß double bei Berechnungen länger dauern als float, ist doch klar, 
insbesondere wenn die FPU das nicht unterstützt. Aber wenn man double 
braucht, dann muß man double nehmen und nicht mit dem Schreckgespenst im 
Nacken: bloß nicht - streng verboten!

Um die Sache noch einmal etwas nüchterner zu betrachten:
Den verwendeten µC und die Taktfrequenz gibst Du nicht an, aber ich 
vermute den F407 mit 168 MHz. Läßt man die Konvertierungen aus Deinem 
Beispiel einmal weg, dann dauert die double-Multiplikation geschätzt <= 
1,5 µs.
Ich finde das richtig schnell!

von Mike R. (thesealion)


Lesenswert?

Jim M. schrieb:
> Da ist was mit dem Wertebereich von i kaputt. Hast Du Dir mal die
> Zwischenwerte von i im Debugger angesehen?

Ich würde sagen, diese Aussage ist genau richtig.

Ich weiß nicht, ob der TE jetzt noch mitliest, aber der Fehler in diesem 
Programm liegt (wieder einmal) in elementarsten C Fehlern)
1
int i = 4096+voltage;
2
...       
3
i = voltage*(m_sinus[t]);
4
i = (4095/3.61)*i;

Wenn man sich das m_sinus array ansieht, fällt einem auf, das dort 
kein Wert größer gleich 1 ist. Und 0.5 * <1 gibt immer eine 0.
Bei der nächsten Zeile bleibt das also 0 für i.
1
write_out(i+4096);
Diese Funktion sendet also immer nur 4096 an den DAC. (Wenn ich das 
richtig gesehen habe, ist das gesetzte Bit ein Konfigurationswert, 
ansonsten wäre es zusätzlich noch ziemlich sinnlos, da der DAC nur 12Bit 
hat und 4096 somit außerhalt der 12bit liegt).

von R. R. (elec-lisper)


Lesenswert?

Mike R. schrieb:
>
1
> int i = 4096+voltage;
2
> ...
3
> i = voltage*(m_sinus[t]);
4
> i = (4095/3.61)*i;
5
>
>
> Wenn man sich das m_sinus array ansieht, fällt einem auf, das dort
> kein Wert größer gleich 1 ist. Und 0.5 * <1 gibt immer eine 0.
> Bei der nächsten Zeile bleibt das also 0 für i.

Und was ist mit der Zeile am Anfang von main()? =>
1
voltage =(4095/3.61)*voltage;

Wird dort das voltage bei der Multiplikation nach int gecastet?

von temp (Gast)


Lesenswert?

m.n. schrieb:
> Daß double bei Berechnungen länger dauern als float, ist doch klar,
> insbesondere wenn die FPU das nicht unterstützt. Aber wenn man double
> braucht, dann muß man double nehmen und nicht mit dem Schreckgespenst im
> Nacken: bloß nicht - streng verboten!

Es geht nicht um streng verboten! Und zeig mir mal den Cortex M 
Controller der double in der FPU kann. Es geht nur darum die Sinne zu 
schärfen worauf man beim Einsatz von float achten muss. Es ist eben 
nicht sofort ersichtlich dass die Multiplikation einer float Variablen 
mit einer Konstanten automatisch in double endet, wenn die Konstante 
nicht ausdrücklich als float gekennzeichnet wird.

>
> Um die Sache noch einmal etwas nüchterner zu betrachten:
> Den verwendeten µC und die Taktfrequenz gibst Du nicht an, aber ich
> vermute den F407 mit 168 MHz. Läßt man die Konvertierungen aus Deinem
> Beispiel einmal weg, dann dauert die double-Multiplikation geschätzt <=
> 1,5 µs.
> Ich finde das richtig schnell!

Das ist ein STM32F334 mit 64MHz! Keine Frage auch die 1,5µs für eine 
double Multiplikation sind schnell. Kostet aber nur mal so aus versehen 
die 5 fache Zeit als wenn man den Flüchtigkeitsfehler nicht gemacht 
hätte. Bei einer PWM mit 50kHz bleiben 20µs für einen Zyklus. Da spielt 
es schon eine Rolle ob ich mit 10 Multiplikation schon fast am Poller 
bin oder meilenweit davon entfernt.

von Mike R. (thesealion)


Lesenswert?

Robin R. schrieb:
> Und was ist mit der Zeile am Anfang von main()? =>voltage
> =(4095/3.61)*voltage;
>
> Wird dort das voltage bei der Multiplikation nach int gecastet?

Die Zeile hab ich irgendwie übersehen.

Dann bleibt nur noch die "völlig" falsche Berechnung.
Alleine für den ersten Wert, der an den DAC geht, bin ich gerade auf 
326251 gekommen (wenn ich nicht schon wieer etwas übersehen habe)

von MIrco (Gast)


Angehängte Dateien:

Lesenswert?

Robin R. schrieb:
> Mike R. schrieb:
>>> int i = 4096+voltage;
>> ...
>> i = voltage*(m_sinus[t]);
>> i = (4095/3.61)*i;
>> >
>> Wenn man sich das m_sinus array ansieht, fällt einem auf, das dort
>> kein Wert größer gleich 1 ist. Und 0.5 * <1 gibt immer eine 0.
>> Bei der nächsten Zeile bleibt das also 0 für i.
>
> Und was ist mit der Zeile am Anfang von main()? =>voltage
> =(4095/3.61)*voltage;
>
> Wird dort das voltage bei der Multiplikation nach int gecastet?

Ja, danke. den Fehler habe ich schon bemerkt.

Das mit dem Tipp mit der float Variable habe ich auch schon bemerkt. Ich 
habe die Variablen schon alle in Float umgewandelt und muss schreibe 
jetzt mein eigenes Programm ohne die GPIO-Lib. Wenn ich den diese 
benutze und einen Pin toggle dauert der Befehl insgesamt 200 ns und da 
ich das in einer Schleife aufrufe, summiert sich die Zeit schon 
beträchtlich.




Eine andere Frage wenn ich die fsclk auf 50 MHz setze bekomme ich am 
SCLK PIn/D13  die CLockrate von 50 MHz zwar hin, aber habe eine 
Pausenzeit des SPIs von ungefähr einer 1 us (siehe Bild). Dabei schreibe 
ich nur in der while schleife irgend einen Wert auf den Bus.
Andererseits verwende ich aktuell die ganzen umfangreichen Libs. Ich 
weiß, da ich möglichst schnell arbeiten möchte, ist es unschön das ich 
diese verwende.

Da mir auch die Erfahrung mit dem Mikrocontroller fehlt, wollte ich euch 
vorab fragen, ob es überhaupt machbar ist die Pausenzeit auf z.B. 500ns 
zu verkürzen?! Die minimalé Pausenzeit beträgt schließlich 320 ns 
((50MHz/16bit)^-1)

von Ohm (Gast)


Lesenswert?

Mike R. schrieb:
> Alleine für den ersten Wert, der an den DAC geht, bin ich gerade auf
> 326251 gekommen

Ich bin auf den gleichen Wert gekommen. Was macht die SPI-Übertragung 
mit den 3 überzähligen Bits. Egal, ob sie vorn oder hinten abgeschnitten 
werden, es kommt garantiert nicht das aus dem DAC, was der TE wollte.

von MIrco (Gast)


Lesenswert?

Ohm schrieb:
> Mike R. schrieb:
>> Alleine für den ersten Wert, der an den DAC geht, bin ich gerade auf
>> 326251 gekommen
>
> Ich bin auf den gleichen Wert gekommen. Was macht die SPI-Übertragung
> mit den 3 überzähligen Bits. Egal, ob sie vorn oder hinten abgeschnitten
> werden, es kommt garantiert nicht das aus dem DAC, was der TE wollte.

Ja, das Problem habe ich mittlerweile beseitigt und bekomme einen Sinus 
aus meinem DAC heraus.

von m.n. (Gast)


Lesenswert?

temp schrieb:
> Und zeig mir mal den Cortex M
> Controller der double in der FPU kann.

http://www.atmel.com/devices/ATSAMS70J19.aspx
zum Beispiel, ohne daß Du Dich gleich auf den M7 stürzt ;-)

temp schrieb:
> Das ist ein STM32F334 mit 64MHz! Keine Frage auch die 1,5µs für eine
> double Multiplikation sind schnell.

Hochgerechnet auf den ..F411 (100 MHz) bleiben ca. 1 µs und auf den 
..F407 (168 MHz) rund 0,5 µs. FDIV hatte ich an anderer Stelle mal 
gemessen: 
Beitrag "Re: Controller mit FPU"
Für die meisten Anwendungen reicht sicherlich 'float' aus. Soll jeder 
(vorurteilsfrei) entscheiden, wie er es braucht und mag.


Wenn der TO mit dem F411 etwas warm geworden ist, kann er die 
Kurvenausgabe vielleicht optimieren:

Tabelle für Sinuswerte (im Programm!) errechnen, skalieren und als 
int-Tabelle ablegen
DMA-Controller für zyklische Ausgabe konfigurieren
Tabellenwerte mit Timer gesteuert per DMA ausgeben

So würde ich es machen, wenn es mit minimaler CPU-Last schnell gehen 
soll.

von Mirco (Gast)


Lesenswert?

Hallo,

ich wollte den Thread noch einmal hoch pushen und nachfragen, ob einer 
von euch Richtwerte für die Verarbeitungszeit von verschiedenen Befehlen 
hat z.B. Pin von High auf Low ziehen oder irgendwelche Werte aus einer 
Matrix ausgeben etc... (Die Basics meines Programms)


Was ist die maximale SPI Ausgabefrequenz z.b. oder in Assembler ?

Wie ich oben beschrieben habe, erreiche ich aktuell die oben genannten 
Werte.

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.