Forum: Mikrocontroller und Digitale Elektronik STM32 F0 Einfaches PWM Signal


von Keru B. (keru)


Lesenswert?

Hallo,
ich arbeite mich derzeit in die Timer des STM32F0 Discovery Boards ein 
und habe dabei ein paar Schwierigkeiten, da ich auch zum ersten mal mit 
einem Mikrokontroller Board arbeite.

Ich benötige für ein Projekt 3 individuell einstellbare PWM Signale, 
diese möchte ich an jeweils einem Pin des Boards abgreifen können.
1
#include "stm32f0xx.h"
2
#include "core_cm0.h"
3
#include <stdio.h>
4
5
int main(void)
6
{
7
  RCC ->AHBENR |= (1<<19);      //Enable clock for port c
8
  GPIOC->MODER |= (1<<14);      //Enable Port c Pin 7 as a digital output
9
10
  RCC->APB2ENR |=(1<<16);        //Enable Timer 15
11
  TIM15->CR1 |= (1<<0);        //Enable Counter for Timer 15
12
  TIM15->CR1  &= ~((1<<8)|(1<<9));  //Bit 9:8 are for clock division 00 = tDTS = tCK_INT
13
  TIM15->CR1 |= (1<<7);        //Enable Auto Reload Register
14
15
16
  TIM15->PSC = 40000;          //Set Prescaler to 40.000
17
  TIM15->RCR = 0;            //Set Repetition Counter to 0
18
19
  TIM15->BDTR |= (1<<11);        //Off-state selection for Run mode
20
  TIM15->BDTR |= (1<<15);        //Main Output enable for CCxE
21
22
  TIM15->CCMR1 &=  ~((1<<0) | (1<<1));  //Bit 1:0 = 00 CC1 channel is configured as output
23
  TIM15->CCMR1 |= (1<<3);        //Preload of Register CCR1 is enabled
24
  TIM15->CCMR1 |= ((1<<5) | (1<<6));  //Bits 6:4 for PWM Mode: 110 = PWM Mode 1 active as long as CNT < CCR1
25
26
  TIM15->CCER |= (1<<0);        //CC1 output enable (BDTR important?)
27
  TIM15->CCER &= ~(1<<1);        //Bit 1 Output Polarity 0:OC1 active high
28
29
  TIM15->ARR = 1000;          //Set Period Time to 500
30
  TIM15->CCR1 = 500;          //CNT Value to activate PWM Output1
31
32
    while(1)
33
    {
34
      if(TIM15->SR & (1<<1))      //(Bit1 of SR) Check if CNT register is equal to CCR1 register
35
      {
36
        GPIOC->ODR |= (1<<7);        //Turn GPIOC Pin 7 ON or assert high
37
      }else{
38
        GPIOC->ODR &= ~(1<<7);
39
      }
40
    }
41
}
Dies ist mein derzeitiges Test Programm. Ich habe nun folgendes Problem:
Der Timer läuft, bis zu dem Autoreloadwert und fängt dann wieder von 
vorne an, so wie gewollt. Der Wert im CCR1 löst mir auch mein 
Interruptflag im Statusregister aus. Allerdings wird dies nicht mit dem 
Autoreload wieder zurück gesetzt.
Ich denke ich bin mit dem Interruptflag auf dem falschen Weg.
Wie kann ich hier ein einfaches PWM Signal erzeugen?

Im Manual wird ein OCxREF beschrieben, dies kann ich allerdings 
nirgendwo finden.

Ich würde mich sehr über eine kurze Erklärung oder ein Beispiel für das 
STM32F0 freuen, danke!

Gruss
Keru

: Bearbeitet durch User
von Little B. (lil-b)


Lesenswert?

Ich sehe hier verschiedene konzeptionelle Fehler.

Zu aller vorderst: Es gibt zwei grundlegende Möglichkeiten, ein PWM 
signal zu erzeugen. In Hardware, für das das CCR-Register benutzt wird, 
oder in Software, indem man den aktuellen Zählerwert des Timers in 
Software vergleicht. Du hast eine Mischung implementiert, und verwendest 
daher die Hardware nicht wie vorgesehen.

Desweiteren:
Ein Interrupt flag setzt sich nur in einigen wenigen Fällen selbst 
zurück, der Timer gehört definitiv nicht dazu. Um das Flag zurück zu 
setzen, musst du das entsprechende bit in software zurücksetzen.
Und ja, du bist mit Interrupt Flags auf dem Holzweg, das ist nicht 
hilfreich bei der grundlegenden Implementierung eines PWM.

Es ist ungewöhnlich, dass du den Timer erst einschaltest (TIM15->CR1 |= 
(1<<0);) und danach erst initialisierst. Das mag vieleicht 
funktionieren, kann aber zu allen möglichen Fehlverhalten führen. 
Initialisiere erst, und aktiviere erst ganz zum schluss den counter!

Willst du einen PWM in Software realisieren, so könnte das in etwa so 
aussehen:
1
    while(1)
2
    {
3
      if(TIM15->CNT < 500)      // Check current count value
4
      {
5
        GPIOC->ODR |= (1<<7);        //Turn GPIOC Pin 7 ON or assert high
6
      }else{
7
        GPIOC->ODR &= ~(1<<7);
8
      }
9
    }

Das ist aber nicht die elegante methode. Verwende besser die gegebene 
Timer Hardware. Diese wird im Unterkapitel "PWM mode" des Timers deiner 
Wahl im Reference Manual beschrieben. Zusätzlich musst du dann noch die 
entsprechenden Pins deines Controllers auf "Alternate Function" 
konfigurieren. Wie das funktioniert, erfährst du im Kapitel 
"General-purpose I/Os" des Reference Manuals. Welche Pins du für den 
Timer verwenden kannst, kannst du dem "Device Summary" entnehmen.

Ich hoffe, das war so weit hilfreich.
Stelle gerne weitere Fragen, wenn irgendwas nicht klar ist!

~Lil-B

von Keru B. (keru)


Angehängte Dateien:

Lesenswert?

Vielen Dank für deine Hilfe!
Ich hab tatsächlich noch fragen, da ich aus dem Reference Manual noch 
nicht schlau geworden bin.
Ich nutze das RM0091 für STM32F0x1/STM32F0x2/STM32F0x8 advanced 
ARM®-based 32-bit MCUs.

Dort findet man unter PWM edge-aligned mode eine Beschreibung für diesen 
Modus. Ich habe einen kleinen Auschnitt des Beispiels im Anhang 
angeheftet.
Dort ist ein OCxREF angegeben. Dies konnte ich allerdings nirgendwo 
wieder finden. Das OCxREF verhält sich laut dem Beispiel genau wie ich 
es für mein PWM Signal benötige, oder bin ich damit schon wieder auf dem 
Holzweg?

Desweiteren habe ich mir die Alternate Function Register (GPIOC->AFR) 
angeschaut und konnte dabei in der Beschreibung nichts finden, wie ich 
diese einzustellen habe.

Nochmal, vielen Dank für die Hilfe.

Gruss
Keru

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.