Forum: Mikrocontroller und Digitale Elektronik STM32F4 DMA DAC Ringpuffer - Komisches Verhalten bei Sinusgenerierung - Bitte um Hilfe


von Tobias P (Gast)


Angehängte Dateien:

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!

von Tobias P. (Gast)


Lesenswert?

Keiner eine Idee?

von Jonas B. (jibi)


Lesenswert?

Mach mal
DMA_InitStructure.DMA_BufferSize = 1;

und schaue was für eine Spannung ausgegeben wird, müsste ja konstant 
1,65Volt sein, berichte dann hier.

Gruß Jonas

von benwilliam (Gast)


Lesenswert?

was ist das denn für ein array das du nutzt?
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Sinus12bitWeighted;

dachte du brauchst das const uint16_t Sinus12bit ?

von Jonas B. (jibi)


Lesenswert?

>Sinus12bitWeighted

Der Sinus ist doch "gewichtet". Also das passt schon. Copy paste error?

Deswegen immer den kompletten Code posten!

Manoman

: Bearbeitet durch User
von Lutz H. (luhe)


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

: Bearbeitet durch User
von Tobias P. (Gast)


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.

von Lutz H. (luhe)


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.

von Chris D. (myfairtux) (Moderator) Benutzerseite


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.

: Bearbeitet durch Moderator
von Jonas B. (jibi)


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

: Bearbeitet durch User
von Tobias P. (Gast)


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

von Tobias P. (Gast)


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.

von Jonas B. (jibi)


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

von Jonas B. (jibi)


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

von benwilliam (Gast)


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;

von Jonas B. (jibi)


Lesenswert?

Warum?

>@ Jonas:

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

: Bearbeitet durch User
von Jonas B. (jibi)


Lesenswert?

>kaumänische

Will nicht wissen was du so treibst :D

Sorry...

von technikus (Gast)


Lesenswert?

@ Tobias:
Hast du den Fehler gefunden ?


Gruß

von Tobias P. (Gast)


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.

von Jonas B. (jibi)


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

von Tobias P. (Gast)


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.

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.