Forum: Mikrocontroller und Digitale Elektronik STM32 DACs mit DMA Phasenverschiebung


von Peter (Gast)


Lesenswert?

Hallo,

ich habe an meinem STM32F407 2 DAC Kanäle in Benutzung und würde dort 
gerne eine Sinus-Waveform mit variabler Phasenbeziehung ausgeben. Sprich 
die Waveform ist für beide Kanäle die selbe, die Phase soll gerampt 
werden um einen Kondensatormotor zum Anlaufen zu bewegen. Im Moment 
nutze ich TIM2 als Trigger um mittels circular DMA (2 DACs, 2 
DMA-Kanäle) die Werte aus einer LUT zum jeweiligen DAC-Kanal zu bringen. 
Das funktioniert auch sehr gut. Die Frequenz lässt sich über den 
TIM2-reload-value ARR verstellen. Die Zielfrequenz liegt irgendwo 
zwischen 1 und 1kHz.
1
#include "main.h"
2
 
3
#define NS  128
4
 
5
const uint32_t Wave_LUT[NS] = {
6
2048, 2149, 2250, 2350, 2450, 2549, 2646, 2742, 2837, 2929, 3020, 3108, 3193, 3275, 3355, 3431, 3504, 3574, 3639, 3701, 3759, 3812, 3861, 3906, 3946, 3982, 4013, 4039, 4060, 4076, 4087, 4094, 4095, 4091, 4082, 4069, 4050, 4026, 3998, 3965, 3927, 3884, 3837, 3786, 3730, 3671, 3607, 3539, 3468, 3394, 3316, 3235, 3151, 3064, 2975, 2883, 2790, 2695, 2598, 2500,    2400, 2300, 2199, 2098, 1997, 1896, 1795, 1695, 1595, 1497, 1400, 1305, 1212, 1120, 1031, 944, 860, 779, 701, 627, 556, 488, 424, 365, 309, 258, 211, 168, 130, 97, 69, 45, 26, 13, 4, 0, 1, 8, 19, 35, 56, 82, 113, 149, 189, 234, 283, 336, 394, 456, 521, 591, 664, 740, 820, 902, 987, 1075, 1166, 1258, 1353, 1449, 1546, 1645, 1745, 1845, 1946, 2047
7
};
8
 
9
DAC_HandleTypeDef hdac;
10
DMA_HandleTypeDef hdma_dac_ch1;
11
DMA_HandleTypeDef hdma_dac_ch2;
12
TIM_HandleTypeDef htim2;
13
 
14
int main(void)
15
{
16
    HAL_Init();
17
    SystemClock_Config();
18
    MX_GPIO_Init();
19
    MX_DMA_Init();
20
    MX_DAC1_Init();
21
    MX_DAC2_Init();
22
    MX_TIM2_Init();
23
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)Wave_LUT, 128, DAC_ALIGN_12B_R);
24
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t*)Wave_LUT, 128, DAC_ALIGN_12B_R);
25
    HAL_TIM_Base_Start(&htim2);
26
 
27
    while (1)
28
    {
29
 
30
    }
31
}

Nun würde ich gerne die Phasenbeziehung zwischen DAC1 und DAC2 im 
Betrieb veränderbar haben. Konkret soll die Phase später über eine 
Rampenfunktion geführt werden. Nun stellt sich mir die Frage wie ich am 
elegantesten die Phase der LUT verändere (wenn möglich ohne eine der 
beiden LUTs für jede Phasenbeziehung neu zu berechnen).
- Dazu fällt mir spontan ein: Start-Adresse des DMA verändern -> geht 
das, wenn ja wie (circular)?
- Welche anderen Möglichkeiten seht ihr? (Asynchroner Start? Wenn ja 
wie?)

Danke

von Knaxtus (Gast)


Lesenswert?

Peter schrieb:
> - Dazu fällt mir spontan ein: Start-Adresse des DMA verändern -> geht
> das, wenn ja wie (circular)?

Natürlich geht das.
Ohne jetzt zu wissen, was HAL_DAC_Start_DMA() genau
macht, ist das 3. Arg (WaveLUT in Deinem Fall) wohl die Startadresse.
Da kannst Du nat einen bel. Wert übergeben.
Das 4. Arg (128) ist wohl die Anzahl der Samples.
Du müsstest also den DMA in einen nicht-zyklischen Teil, der bei
der gewünschten Startadresse losläuft (Sample-Zahl entsprechend 
anpassen)
und in einen zyklischen Teil, aufteilen.
Der zyklische DMA Transfer wäre dann nach dem Ende des nicht-zyklischen
zu starten, z.B. per DMA-End-of-Transfer Interrupt-Handler

> - Welche anderen Möglichkeiten seht ihr? (Asynchroner Start? Wenn ja
> wie?)

Per TIM2 Interrupt-Handler mitzählen und bei einem geeigneten Zählerwert
den DMA Transfer für den 2. Kanal starten?

Bei einem max 1 kHz Signal stellt sich nat dir Frage, warum man sich 
überhaupt
mit DMA rumschlagen sollte. Oder ist Dein Controller schon am Anschlag?

von foobar (Gast)


Lesenswert?

> Bei einem max 1 kHz Signal stellt sich nat dir Frage, warum man sich
> überhaupt mit DMA rumschlagen sollte.

1kHz mal 128 Samples pro Periode ...

von 542325 (Gast)


Lesenswert?

die LUT müsste um eine halbwelle vegrößert werden
so das es 3 halbwellen sind
einen DMA kanal setzt du einen offset um eben maximal eine halbwelle
1
uint32_t phase = xxx ; //  0...63 
2
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)Wave_LUT + phase , 128, DAC_ALIGN_12B_R);
Auflösung ist begrenzt ... 64 phasenstufen
das ist erstmal quick&dirty ....

mit interrupt kannst das auch zur laufzeit ohne stop/neustart des DMA
machen

half transfer/full transfer
dann den circular buffer vergrößern ( x2 )
und den half/full transfer interrupt nutzen zum switchen der buffer

so ist z.B der erste buffer in benutzung und der zweite kann dann im 
rest des programms bearbeitet werden.
z.b.  füllen mit neu berechneten Daten

wird zB bei vielen Audioapplikationen gemacht


mit DMA sind das recht wenige Interrupts pro sekunde

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.