Forum: Mikrocontroller und Digitale Elektronik STM32 Six-step PWM signal generation using TIM1


von Fabian L. (fabls)


Angehängte Dateien:

Lesenswert?

Hallo Liebe Forum Mitglieder,

ich Arbeite momentan mit einem Stm32 Cortex M3 Chip das Thema mit dem 
ich mich befasse geht über einen Bürstenlosen DC Motor, den ich mittels 
PWM Signal ansteuern will. Da die STM32 Library ein Beispiel beinhaltet 
über ein 6 Stufen PWM Signal habe ich dieses zum Start benutzt. Das 
Problem liegt nun, dass wenn ich den Code auf meinen uC lade werden die 
PWM Signale nicht so ausgegeben wie auf dem hoch geladenen Bild. In der 
read.txt steht drinnen das man ein COM Signal mit der Software erstellen 
soll, dies mache ich mit dem TIM_GenerateEvent(TIM1, 
TIM_EventSource_COM); Befehl. Aber wenn ich nun meine Signale auf dem 
Oszilloskop anschaue dann kommt nur eine konstante Spannung von 3,3V und 
es entsteht kein PWM Signal.

Meine Frage ist nun, ob mir jemand sagen kann was der Fehler ist bzw. 
was ich Falsch mache. Wenn ihr weitere Details benötigt könnt ihr mir 
bescheid geben.
Ich Bedanke mich schon mal im Voraus

Mit freundlichen Grüßen

Fabian

von Nils P. (ert)


Lesenswert?

poste deine Init-function sonst kann man hier nur raten...

prinzipell:
1) Clock einschalten (für timer und Ports)
2) Timer init
3) Timer OC init für alle drei channels --> high + Low
4) Totzeit setzen
5) Evtl noch ADC an den Timer koppeln

Gruß ert

von Fabian L. (fabls)


Lesenswert?

Danke für deine schnelle Antwort :)

Es wird nur die stm32f10x.h noch benutzt.

Die Totzeit stell ich doch mit folgendem Code ein oder?

  /* Automatic Output enable, Break, dead time and lock configuration*/
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
  TIM_BDTRInitStructure.TIM_DeadTime = 1;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
  TIM_BDTRInitStructure.TIM_AutomaticOutput = 
TIM_AutomaticOutput_Enable;

Also mit dem Befehl:
TIM_BDTRInitStructure.TIM_DeadTime = 1;

von Nils P. (ert)


Lesenswert?

jaein. Musst schon den Stuct der BDTRConfig übergeben.

Für den ersten Test lass ermal die Totzeit weg (und die B6 Brücke 
natürlich auch)

1b) ist natürlich die alternate function den Pins zuzuweisen.

von Fabian L. (fabls)


Lesenswert?

Danke für deine Antwort.

Die struct wird am ende der BDTRConfig übergeben hab es nur nicht mit 
reinkopiert. Die Pins sind auch auf Alternate Function push pull 
gesetzt.
Ich denke das Problem liegt bei dem COM event was man per Software 
setzen soll oder per Hardware

Aus der Read.txt :

"The COM event can be generated by software by setting the COM bit in 
the TIM1_EGR register or by hardware (on TRGI rising edge)."

Um das COM event zu generieren benutze ich die Funktion 
TIM_GenerateEvent(TIM1, TIM_EventSource_COM);
Die Funktion setze ich am Ende des Codes.

Um die Channel der Timer für das PWM einzustellen ist in dem Example 
Code
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing; eingestellt. Ich 
habe das auf TIM_OCMode_PWM1 eingestellt damit überhaupt ein PWM Signal 
kommt. Sobald ich TIM_OCMode_PWM1 eingestellt habe und 
TIM_GenerateEvent(TIM1, TIM_EventSource_COM); gesetzt habe, bekomme ich 
auf dem Oszilloskop auch nur noch konstant die 3,3V angezeigt.

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


Lesenswert?

Ich poste hier mal eine komplett lauffähige Init für Timer 1 und drei 
PWM Kanäle. Lediglich der Interrupt ist hier nicht initialisiert. 
Vergleich das mal mit deinem Code. Auch denke dran das die Clock für den 
PWM Port angeschaltet werden muss:
1
// 3 PWM Channels. Use UpdateDTI() to set the deadtime
2
void TimerInit(void) {
3
4
RCC_APB2PeriphClockCmd(TIM1_CLK, ENABLE);
5
/* Initialize basic structures to default */
6
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
7
TIM_OCStructInit(&TIM_OCInitStructure);
8
/* Time base configuration */
9
10
TIM_TimeBaseStructure.TIM_Prescaler = 256;
11
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
12
TIM_TimeBaseStructure.TIM_Period = 0x00FF;
13
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
14
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
15
16
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
17
TIM_UpdateRequestConfig(TIM1, TIM_UpdateSource_Global);
18
TIM_UpdateDisableConfig(TIM1,DISABLE);
19
20
/* Channel 1, 2 and 3 Configuration in PWM mode */
21
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
22
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
23
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
24
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
25
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
26
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
27
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;
28
29
TIM_OCInitStructure.TIM_Pulse = 0x0000;
30
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
31
TIM_OCInitStructure.TIM_Pulse = 0x0000;
32
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
33
TIM_OCInitStructure.TIM_Pulse = 0x0000;
34
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
35
}
36
/* Update the BDTR register with deadtime setting, break features and output options
37
 */
38
void UpdateDTI(u8 deadTime){
39
40
  TIM_BDTRStructInit(&TIM_BDTRInitStructure);
41
  /* Automatic Output enable, Break, dead time and lock configuration*/
42
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
43
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
44
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
45
  TIM_BDTRInitStructure.TIM_DeadTime = deadTime;
46
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
47
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
48
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
49
  TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
50
}

von Fabian L. (fabls)


Lesenswert?

Danke für deine schnelle Antwort :).

Also das PWM Signal wird bei mir korrekt Angezeigt nur die Channel 1-3 
sind nicht Phasenverschoben, ich benötige die Phasenverschiebung,da ich 
die Signale für eine Motor Control Steuerung benutzen möchte.

__|--|_____|--|__
_____|--|______|--|__
--|______|--|______|--|__
Damit die Signale 120° Phasenverschoben sind.

Deine BDTR Funtkion, die du gepostet hast, Updatest du mit Werten. Nun 
meine Frage benutzt du für die Werte noch einen anderen Timer oder eine 
einfache schleife?

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


Lesenswert?

Fabian L. schrieb:
> Nun
> meine Frage benutzt du für die Werte noch einen anderen Timer oder eine
> einfache schleife?

Wofür jetzt? Die Totzeit wird beim Programmstart aus einem EEPROM 
gelesen und dann einmal gesetzt. Für Blockkommutierung benutze ich 
enable/disable der OC Outputs, das geht am schnellsten (mittels des CCER 
Registers). Umschalten tue ich in der Interrupt Routine für die 
Hallsensoren, da ich hier nur Motoren mit Sensoren steuere. Die Werte in 
der PWM werden im Timerüberlauf Interupt aufgefrischt und kommen von der 
Drehlzahlregelung.
Bei Blockkommutierung stehen in allen drei CC Registern die gleichen 
Werte, sobald ich auf Sinus umstelle, natürlich nicht mehr. Die 
Phasenverschiebung für Sinusmodulation kommt in bewährter Weise aus 
einer Tabelle (siehe AVR447, die ich auf den STM32 angepasst habe).

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.