STM32F4 DMA DAC Ringpuffer - Komisches Verhalten bei Sinusgenerierung - Bitte um Hilfe

Gast #3474368
Lesenswert?

Hallo liebe Mikrocontroller-Community,

ich habe ein Problem und würde mich freuen wenn mir einer helfen kann.

Ich benutze den STM32F407 um ein Sinus-Signal mit einer Mittenspannung 
von 1,65 Volt zu erzeugen.

Grundlage ist eine Konstante innerhalb welcher eine Periode als Werte 
abgespeichert sind:
1
const uint16_t Sinus12bit[100] = {
2
        2048, 2176, 2304, 2431, 2557, 2680, 2801, 2919, ... 1791, 1919};

2048 stellt als Startwert die Mittenspannung 1,65 Volt dar.

Ich verwende weiterhin einen DMA um die Werte der Konstante in den DAC 
zu schreiben. Der DMA ist als Ringpuffer konfiguriert und durchläuft 
diesen auf Basis eines Timers.

Das funktioniert alles wunderbar, mit einer einzigen Ausnahme: der DAC 
startet nicht bei 2048 den Durchlauf sondern bei einem Wert, welcher 0,8 
Volt entspricht. Siehe das angehängte Bild.

Ich habe keine Ahnung woran das liegen kann, fällt euch was ein?

Hier ein Teil des Initialisierungscodes:
1
    DAC_StructInit(&DAC_InitStructure);
2
      DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
3
      DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
4
      DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
5
      DAC_Init(DAC_Channel_2, &DAC_InitStructure);
6

7
      DMA_DeInit(DMA1_Stream6);
8
      DMA_InitStructure.DMA_Channel = DMA_Channel_7;
9
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS;
10
      DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Sinus12bitWeighted;
11
      DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
12
      DMA_InitStructure.DMA_BufferSize = 100;
13
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
14
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
15
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
16
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
17
      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
18
      DMA_InitStructure.DMA_Priority = DMA_Priority_High;
19
      DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
20
      DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
21
      DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
22
      DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
23
      DMA_Init(DMA1_Stream6, &DMA_InitStructure);
24

25
      DAC_Cmd(DAC_Channel_2, ENABLE);
26
      DMA_Cmd(DMA1_Stream6, ENABLE);
27
      DAC_DMACmd(DAC_Channel_2, ENABLE);

Im DAC Channel 2 output buffer stehen die 0,8 Volt als Startwert bereits 
nach der Initialisierung DAC_Cmd(); drin.

Vielen Dank schonmal im Voraus für eure Mühen!
Angehängte Dateien:
#3479211
Lesenswert?

Hallo,

es könnte sein, dass die  ersten Werte der Wertetabelle nicht dem Sinus 
von 0 Grad entsprechen, sondern zum Beispiel bei -45 ° beginnen.
Wie sieht es aus, wenn die ersten 25 Werte  von  Sinus12bit[100] am 
Ende stehen?
Dann müsste die Kurve auf einen höheren Spannungswerte beginnen.
Der genaue Index für 0 Grad müsste  nochmal genau berechnet werden.

Gruß Lutz
Gast #3479245
Lesenswert?

@ Jonas:

In der tat führt Buffersize=1 dazu, dass konstant 1,65 Volt am Ausgang 
stehen.

@ benwilliam:

Sinus12BitWeighted passt soweit:
1
if (Weight<=1){
2

3
      for (i=0; i<100; i++){
4
        IntermediateValue = Sinus12bit[i];
5
        IntermediateValue = (IntermediateValue-2047)*Weight+2047;
6
        Sinus12bitWeighted[i] = IntermediateValue;
7
      }
8
    } else {
9
      for (i=0; i<100; i++){
10
          Sinus12bitWeighted[i] =0;
11
        }
12
    }

Verwende ich Sinus12Bit anstatt dem neu berechnetten Vektor habe ich das 
gleiche problem wie vorher.

@ Lutz:

Verschiebe ich die Werte kommt es in der tat dazu, dass irgendwann Start 
und Endwert stimmen.

Das löst zwar die Problematik, aber nicht das Verständnis, woher diese 
"Phasenverschiebung" kommt und der Ringpuffer irgendwo anfängt und nicht 
am Anfang des Arrays.
#3479279
Lesenswert?

Tobias P. schrieb:
> Das löst zwar die Problematik, aber nicht das Verständnis, woher diese
> "Phasenverschiebung" kommt und der Ringpuffer irgendwo anfängt und nicht
> am Anfang des Arrays.

Der Ringpuffer wurde von irgendjemanden berechnet,
und da sind Wertepaare hinterlegt.
Der index 0 entspricht dem Sinus eines bestimmten Winkels , und so 
weiter.
Logik ist da keine . An jedem beliebigen Index kann so jeder beliebige 
Spannungswert ausgegeben werden.

Der Hintergrund ist, dass die Sinusberechnung ziemlich aufwendig ist,
und deshalb oft Wertetabellen genutzt werden, bei denen die Berechnung
lange vordem Nutzen der Werte erfolgt.
Moderator Persönliche Seite #3479286
Lesenswert?

lutz h. schrieb:
> Tobias P. schrieb:
>> Das löst zwar die Problematik, aber nicht das Verständnis, woher diese
>> "Phasenverschiebung" kommt und der Ringpuffer irgendwo anfängt und nicht
>> am Anfang des Arrays.
>
> Der Ringpuffer wurde von irgendjemanden berechnet,
> und da sind Wertepaare hinterlegt.
> Der index 0 entspricht dem Sinus eines bestimmten Winkels , und so
> weiter.
> Logik ist da keine . An jedem beliebigen Index kann so jeder beliebige
> Spannungswert ausgegeben werden.
>
> Der Hintergrund ist, dass die Sinusberechnung ziemlich aufwendig ist,
> und deshalb oft Wertetabellen genutzt werden, bei denen die Berechnung
> lange vordem Nutzen der Werte erfolgt.

Das dürfte Tobias klar sein und die ersten Werte der Tabelle sehen ok 
aus - das dürfte sin(2048*x)+2048 sein. Die Referenzspannungen sind 
offensichtlich auch da, sonst wäre das Oszillogramm nicht so, wie es 
ist.

Was fehlt ist ein: DAC_DeInit();

Aber das dürfte eigentlich nicht das Problem lösen.
#3479389
Lesenswert?

>IntermediateValue-2047

Nur nebenbei: Wie kommst du auf 2047 überall in den Berechnungen?

>Das löst zwar die Problematik, aber nicht das Verständnis, woher diese
>"Phasenverschiebung" kommt und der Ringpuffer irgendwo anfängt und nicht
>am Anfang des Arrays.

>@ Jonas:

>In der tat führt Buffersize=1 dazu, dass konstant 1,65 Volt am Ausgang
>stehen.

Erhöhe mal langsam den Wert für Buffersize und schaue was passiert.

Ich vermute ein Pointer | Überlauf | falscher cast etc Problem, bzw. 
kann es sein dass der dac noch nicht ready ist und daher die ausgabe 
mitten im ringbuffer beginnt? nur ein gedanke...



Gruß Jonas
Gast #3479481
Lesenswert?

Weil 2047 "meine " gewählte Mittenspannung ist. Ob 2048 oder 2047 ist ja 
eigentlich egal. Basis sind die 12 bit vom ADC.

Wenn ich die Buffersize erhöhe sieht das ganze richtig zerwirscht aus. 
DAC bricht nach den 100 Werten zusammen. Vermutlich weil Buffer 
natzürlich leer. Natürlich periodisch.

Pointer würde ich gerne mal finden für den Ringpuffer ...

Zwischen Initialisierung und betrieb des DACs vergehen mindestens 2 ms, 
sollte reichen.

LG
Gast #3479486
Lesenswert?

Ich habe jetzt erstmal die Phasenverschiebung angepasst. Ich warte 
einfach mal drauf das sich das ganze auf Grund weiterer 
Programmierarbeiten verschiebt, dann könnte ich die Ursache eingrenzen.
#3479491
Lesenswert?

>Ich habe jetzt erstmal die Phasenverschiebung angepasst. Ich warte
>einfach mal drauf das sich das ganze auf Grund weiterer
>Programmierarbeiten verschiebt, dann könnte ich die Ursache eingrenzen.

Möp. Schlechteste was du tun kannst. Ich würde dem auf den Grund gehen, 
oder den Code rausnehmen und mich um andere Dinge kümmern, aber auf den 
aktuellen Code willst du nicht weiter aufbauen...Nur ein Tip.

Gruß Jonas
#3479538
Lesenswert?

>Pointer würde ich gerne mal finden für den Ringpuffer ...

Ehm ?

>DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Sinus12bitWeighted;

Das Array ist eine Datenstruktur, auf das erste Element des Arrays 
zeigst du hier und das ist eine Adresse = Pointer :)

Oha, jetzt gibt's bestimmt haue von den Mods weil ich was falsch erklärt 
hab...

Gruß Jonas
Gast #3479571
Lesenswert?

arrg fehlt hier nicht das kaumänische '&' ? :)
1
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Sinus12bitWeighted;

also müsste es nicht so lauten?
1
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&Sinus12bitWeighted;
Gast #3480564
Lesenswert?

@Jonas: Auf dem Code wird nicht weiter aufgebaut, keine Sorge. Fehler 
ist nicht gefunden.

Deine Pointer-Theorie stimmt hier nicht, sonst würde das problematische 
Verhalten ja nicht auftreten. Der Ringpuffer startet eben woanders als 
der Pointer des Arrays anzeigt.

Es führt zu 1,65 Volt weil das der einzige Wert ist der vom DMA in den 
Puffer geladen wird und in den DAC geschrieben.

@benwilliam: Ist egal.

@technikus: Leider nein.
#3480569
Lesenswert?

>Deine Pointer-Theorie stimmt hier nicht, sonst würde das problematische
>Verhalten ja nicht auftreten.

>>@ Jonas:

>>In der tat führt Buffersize=1 dazu, dass konstant 1,65 Volt am Ausgang
>>stehen.

Mit Buffersize=1 hast du doch überprüft das es sich um kein 
Pointer-Problem handelt, der richtige Wert wird von der richtigen 
Adresse (Start des Arrays = Ringsbuffers) in den DAC geschrieben, sogar 
wie gewollt 2 bytes in der richtigen Bytereihenfolge. Jetzt kann 
eigentlich nur noch was an der Konfiguration des DMA's nicht passen. Und 
da musst du ansetzen.


Gruß Jonas
Gast #3506728
Lesenswert?

Bei einem Wert im Puffer gibts ja auch nur einen möglich Startwert.

Ich konnte dem Problem immernoch nicht auf die Spur kommen.

Die Phasenverschiebung ändert sich mit unterschiedlichem Zeitpunkt der 
Initialisierung. Wenn ich alles während der Programmausführung neu 
initialisiere habe ich eine andere Phasenverschiebung.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren