Forum: Mikrocontroller und Digitale Elektronik STM32F4 Timer 5 PWM Problem


von Marcel D. (rubmack)


Lesenswert?

Guten Abend zusammen.
Ich arbeite gerade an meinem STM32F4Discovery Board und habe folgendes 
Problem. Ich versuche die Pins PA1 und PA8 zu nutzen um ein PWM Signal 
auszugeben.

An dem Pin PA8 ist das gar kein Problem. Jedoch für den Pin PA1, 
zusammen mit dem Timer 5 Channel 2, funktioniert das nicht. Ich habe 
bereits etliche Foren Posts durchgeblättert, doch auch wenn ich den Pin 
PA1 identisch wie in diesen Beispielen konfiguriere, geht nichts. Es 
kommt kein PWM Signal am Ausgang an, dieser bleibt low.

1
void GPIOinit(void)
2
{
3
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
4
5
    GPIO_InitTypeDef GPIO_InitDef;
6
7
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM5);
8
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);
9
10
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_8;
11
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
12
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_AF;
13
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
14
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
15
16
    GPIO_Init(GPIOA, &GPIO_InitDef);
17
18
}

1
void Timinit(void){
2
  
3
  TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
4
5
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
6
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);
7
8
  TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
9
  TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
10
  TIM_TimeBase_InitStructure.TIM_Period = 8399;
11
  TIM_TimeBase_InitStructure.TIM_Prescaler = 0;
12
  TIM_TimeBase_InitStructure.TIM_RepetitionCounter = 0;
13
  TIM_TimeBaseInit(TIM5, &TIM_TimeBase_InitStructure);
14
15
  TIM_Cmd(TIM5, ENABLE);
16
17
18
  TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
19
  TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
20
  TIM_TimeBase_InitStructure.TIM_Period = 8399;
21
  TIM_TimeBase_InitStructure.TIM_Prescaler = 0;
22
  TIM_TimeBase_InitStructure.TIM_RepetitionCounter = 0;
23
  TIM_TimeBaseInit(TIM1, &TIM_TimeBase_InitStructure);
24
25
  TIM_Cmd(TIM1, ENABLE);
26
27
}

1
void setPWM(void){
2
3
  TIM_OCInitTypeDef TIM_OC_InitStructure;
4
5
6
  TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM2;
7
  TIM_OC_InitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
8
  TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
9
  TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable;
10
  TIM_OC_InitStructure.TIM_Pulse = 2000;
11
12
13
  TIM_OC2Init(TIM5, &TIM_OC_InitStructure);
14
  TIM_OC2PreloadConfig(TIM5, TIM_OCPreload_Enable);
15
16
}


Ich hoffe ihr könnt mir helfen.
Mit freundlichen Grüßen

von aSma>> (Gast)


Lesenswert?

Servus,

-hier fehlt dein Pin PA1
>GPIO_InitDef.GPIO_Pin =  GPIO_Pin_8;

-bei
>TIM_Cmd(TIM1, ENABLE);
fehlt eigentlich: TIM_CtrlPWMOutputs(...) und

-void setPWM(void) ist der Name unglücklich gewählt!

nenne es doch:
void setPWM_Tim5(void) oder so, wobei die Reihenfolge der 
Initialisierung interessant wäre.

Wenn nichts klappt, dann poste die ganze .c Datei.

mfg

von Marcel D. (rubmack)


Lesenswert?

Hi, wow das ging ja echt fix.

Ok ich habe versucht die Teile zu vereinfachen und nur den Code für 
Timer 5 einzufügen.

>-hier fehlt dein Pin PA1
Ist vorhanden, habs jedoch hier im Forumspost raus genommen.

>fehlt eigentlich: TIM_CtrlPWMOutputs(...) und
Hier das gleiche

>-void setPWM(void) ist der Name unglücklich gewählt!
Eigentlich ist es bei mir die Funktion setPWM(int pulse, int chanel), 
damit ich mit einer Funktion beide PWM Kanäle setzen kann.

Ich hatte gedacht eine gekürzte Version macht es einfachen, dem scheint 
nicht so zu sein.
1
int main(void)
2
{
3
  SystemInit();
4
  GPIOinit();
5
  Timinit();
6
  Analoginit();
7
  // CANinit();
8
  int counter;
9
10
  int test;
11
12
  test = SysTick_Config(SystemCoreClock/1000);
13
14
  GPIO_SetBits(GPIOC, GPIO_Pin_9);
15
  GPIO_SetBits(GPIOA, GPIO_Pin_2);
16
  GPIO_SetBits(GPIOB, GPIO_Pin_12);
17
18
  setPWM(2099,1);
19
  setPWM(2099,2);
20
21
/*  ErrorStatus check;
22
  int32_t ee_wert;
23
24
  check=UB_EE_FLASH_Init();
25
*/
26
27
28
    while(1)
29
    {
30
      counter = TIM_GetCounter(TIM5);
31
    }
32
}

Hier sind noch einige relikte aus Test, mit
1
counter = TIM_GetCounter(TIM5)
habe ich getestet ob der Timer überhaupt zählt. Das Tut er.

1
void GPIOinit(void)
2
{
3
   /*Initialisiert alle GPIO
4
    *
5
    */
6
    GPIO_InitTypeDef GPIO_InitDef;
7
8
    // PWM
9
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
10
11
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM5);
12
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);
13
14
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_8| GPIO_Pin_1;
15
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
16
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_AF;
17
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
18
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
19
20
    GPIO_Init(GPIOA, &GPIO_InitDef);
21
22
    // PWM Ende
23
24
25
    // SH_Ctrl
26
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_2;
27
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
28
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
29
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
30
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
31
32
    GPIO_Init(GPIOA, &GPIO_InitDef);
33
    // SH_Ctrl Ende
34
35
    // Clutch_Ctrl
36
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
37
38
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_9;
39
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
40
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
41
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
42
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
43
44
    GPIO_Init(GPIOC, &GPIO_InitDef);
45
    // Clutch_Ctrl Ende
46
47
    // Digital_Out
48
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
49
50
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
51
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
52
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
53
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
54
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
55
56
    GPIO_Init(GPIOB, &GPIO_InitDef);
57
    // Digital_Out Ende
58
59
60
  // Analog_In
61
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6| GPIO_Pin_7;
62
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
63
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_AN;
64
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
65
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
66
67
    GPIO_Init(GPIOA, &GPIO_InitDef);
68
    // Analog_In Ende
69
70
    // Digital_In 3&4
71
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_14 | GPIO_Pin_15;
72
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
73
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_IN;
74
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_DOWN;
75
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
76
77
    GPIO_Init(GPIOB, &GPIO_InitDef);
78
    // Digital_In 3&4 Ende
79
80
    // Digital_In 1&2
81
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
82
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
83
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_IN;
84
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_DOWN;
85
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
86
87
    GPIO_Init(GPIOC, &GPIO_InitDef);
88
    // Digital_In 1&2 Ende
89
90
    // Can
91
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);
92
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);
93
94
    GPIO_InitDef.GPIO_Pin =  GPIO_Pin_11 | GPIO_Pin_12;
95
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
96
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_AF;
97
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_DOWN;
98
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
99
100
    GPIO_Init(GPIOA, &GPIO_InitDef);
101
    // Can Ende
102
103
}

1
void Timinit(void){
2
  /* Initialisiert Timer 1 und 2
3
   * werden für die PWM Signale gebraucht
4
  */
5
6
  TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
7
8
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
9
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);
10
11
  TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
12
  TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
13
  TIM_TimeBase_InitStructure.TIM_Period = 8399;
14
  TIM_TimeBase_InitStructure.TIM_Prescaler = 0;
15
  TIM_TimeBase_InitStructure.TIM_RepetitionCounter = 0;
16
  TIM_TimeBaseInit(TIM5, &TIM_TimeBase_InitStructure);
17
18
  TIM_Cmd(TIM5, ENABLE);
19
20
21
22
  TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
23
  TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
24
  TIM_TimeBase_InitStructure.TIM_Period = 8399;
25
  TIM_TimeBase_InitStructure.TIM_Prescaler = 0;
26
  TIM_TimeBase_InitStructure.TIM_RepetitionCounter = 0;
27
  TIM_TimeBaseInit(TIM1, &TIM_TimeBase_InitStructure);
28
29
  TIM_Cmd(TIM1, ENABLE);
30
31
}

1
void setPWM(int duty, int channel){
2
  /*Channel 1 = Clutch
3
   *Channel 2 = Shifting
4
   *duty ist das Tastverhältnis
5
  */
6
  TIM_OCInitTypeDef TIM_OC_InitStructure;
7
8
  int pulse;
9
10
  pulse = duty;  //hier Pulse berechnen
11
12
  TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM2;
13
  TIM_OC_InitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
14
  TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
15
  TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable;
16
  TIM_OC_InitStructure.TIM_Pulse = pulse;
17
18
19
  if(channel = 1){
20
    TIM_OC1Init(TIM1, &TIM_OC_InitStructure);
21
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
22
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
23
  }
24
  if(channel = 2){
25
    TIM_OC2Init(TIM5, &TIM_OC_InitStructure);
26
    TIM_OC2PreloadConfig(TIM5, TIM_OCPreload_Enable);
27
28
29
30
  }
31
32
}

Ich hoffe ich habe keien Verwirrung gestiftet.
Wird der Rest, sprich die ganzen CAN initialisierungsfunktionen und die 
ADC/DMA Init funktionen auch zur Fehlersuche gebraucht? Ansonsten ist 
das der Code der kompilierbar ist und auf dem STM32F4Discovery Board am 
Pin PA8 ein PWM Signal ausgibt.

Mit freundlichen Grüßen

von Dominik B. (odysseus1710)


Lesenswert?

Marcel D. schrieb:
> if(channel = 1){
>     TIM_OC1Init(TIM1, &TIM_OC_InitStructure);
>     TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
>     TIM_CtrlPWMOutputs(TIM1, ENABLE);
>   }
>   if(channel = 2){
>     TIM_OC2Init(TIM5, &TIM_OC_InitStructure);
>     TIM_OC2PreloadConfig(TIM5, TIM_OCPreload_Enable);

Fehlt hier immernoch in dem hochgeladenen Teil das
1
 TIM_CtrlPWMOutputs(TIM5, ENABLE);
?

Ansonsten mal nachprüfen, ob Timer 5 überhaupt läuft, wenn du dein 
Programm startest und ob du für PA1 auch noch AF2 eingestellt ist und du 
nicht an anderer Stelle den Pin wieder umkonfigurierst (z.B. für UART)

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


Lesenswert?

Marcel D. schrieb:
> if(channel = 1){

Sowas sollte dir ein 'possibly unwanted assignment' oder sowas ähnliches 
geben - sinnvoll ist eher
1
if (channel == 1) {
2
// etc. pp.

In meinem PWM Init mit TIM4 habe ich noch die folgende spassige Zeile:
1
  TIM_ARRPreloadConfig(TIM4, ENABLE);
Wofür das war, blättere ich jetzt nicht nach, hat aber anscheinend einen 
Sinn :-P

Dominik B. schrieb:
> Fehlt hier immernoch in dem hochgeladenen Teil das
> TIM_CtrlPWMOutputs(TIM5, ENABLE);?

Nee, bei den einfachen Timern gibts das nicht.

von Marcel D. (rubmack)


Angehängte Dateien:

Lesenswert?

Danke für die Hilfe.

>if (channel == 1) {
erledigt

>TIM_ARRPreloadConfig(TIM4, ENABLE);
ausprobiert, ändert jedoch nichts

Angehängt sind Oszilloskop sreenchots der Kanäle PA1 und PA8. PA8 ist in 
blau und PA1 ist in rot.

Und ich habe den timer Wert in der while Schleife ausgelesen, siehe 
drittes Bild im Anhang. Heisst das der Timer läuft?


Gruß Marcel

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


Lesenswert?

Den Abschnitt hier hast du gelesen?:
>As the preload registers are transferred to the shadow registers
> only when an update event
>occurs, before starting the counter, you have to initialize all the
>registers by setting the UG bit in the TIMx_EGR register.

Also solltest du ein Update Event erzwingen, wenn ales soweit geladen 
ist. Im einfachsten Fall geht das mit:
1
TIM5->EGR |= (1 << TIM_EGR_UG);

Probier das mal nach einen Setzen des OC Registers.

von Marcel D. (rubmack)


Lesenswert?

Hi Matthias,

>TIM5->EGR |= (1 << TIM_EGR_UG);
hab ich genauso eingefügt. Es tut sich leider gar nichts.


Mich macht stutzig, dass an dem Pin ja etwas ankommt (siehe Osci Bilder 
meines letzten Posts). Es sieht aus als würde ein Kondensator geladen 
werden, oder ähnliches. Ich schaue mal ob der Pin des Discovery Boards 
noch anderweitig verwendet wird.

Gruß Marcel

von Dominik B. (odysseus1710)


Lesenswert?

Marcel D. schrieb:
> Heisst das der Timer läuft?

Jap, sieht ganz so aus, wenn der Wert nicht immer gleich ist zu 
verschiedenen Zeiten.

Marcel D. schrieb:
>>if (channel == 1) {
> erledigt

Hast du das für beide Abfragen korrigiert?
1
if(channel = 2)
Ist nämlich nie erfüllt, bei Kanal 1 war das zufälligerweise noch eine 
erfüllte Bedinung.
Hätte alles darauf gesetzt, dass das der Fehler gewesen ist.

von Eiermann (Gast)


Lesenswert?

Marcel D. schrieb:
> GPIO_InitDef.GPIO_Pin =  GPIO_Pin_8| GPIO_Pin_1;
>     GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
>     GPIO_InitDef.GPIO_Mode = GPIO_Mode_AF;
>     GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
>     GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;

zu
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;

Die Reihenfolge der Initialisierung ist etwas zweifelhaft.

Mach die
TIM_ARRPreloadConfig(TIM5, ENABLE);
Register an und ändere die Periode mit
TIM5->CCR2 = x;
TIM1->CCR1 = y;

>void setPWM(int duty, int channel)

Dafür braucht man keine Funktion! Du könntest auch mit defines arbeiten
1
#define maxPeriode               8399
2
#define setPWM(TIMx,CCRx,wert)   TIMx->CCRx = (wert < maxPMW) ? wert : maxPMW;
3
z.B
4
setPWM(TIM5,CCR2, 555);


Also guck dir nochmals die Standart Beispiele an. Oftmals ist die 
Reihenfolge der Initialisierung ausschlagebend!

mfg

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


Lesenswert?

Marcel D. schrieb:
> Ich schaue mal ob der Pin des Discovery Boards
> noch anderweitig verwendet wird.

Wenn das das Discovery F4 mit dem STM32F407 ist, sollten beide Pins frei 
sein, dank Uwe B.s unermüdlicher Forschung:
http://mikrocontroller.bplaced.net/wordpress/wp-content/uploads/2013/03/Pinbelegung_v101.html

Die Tabelle solltest du dir, falls noch nicht geschehen, runterladen und 
abbunkern.

von Marcel D. (rubmack)


Lesenswert?

Hallo zusammen und vielen Dank für eure Hilfe.
Ich habe den Fehler gefunden. Es lag nicht am Code, sondern an einem 
externen Schaltungsrelikt. Ich habe vor einiger Zeit etwas an den Pin 
PA1 gelötet und durch diese externe Beschaltung kam kein sauberes PWM 
Signal heraus.

Tut mir leid das ich eure Zeit damit verschwendet habe.

>Mach die
>TIM_ARRPreloadConfig(TIM5, ENABLE);
>Register an und ändere die Periode mit
>TIM5->CCR2 = x;
>TIM1->CCR1 = y;
Das ist ein super Hinweis! Danke Eiermann.



Falls jemand diesen Post ausgraben sollte, weil er gerade auf 
Fehlersuche ist. Der Code aus dem 3.Post hat bei meinem STM32F4Discovery 
Board funktioniert.

Mit freundlichen Grüßen
Marcel

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.