Forum: Mikrocontroller und Digitale Elektronik PWM Signalerzeugung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi

Ich benötige ein Signal, welches ich über PWM generieren kann.
Ich habe folgenden Code geschrieben, bekomme aber kein Signal heraus.
Sieht jemand gerade meinen Fehler im Code? Ich bin mal gespannt, was das 
ist.

Habe das Nucleo STM32L476
1
void User_Init_Timer2(uint8_t Presc, uint8_t period, uint8_t duty_Cycle_perCent)
2
{
3
   uint8_t duty_Cycle = period*duty_Cycle_perCent/100;
4
   
5
   
6
        /* Configure register bits for Channel 1*/
7
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_OC1M;                /* Ensure bits of OC1M are cleared*/
8
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC1S;                /* Set CC1 as output */
9
   TIM2->CCMR1 |= TIM_OCMODE_PWM2;                          /* OC1 is low until CCR1, with PWM mode 2 the polarity is set*/  
10
   TIM2->CCER &= (uint16_t)~TIM_CCER_CC1P;                  /* Reset CC1P register for OC1 active high */
11
   TIM2->CCR1 = duty_Cycle;                                 /* Set the compare value channel 1*/
12
   
13
        /* General configuration for all Timer 1 Channels 1-4*/  
14
   RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;                    /* Peripheral clock enable */  
15
   TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);               /* Reset bits of CMS (Edge-aligned mode) and DIR generally */
16
   TIM2->CR1 |= TIM_COUNTERMODE_CENTERALIGNED3;             /* Select the up counter mode */
17
   TIM2->CR1 &= ~TIM_CR1_CKD;                               /* Erase bits of CKD */
18
   TIM2->CR1 |= TIM_CLOCKDIVISION_DIV1;                     /* Set the clock division to 1*/
19
   TIM2->PSC = Presc;                                       /* Set the Prescaler value */
20
   TIM2->ARR = period - 1;                                  /* Set the Auto-reload value*/
21
   TIM2->CR1 |= TIM_CR1_OPM;                                /* Activate the one pulse mode*/
22
   TIM2->EGR |= TIM_EGR_UG;                                 /* Generate an update event to reload Prescaler and Repetition counter value immediately*/
23
   TIM2->CCER |= TIM_OCPOLARITY_HIGH;                       /* Set the Output Compare Polarity to High */
24
   TIM2->SMCR = RESET;                                      /* Configure the Internal Clock Source*/
25
   TIM2->BDTR |= TIM_BDTR_MOE;                              /* Enable the TIM main Output */  
26
}
27
28
void Enable_Timer2_Counter()
29
{
30
  TIM2->CR1 |= TIM_CR1_CEN; 
31
}
32
33
void Enable_Flash_LED_1()
34
{
35
  TIM2->CCER |= TIM_CCER_CC1E;                             /* Enable the Compare output channel 1 */
36
}
37
38
int main(void)
39
{
40
41
  /* USER CODE BEGIN 1 */
42
43
  /* USER CODE END 1 */
44
45
  /* MCU Configuration----------------------------------------------------------*/
46
47
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
48
  HAL_Init();
49
50
  /* Configure the system clock */
51
  SystemClock_Config();
52
53
  /* Initialize all configured peripherals */
54
  MX_GPIO_Init();
55
  MX_TIM2_Init();
56
57
58
  User_Init_Timer2(0, 20, 50);
59
  Enable_Timer2_Counter();   
60
  Enable_Flash_LED_1();
61
 
62
63
}

von DraconiX (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mach dir mal eine while(1) in deine Main. Ein µC springt dann immer 
wieder an den Anfang und deine Init beginnt von neuen.

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
DraconiX schrieb:
> Mach dir mal eine while(1) in deine Main. Ein µC springt dann
> immer
> wieder an den Anfang und deine Init beginnt von neuen.

Hab ich drin, nur nicht hier angegeben.
Die While(1) ist leer.
Ich glaube aber nicht, dass die While(1) hier das Problem wäre, falls 
sie bei mir im Code fehlen würde.

Stimmt denn der Code so?

von Boris O. (bohnsorg) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Manchmal muss man den PINs noch mitteilen, was ihre Funktion ist, d.h. 
ob sie Ein- oder Ausgänge sind. PWM wird vielleicht erzeugt, geht aber 
nicht auf den PIN.

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Pins sollten nicht das Problem sein.
Es macht das Tool CubeMX automatisch.

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D.I schrieb:
> TIM2->CR1 |= TIM_CR1_OPM;     /* Activate the one pulse mode*/

Bist du sicher, dass du das willst?

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wolfgang schrieb:
> D.I schrieb:
> TIM2->CR1 |= TIM_CR1_OPM;     /* Activate the one pulse mode*/
>
> Bist du sicher, dass du das willst?

Hab ich bereits heraus genommen.
Das tut immer noch nicht.
Mir gehen langsam die Ideen aus..

von Christopher J. (christopher_j23)


Bewertung
1 lesenswert
nicht lesenswert
Du schreibst in deiner User_Init_Timer2 irgendwelche HAL-Definitionen 
direkt in die Register und wunderst dich, dass es nicht klappt?

z.B.
> TIM2->CCER |= TIM_OCPOLARITY_HIGH;



Abgesehen davon:

D.I schrieb:
> TIM2->BDTR |= TIM_BDTR_MOE;

BDTR gibts nur für "advanced timer".


D.I schrieb:
> TIM2->CR1 |= TIM_COUNTERMODE_CENTERALIGNED3;             /* Select the
> up counter mode */

Centeraligned 3 ist für Up-Down-Counter (daher center-aligned), nicht 
für Upcounter.


D.I schrieb:
> MX_TIM2_Init();
>
> User_Init_Timer2(0, 20, 50);

Warum zur Hölle konfigurierst du den Timer nicht komplett selber und 
lässt den CubeMX-Kram weg oder machst es konsequent komplett mit CubeMX? 
So ein zusammenkopierter Mischmasch kann doch nie und nimmer vernünftig 
funktionieren.

Für eine funktionierende PWM brauchst du
1. eine GPIO Konfiguration
2. eine Timer Konfiguration

zu 1.
1.1 GPIO Takt anschalten (z.B. im RCC_AHB2ENR)
1.2 GPIO Mode auf "alternate function mode" konfigurieren (z.B. im 
GPIOx_MODER)
1.3.1 GPIO "alternate function" auswählen (aus Datenblatt, für 
entsprechenden Pin, je nach gewünschter Funktion)
1.3.2 "alternate function" in entsprechendes Register schreiben (z.B. im 
GPIOx_AFRL oder GPIOx_AFRH);

zu 2.
2.1 Timer Takt anschalten (z.B. im RCC_APB1ENR1)
2.2 "Time Base" konfigurieren, d.h. Timer Takt und Periode
2.2.1 TIMx_PSC entsprechend wählen (für Timer Takt)
2.2.2 TIMx_ARR entsprechend wählen (für Periodendauer)
2.3 Output Compare konfigurieren
2.3.1 PWM Modus wählen (z.B. OC1M Bits in TIMx_CCMR1 auf PWM mode 1 
konfigurieren)
2.3.2 OC Output aktivieren (z.B. CC1E Bit in TIMx_CCER setzen)
2.4 Pulsbreite Wählen (z.B. in TIMx_CCR1)
2.5 Timer starten (z.B. CEN Bit in TIMx_CR1 setzen)

und nur für "advanced timer":
2.6 Hauptschalter umlegen ("Main Output Enable" bzw. MOE Bit in 
TIMx_BDTR setzen)

von D.I (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Christopher J. schrieb:


>> TIM2->CCER |= TIM_OCPOLARITY_HIGH;

> D.I schrieb:
>> TIM2->CR1 |= TIM_COUNTERMODE_CENTERALIGNED3;             /* Select the
>> up counter mode */
>
> Centeraligned 3 ist für Up-Down-Counter (daher center-aligned), nicht
> für Upcounter.
>

Hallo Christopher

Vielen Dank für deine präzise Beschreibung. Ich werde mir das morgen bei 
Gelegenheit mal ansehen und mich daran versuchen.
Kurz zuvor noch 2 Verständnisfragen.

1. Warum darf ich da mittels TIM->CCER die Polarität nicht wählen? Muss 
man das bei der PWM nicht?

2. Ich weiss was PWM ist, aber was ist jetzt eigentlich der Vorteil, 
wenn ich den Puls, den ich generieren möchte, über PWM mache?
Ich habe nämlich zuvor mehrere Pulse über den Wiederholzähler 
(repetition) generiert und dabei auch einen CCRx gesetzt. Die 
Vorgehensweise ist ja bei PWM ähnlich und die Pulsbreite stelle ich ja 
auch über CCRx ein. Die Periode per ARR. Hmm, was ist jetzt genau der 
Unterschied hier im Gegensatz zur N-Pulse Generation??

Nebenbei: Ich habe die Zeilen von der Programmierung, die ich vorher 
gemacht habe kopiert und TIM1 auf TIM2 geändert. Dass es kein BDTR 
Register gibt, ist mir jetzt auch klar, aber warum finde ich dann, wenn 
ich TIM2->(hier STRT+Leertaste gedrückt) das BDTR Register??
Mein Ziel ist es einen einzigen Puls über PWM zu generieren und zwar so, 
dass der Counter Center-aligned ist und somit alle Pulse in den 
jeweilgen Kanälen immer zentriert sind. Siehe Bild

von Christopher J. (christopher_j23)


Bewertung
0 lesenswert
nicht lesenswert
D.I schrieb:
> 1. Warum darf ich da mittels TIM->CCER die Polarität nicht wählen? Muss
> man das bei der PWM nicht?

Muss man nicht aber darfst du natürlich nur solltest du es richtig 
machen, wenn du es denn machen willst. Schau mal nach, was genau 
"TIM_OCPOLARITY_HIGH" als Wert hat. Sehr gut möglich, dass es einfach 
nur 0x1 ist. Dann setzt du halt das letzte Bit im CCER aber nicht das OC 
Polarity Bit (von welchem Kanal überhaupt?) . Das muss irgendein Kram 
aus der HAL sein. Nimm doch einfach die Bitmasken aus dem Header, da 
steht doch wirklich alles drin was du brauchst und die Bezeichnungen 
decken sich mit denen im Handbuch.

D.I schrieb:
> Dass es kein BDTR Register gibt, ist mir jetzt auch klar, aber warum
> finde ich dann, wenn ich TIM2->(hier STRT+Leertaste gedrückt) das BDTR
> Register??

Vielleicht weil es für die unterschiedlichen Timer nur eine gemeinsame 
Struct-Definition gibt und die eben alle Register beinhaltet.

D.I schrieb:
> was ist jetzt genau der Unterschied hier im Gegensatz zur N-Pulse
> Generation??

Es gibt keinen. Ich wollte dir mit der Checkliste von oben auch nur 
einen Hinweis geben wie du überhaupt zu irgendeiner funktionierenden 
PWM-Konfiguration gelangen kannst (ohne CubeMX). Natürlich kannst du das 
Ding als Up-Down-Counter konfigurieren, mit allen möglichen extras hier 
und da aber wenn noch nicht mal die absolute Basiskonfiguration läuft 
würde ich mir da eher weniger sorgen drum machen.

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Kann ja sein das ich das alles zu einfach sehe, aber wieso bewegen die 
meisten Leute immer einen Haufen Bits in irgendwelche Register wenn sie 
schon HAL benutzen?

Bei mir läuft das nach der CubeMX Codeerstellung so ab:

ich nehme das 'TIM_OC_InitTypeDef sConfigOC;' aus der MX_TIM1_Init,
mache es in der tim.h global zugänglich.
Damit habe ich Zugriff auf alles was das PWM betrifft.

in der main.c bleibt dann nur noch z.B.: 
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);

wenn ich etwas am PWM ändern möchte:
sConfigOC.Pulse=100;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);

optional vorher noch ein HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);
geht aber auch ohne.

von pegel (Gast)


Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
D.I schrieb:
> dass der Counter Center-aligned ist und somit alle Pulse in den
> jeweilgen Kanälen immer zentriert sind.

Auf einem F103 Mini Board mit 72MHz, 1kHz PWM probiert:

in der main.c bleibt nur der Start vom PWM.

  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);

Sonstiges siehe Bilder.

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ok. Etwas geschummelt.
Durch den Center Mode halbiert sich die PWM Frequenz da sich alle Werte 
gegenüber Up oder Down Mode verdoppeln. Muss natürlich beim Berechnen 
beachtet werden.

von Christopher J. (christopher_j23)


Bewertung
1 lesenswert
nicht lesenswert
pegel schrieb:
> Kann ja sein das ich das alles zu einfach sehe, aber wieso bewegen die
> meisten Leute immer einen Haufen Bits in irgendwelche Register wenn sie
> schon HAL benutzen?

Diese Kombination sehe ich zum ersten mal.

Wem der HAL von ST taugt und damit glücklich wird soll es auch 
meinetwegen benutzen. Ich frage mich nur was diese Leute dann machen, 
wenn ein bestimmtes Hardware-Feature nicht in CubeMX per Eingabemaske 
konfigurierbar ist. Die vorgehensweise des TO (CubeMX irgendetwas 
generieren lassen, irgendetwas in die Register schreiben, Trial and 
Error) sehe ich jedenfalls als ultimatives Rezept wie man kurz- und/oder 
langfristig - aber in jedem Fall hart - auf die Nase fällt.

von D.I (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Christopher J. schrieb:
> D.I schrieb:
>> 1. Warum darf ich da mittels TIM->CCER die Polarität nicht wählen? Muss
>> man das bei der PWM nicht?
>
> Muss man nicht aber darfst du natürlich nur solltest du es richtig
> machen, wenn du es denn machen willst. Schau mal nach, was genau
> "TIM_OCPOLARITY_HIGH" als Wert hat. Sehr gut möglich, dass es einfach
> nur 0x1 ist. Dann setzt du halt das letzte Bit im CCER aber nicht das OC
> Polarity Bit (von welchem Kanal überhaupt?) . Das muss irgendein Kram
> aus der HAL sein. Nimm doch einfach die Bitmasken aus dem Header, da
> steht doch wirklich alles drin was du brauchst und die Bezeichnungen
> decken sich mit denen im Handbuch.
>

Christopher, das ist mitunter das, was ich schon länger mal ansprechen 
wollte.
Nämlich, ich nehme an, dass die Definitionen in den Header-files dafür 
da sind, dass man die Bitstruktur kennen muss, deshalb gibt man ja auch 
sinnvolle Namen wie TIM_OCPOLARITY_HiGH etc. Wenn ich die jetzt setzen 
möchte, heisst das, dass ich immer schauen muss, was für ein Wert 
dahinter steckt. Denn wenn ich jetzt weiss, dass eine 0 dahinter steckt 
müsste es eigentlich folgend heissen:
TIM1->CCER &= TIM_OCPOLARITY_HIGH;, weil TIM_OCPOLARITY_HIGH = 0x0000 
ist.
Es löscht mir aber das gesamte Register so. Das ist ja so voll 
bescheuert, wenn ich zuvor zB CC2E eingeschaltet habe und das bleiben 
soll, dann aber CC1E enablen möchte, dann löscht es mir CC2E mit dieser 
Definition Polarity_high auch. So kann ich gleich ins Register schauen 
und die Bits schieben.

Sieh bitte mal diesbezüglich in die Application Note im Anhang S43 im 
Code 3. unterste Zeile... Die haben das dort auch so drin.

Dazu habe ich noch weitere Fragen:
Welche header-Datei meinst du, wenn du davon sprichst?
Also in anderen Worten ich soll stm32l476xx.h verwenden anstatt 
stm32l4xx_hal_tim.h?? Denn da steht auch das mit der OCPOLARITY_HIGH

>
> Es gibt keinen. Ich wollte dir mit der Checkliste von oben auch nur
> einen Hinweis geben wie du überhaupt zu irgendeiner funktionierenden
> PWM-Konfiguration gelangen kannst (ohne CubeMX). Natürlich kannst du das
> Ding als Up-Down-Counter konfigurieren, mit allen möglichen extras hier
> und da aber wenn noch nicht mal die absolute Basiskonfiguration läuft
> würde ich mir da eher weniger sorgen drum machen.

Wozu gibt es die PWM Funktion dann? Es sind eigentlich alle Pulse, die 
ich erzeuge eine PWM. Denn ich kann ja CCRx und ARR immer so einstellen 
wie ich will. Ob mit PWM Funktion oder ohne.

> Diese Kombination sehe ich zum ersten mal.
>
> Wem der HAL von ST taugt und damit glücklich wird soll es auch
> meinetwegen benutzen. Ich frage mich nur was diese Leute dann machen,
> wenn ein bestimmtes Hardware-Feature nicht in CubeMX per Eingabemaske
> konfigurierbar ist. Die vorgehensweise des TO (CubeMX irgendetwas
> generieren lassen, irgendetwas in die Register schreiben, Trial and
> Error) sehe ich jedenfalls als ultimatives Rezept wie man kurz- und/oder
> langfristig - aber in jedem Fall hart - auf die Nase fällt.

Ja für mich ist das auch schwierig. Es gibt 10000 headerfiles und 
irgendwelche structs, die die Variablen enthalten, aber denen auch 
wieder die hal-Definitionen zugewiesen werden und einer HAL Funktion 
übergeben werden. Hier mal ein Stück vom Timer_Init, was generiert 
wurde:
(So hätte ich es im nächsten Schritt versucht zu programmieren)

static void MX_TIM1_Init(void)
{

  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 8;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 255;
  if (HAL_TIM_OC_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
.
.
.
.
.
HAL_TIM_MspPostInit(&htim1);

Also die Verwendung von TypeDefs, soweit in Ordnung.
TIM1 steht in der stm32l476xx.h, auch ok. Aber TIM_COUNTERMODE_UP steht 
in der stm32l4xx_hal_tim.h, die ich ja nicht verwenden soll.
Das ist doch auch eine Kombination?! In der letzten Zeile erfolgt die 
Überprüfung mittels HAL und dann weiter unten im Code dann die Übergabe 
HAL_TIM_MspPostInit(&htim1);

Ich würde jetzt gerne wissen, was du von vorn herein ignorierst an HAL 
und wie du ohne HAL programmierst. Ich wäre dir sehr dankbar, weil die 
HALs nerven mich auch. Ich blicke da nicht durch.

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Edit: oder S37 4. unterste Zeile in der Appl. Note

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christopher J. schrieb:
> Ich frage mich nur was diese Leute dann machen,
> wenn ein bestimmtes Hardware-Feature nicht in CubeMX per Eingabemaske
> konfigurierbar ist.

Ich denke "diese Leute" können sogar meist Datenblätter lesen und bei 
Bedarf das Fehlende an der richtigen Stelle einfügen, wenn es sein muss.
Wie schon öfter erwähnt muss man nur den HAL Funktionen folgen und kommt 
so bis auf die nackten Register.

D.I schrieb:
> weil die HALs nerven mich auch.

Ok. wenn dir das zu einfach ist, dann leide weiter ;)

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
pegel schrieb:

>
> Ok. wenn dir das zu einfach ist, dann leide weiter ;)

Hey, das ist Provokation!! :P

Nein, der eine sagt kein HAL verwenden, der andere sagt HAL verwenden.
Wie programmiert man dann denn ohne HAL?

Ich werde es sobald ich dazu komme, auch so programmieren wie du es 
beschrieben hast.

Danke übrigens für deine Hilfe auch ;)

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wie gesagt ist HAL nur eine abstrakte Form für das was du per Hand 
machst.
Folge doch zum Spaß den Funktionen im Quelltext oder Debugger.

z.B.

MX_TIM1_Init -> HAL_TIM_Base_Init -> TIM_Base_SetConfig ->

führt zu der Kommentierten Funktion
1
/**
2
  * @brief  Time Base configuration
3
  * @param  TIMx : TIM periheral
4
  * @param  Structure : TIM Base configuration structure
5
  * @retval None
6
  */
7
void TIM_Base_SetConfig(TIM_TypeDef *TIMx, TIM_Base_InitTypeDef *Structure)
8
{
9
  uint32_t tmpcr1 = 0;
10
  tmpcr1 = TIMx->CR1;
11
12
  /* Set TIM Time Base Unit parameters ---------------------------------------*/
13
  if (IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx))
14
  {
15
    /* Select the Counter Mode */
16
    tmpcr1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
17
    tmpcr1 |= Structure->CounterMode;
18
  }
19
20
  if(IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx))
21
  {
22
    /* Set the clock division */
23
    tmpcr1 &= ~TIM_CR1_CKD;
24
    tmpcr1 |= (uint32_t)Structure->ClockDivision;
25
  }
26
27
  TIMx->CR1 = tmpcr1;
28
29
  /* Set the Autoreload value */
30
  TIMx->ARR = (uint32_t)Structure->Period ;
31
32
  /* Set the Prescaler value */
33
  TIMx->PSC = (uint32_t)Structure->Prescaler;
34
35
  if (IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx))
36
  {
37
    /* Set the Repetition Counter value */
38
    TIMx->RCR = Structure->RepetitionCounter;
39
  }
40
41
  /* Generate an update event to reload the Prescaler 
42
     and the repetition counter(only for TIM1 and TIM8) value immediatly */
43
  TIMx->EGR = TIM_EGR_UG;
44
}

Damit siehst du das die am Ende auch nur die Register setzen und HAL 
kein Feind der "zu Fuß Programmierung" sein muss.

von Christopher J. (christopher_j23)


Bewertung
0 lesenswert
nicht lesenswert
D.I schrieb:
> stm32l476xx.h

Den meine ich. Da sind die Register für die jeweilige Peripherie als 
Struct zusammengefasst (bzw. durch einen Zeiger auf diesen zugänglich). 
Die Syntax dafür ist immer die gleiche:

Peripherie->Register, z.B. TIM1->ARR

Außerdem bekommst du in diesem Header auch noch Bitdefinitionen für 
deine Register mitgeliefert und zwar nach dem Schema

Peripherie_Register_Bit, z.B. TIM_CCER_CC1E für das CC1E Bit im CCER 
eines Timers. Die Nummer des Timers wird weggelassen, da sie für die 
Bitdefinition irrelevant ist.

Willst du also das CC1E Bit für Timer 1 setzen:

TIM1->CCER |= TIM_CCER_CC1E;

Das Schema ist übrigens bei allen Herstellern so, nicht nur bei ST.


Außerdem gibt es immer noch die Position und die Maske des Bits bzw. 
Bitfeldes, indem ein _Pos bzw. _Msk angehängt wird. Für Bitfelder gibt 
es noch durchnummerierte Masken für jedes einzelne Bit. Das ganze sieht 
dann z.B. für OC1M im CCMR1 so aus.
1
#define TIM_CCMR1_OC1M_Pos        (4U)                                         
2
#define TIM_CCMR1_OC1M_Msk        (0x1007U << TIM_CCMR1_OC1M_Pos)              /*!< 0x00010070 */
3
#define TIM_CCMR1_OC1M            TIM_CCMR1_OC1M_Msk                           /*!<OC1M[2:0] bits (Output Compare 1 Mode) */
4
#define TIM_CCMR1_OC1M_0          (0x0001U << TIM_CCMR1_OC1M_Pos)              /*!< 0x00000010 */
5
#define TIM_CCMR1_OC1M_1          (0x0002U << TIM_CCMR1_OC1M_Pos)              /*!< 0x00000020 */
6
#define TIM_CCMR1_OC1M_2          (0x0004U << TIM_CCMR1_OC1M_Pos)              /*!< 0x00000040 */
7
#define TIM_CCMR1_OC1M_3          (0x1000U << TIM_CCMR1_OC1M_Pos)              /*!< 0x00010000 */

Was die Appnote angeht:

TIM1->CCER |= TIM_OCPOLARITY_HIGH;

ist so ein Fall wo eine Definiton aus der HAL scheinbar direkt ins 
Register geschrieben werden kann. Das es nicht immer zutrifft hast du ja 
selber gemerkt.

Schaust du in stm32l476xx.h findest du
1
#define TIM_CCER_CC1P_Pos         (1U)                                         
2
#define TIM_CCER_CC1P_Msk         (0x1U << TIM_CCER_CC1P_Pos)                  /*!< 0x00000002 */
3
#define TIM_CCER_CC1P             TIM_CCER_CC1P_Msk                            /*!<Capture/Compare 1 output Polarity */

Willst du also inverse Polarität, dann setzt du z.B.
TIM1->CCER |= TIM_CCER_CC1P;

Was nun "Polarity High" oder "Polarity Low" bedeutet musst du doch 
sowieso im Handbuch nachschauen.

D.I schrieb:
> Wozu gibt es die PWM Funktion dann? Es sind eigentlich alle Pulse, die
> ich erzeuge eine PWM. Denn ich kann ja CCRx und ARR immer so einstellen
> wie ich will. Ob mit PWM Funktion oder ohne.

Ich hoffe mal wir reden da nicht aneinander vorbei. Ich meinte, dass es 
für die Konfiguration "pwm mode 1" oder "pwm mode 2" keinen Unterschied 
macht ob N-Pulse oder unendlich viele. Man ermöglicht mit der Selektion 
eines Modus lediglich, dass am Ausgang überhaupt etwas ankommt. Timer 
können ja z.B. auch zur ausschließlichen Interrupt-Generierung genutzt 
werden.

Beitrag #4972034 wurde vom Autor gelöscht.
von D. I. (Firma: Fa) (buell)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Christopher

Ich habe das jetzt mal so gemacht wie du gesagt hast direkt.
Aber ich kann so trotzdem noch nichts am Ausgang messen bis auf das 
oberste Signal im Bild, was ja kein PWM ist.
Ich habe alle Definitionen jetzt ins Init_Timer2 genommen mit den GPIO 
Konfigurationen. Ich bin immer noch erfolglos. Siehe Bild
1
/**
2
 
3
  *
4
  ******************************************************************************
5
  */
6
/* Includes ------------------------------------------------------------------*/
7
#include "main.h"
8
#include "stm32l4xx_hal.h"
9
10
/* USER CODE BEGIN Includes */
11
12
#define TIM_OCMODE_PWM2_CH1                     TIM_OCMODE_PWM2
13
#define TIM_OCMODE_PWM2_CH2                     ((uint32_t)TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_0)
14
#define TIM_OCMODE_PWM2_CH3                     ((uint32_t)TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0)
15
#define TIM_OCMODE_PWM2_CH4                     ((uint32_t)TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_0)
16
#define TIM_OCMODE_PWM1_CH5                     ((uint32_t)TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_0)
17
#define CH17_SEL                                23
18
#define ADC_Channel_Pos                         6
19
/* USER CODE END Includes */
20
21
/* Private variables ---------------------------------------------------------*/
22
ADC_HandleTypeDef hadc1;
23
DMA_HandleTypeDef hdma_adc1;
24
25
TIM_HandleTypeDef htim1;
26
TIM_HandleTypeDef htim2;
27
28
/* USER CODE BEGIN PV */
29
/* Private variables ---------------------------------------------------------*/
30
31
/* USER CODE END PV */
32
33
/* Private function prototypes -----------------------------------------------*/
34
void SystemClock_Config(void);
35
void Error_Handler(void);
36
static void MX_GPIO_Init(void);
37
static void MX_DMA_Init(void);
38
static void MX_TIM1_Init(void);
39
static void MX_ADC1_Init(void);
40
static void MX_TIM2_Init(void);
41
                                    
42
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
43
                                
44
                                
45
46
/* USER CODE BEGIN PFP */
47
/* Private function prototypes -----------------------------------------------*/
48
49
void Enable_Timerx_Counter(uint8_t Timer_x);
50
void Init_Timer2(uint8_t Presc, uint8_t period);
51
void Enable_LED_x(uint8_t led_x, uint16_t duty_Cycle_value);
52
53
54
/* USER CODE END PFP */
55
56
/* USER CODE BEGIN 0 */
57
58
59
60
void Enable_Timerx_Counter(uint8_t Timer_x)
61
{
62
    /* Enable_Timerx_Counter(uint8_t Timer_x) where Timer_x is 1, 2, 15, 16  */
63
   
64
  if (Timer_x == 1)
65
  { 
66
   TIM1->CR1 |= TIM_CR1_CEN; 
67
  }
68
  
69
  if (Timer_x == 2)
70
  { 
71
   TIM2->CR1 |= TIM_CR1_CEN;  
72
  }
73
  
74
  if (Timer_x == 15)
75
  { 
76
   TIM15->CR1 |= TIM_CR1_CEN; 
77
  }
78
  
79
  if (Timer_x == 16)
80
  { 
81
   TIM16->CR1 |= TIM_CR1_CEN; 
82
  }
83
  
84
}
85
86
87
88
void Init_Timer2(uint8_t Presc, uint8_t period)
89
{    
90
       /* General configuration for all Timer 1 Channels 1-4*/  
91
   RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;                    /* Peripheral clock enable */  
92
   TIM2->CR1 |= TIM_CR1_CMS_0;                              /* Select the Counter Centeraligned Mode 1 */
93
   TIM2->CR1 &= ~TIM_CR1_CKD;                               /* Erase bits of CKD */
94
   TIM2->PSC = Presc;                                       /* Set the Prescaler value */
95
   TIM2->ARR = period - 1;                                  /* Set the Auto-reload value - top value counter*/
96
 
97
        /* Configure register bits for Channel 1*/
98
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC1M;                  /* OC1 is low until CCR1, with PWM mode 2 the polarity is set */
99
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC1S;                /* Set CC1 as output */
100
   TIM2->CCER &= ~TIM_CCER_CC1P;                            /* CC1P for OC1 active high */
101
   
102
   
103
          /* Configure register bits for Channel 1*/
104
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC1M;                  /* OC1 is low until CCR1, with PWM mode 2 the polarity is set */
105
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC1S;                /* Set CC1 as output */
106
   TIM2->CCER &= ~TIM_CCER_CC1P;                            /* CC1P for OC1 active high */
107
   
108
          /* Configure register bits for Channel 1*/
109
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC3M;                  /* OC1 is low until CCR1, with PWM mode 2 the polarity is set */
110
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC3S;                /* Set CC2 as output */
111
   TIM2->CCER &= ~TIM_CCER_CC2P;                            /* CC2P for OC1 active high */
112
   
113
          /* Configure register bits for Channel 1*/
114
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC4M;                  /* OC1 is low until CCR1, with PWM mode 2 the polarity is set */
115
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC4S;                /* Set CC1 as output */
116
   TIM2->CCER &= ~TIM_CCER_CC4P;                            /* CC1P for OC1 active high */
117
   
118
   
119
   /* General configuration of GPIO for Timer2 PWM Generation*/
120
    GPIO_InitTypeDef gpio;
121
   
122
   /* GPIO Ports Clock Enable */
123
  __HAL_RCC_GPIOA_CLK_ENABLE();
124
  __HAL_RCC_GPIOB_CLK_ENABLE();
125
  
126
     /**TIM2 GPIO Configuration    
127
    PB3     ------> TIM2_CH2
128
    PB10     ------> TIM2_CH3
129
    PB11     ------> TIM2_CH4
130
    PA15     ------> TIM2_CH1 
131
    */
132
    gpio.Pin = GPIO_PIN_15;
133
    gpio.Mode = GPIO_MODE_AF_PP;
134
    gpio.Pull = GPIO_NOPULL;
135
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
136
    gpio.Alternate = GPIO_AF1_TIM2;
137
    HAL_GPIO_Init(GPIOA, &gpio);
138
139
    gpio.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_3;
140
    gpio.Mode = GPIO_MODE_AF_PP;
141
    gpio.Pull = GPIO_NOPULL;
142
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
143
    gpio.Alternate = GPIO_AF1_TIM2;
144
    HAL_GPIO_Init(GPIOB, &gpio);
145
     
146
}
147
148
void Enable_Timer2_Counter()
149
{
150
  TIM2->CR1 |= TIM_CR1_CEN; 
151
}
152
153
void Enable_LED_x(uint8_t led_x, uint16_t duty_Cycle_value)
154
{
155
   
156
  if (led_x == 1)
157
  { 
158
   TIM2->CCR1 = duty_Cycle_value;                            /* Set the compare value channel 1*/
159
   TIM2->CCER |= TIM_CCER_CC1E;                              /* Enable the Compare output channel 1 */
160
  }
161
  
162
  if (led_x == 2)
163
  { 
164
   TIM2->CCR2 = duty_Cycle_value;                            /* Set the compare value channel 2*/
165
   TIM2->CCER |= TIM_CCER_CC2E;                              /* Enable the Compare output channel 2 */
166
  }
167
  
168
  if (led_x == 3)
169
  { 
170
   TIM2->CCR3 = duty_Cycle_value;                            /* Set the compare value channel 3*/
171
   TIM2->CCER |= TIM_CCER_CC3E;                              /* Enable the Compare output channel 3 */
172
  }
173
  
174
  if (led_x == 4)
175
  {
176
   TIM2->CCR4 = duty_Cycle_value;                            /* Set the compare value channel 4*/
177
   TIM2->CCER |= TIM_CCER_CC4E;                              /* Enable the Compare output channel 4 */
178
  }
179
}
180
181
/* USER CODE END 0 */
182
183
int main(void)
184
{
185
186
  /* USER CODE BEGIN 1 */
187
188
  /* USER CODE END 1 */
189
190
  /* MCU Configuration----------------------------------------------------------*/
191
192
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
193
  HAL_Init();
194
195
  /* Configure the system clock */
196
  SystemClock_Config();
197
198
  /* Initialize all configured peripherals */
199
  MX_GPIO_Init();
200
  MX_DMA_Init();
201
  MX_TIM1_Init();
202
  MX_ADC1_Init();
203
  MX_TIM2_Init();
204
205
  /* USER CODE BEGIN 2 */
206
   
207
  /* USER Inits*/
208
209
      Init_Timer2(0, 255);
210
211
212
      Enable_Timerx_Counter(2);   
213
      Enable_LED_x(1, 50);
214
      Enable_LED_x(2, 65);
215
      Enable_LED_x(3, 80);
216
      Enable_LED_x(4, 100);
217
    
218
   
219
  
220
  
221
   
222
  /* USER CODE END 2 */
223
224
  /* Infinite loop */
225
  /* USER CODE BEGIN WHILE */
226
  while (1)
227
  {
228
 
229
  /* USER CODE END WHILE */
230
231
  /* USER CODE BEGIN 3 */
232
233
  }
234
  /* USER CODE END 3 */
235
236
}
237
238
/** System Clock Configuration
239
*/
240
void SystemClock_Config(void)
241
{
242
243
  RCC_OscInitTypeDef RCC_OscInitStruct;
244
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
245
  RCC_PeriphCLKInitTypeDef PeriphClkInit;
246
247
    /**Initializes the CPU, AHB and APB busses clocks 
248
    */
249
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
250
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
251
  RCC_OscInitStruct.HSICalibrationValue = 16;
252
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
253
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
254
  RCC_OscInitStruct.PLL.PLLM = 1;
255
  RCC_OscInitStruct.PLL.PLLN = 10;
256
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
257
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
258
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
259
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
260
  {
261
    Error_Handler();
262
  }
263
264
    /**Initializes the CPU, AHB and APB busses clocks 
265
    */
266
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
267
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
268
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
269
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
270
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
271
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
272
273
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
274
  {
275
    Error_Handler();
276
  }
277
278
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
279
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
280
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
281
  {
282
    Error_Handler();
283
  }
284
285
    /**Configure the main internal regulator output voltage 
286
    */
287
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
288
  {
289
    Error_Handler();
290
  }
291
292
    /**Configure the Systick interrupt time 
293
    */
294
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
295
296
    /**Configure the Systick 
297
    */
298
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
299
300
  /* SysTick_IRQn interrupt configuration */
301
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
302
}
303
304
/* ADC1 init function */
305
static void MX_ADC1_Init(void)
306
{
307
308
  ADC_MultiModeTypeDef multimode;
309
  ADC_ChannelConfTypeDef sConfig;
310
311
    /**Common config 
312
    */
313
  hadc1.Instance = ADC1;
314
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
315
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
316
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
317
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
318
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
319
  hadc1.Init.LowPowerAutoWait = DISABLE;
320
  hadc1.Init.ContinuousConvMode = DISABLE;
321
  hadc1.Init.NbrOfConversion = 1;
322
  hadc1.Init.DiscontinuousConvMode = DISABLE;
323
  hadc1.Init.NbrOfDiscConversion = 1;
324
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
325
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
326
  hadc1.Init.DMAContinuousRequests = ENABLE;
327
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
328
  hadc1.Init.OversamplingMode = DISABLE;
329
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
330
  {
331
    Error_Handler();
332
  }
333
334
    /**Configure the ADC multi-mode 
335
    */
336
  multimode.Mode = ADC_MODE_INDEPENDENT;
337
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
338
  {
339
    Error_Handler();
340
  }
341
342
    /**Configure Regular Channel 
343
    */
344
  sConfig.Channel = ADC_CHANNEL_1;
345
  sConfig.Rank = 1;
346
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
347
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
348
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
349
  sConfig.Offset = 0;
350
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
351
  {
352
    Error_Handler();
353
  }
354
355
}
356
357
/* TIM1 init function */
358
static void MX_TIM1_Init(void)
359
{
360
361
  TIM_MasterConfigTypeDef sMasterConfig;
362
  TIM_OC_InitTypeDef sConfigOC;
363
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
364
365
  htim1.Instance = TIM1;
366
  htim1.Init.Prescaler = 1;
367
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
368
  htim1.Init.Period = 8;
369
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
370
  htim1.Init.RepetitionCounter = 255;
371
  if (HAL_TIM_OC_Init(&htim1) != HAL_OK)
372
  {
373
    Error_Handler();
374
  }
375
376
  if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK)
377
  {
378
    Error_Handler();
379
  }
380
381
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
382
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
383
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
384
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
385
  {
386
    Error_Handler();
387
  }
388
389
  sConfigOC.OCMode = TIM_OCMODE_TIMING;
390
  sConfigOC.Pulse = 0;
391
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
392
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
393
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
394
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
395
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
396
  if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
397
  {
398
    Error_Handler();
399
  }
400
401
  if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
402
  {
403
    Error_Handler();
404
  }
405
406
  if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
407
  {
408
    Error_Handler();
409
  }
410
411
  if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
412
  {
413
    Error_Handler();
414
  }
415
416
  sConfigOC.Pulse = 8;
417
  if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_5) != HAL_OK)
418
  {
419
    Error_Handler();
420
  }
421
422
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
423
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
424
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
425
  sBreakDeadTimeConfig.DeadTime = 0;
426
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
427
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
428
  sBreakDeadTimeConfig.BreakFilter = 0;
429
  sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
430
  sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
431
  sBreakDeadTimeConfig.Break2Filter = 0;
432
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
433
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
434
  {
435
    Error_Handler();
436
  }
437
438
  HAL_TIM_MspPostInit(&htim1);
439
440
}
441
442
/* TIM2 init function */
443
static void MX_TIM2_Init(void)
444
{
445
446
  TIM_MasterConfigTypeDef sMasterConfig;
447
  TIM_OC_InitTypeDef sConfigOC;
448
449
  htim2.Instance = TIM2;
450
  htim2.Init.Prescaler = 0;
451
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
452
  htim2.Init.Period = 0;
453
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
454
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
455
  {
456
    Error_Handler();
457
  }
458
459
  if (HAL_TIM_OnePulse_Init(&htim2, TIM_OPMODE_SINGLE) != HAL_OK)
460
  {
461
    Error_Handler();
462
  }
463
464
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
465
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
466
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
467
  {
468
    Error_Handler();
469
  }
470
471
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
472
  sConfigOC.Pulse = 0;
473
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
474
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
475
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
476
  {
477
    Error_Handler();
478
  }
479
480
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
481
  {
482
    Error_Handler();
483
  }
484
485
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
486
  {
487
    Error_Handler();
488
  }
489
490
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
491
  {
492
    Error_Handler();
493
  }
494
495
  HAL_TIM_MspPostInit(&htim2);
496
497
}
498
499
/** 
500
  * Enable DMA controller clock
501
  */
502
static void MX_DMA_Init(void) 
503
{
504
  /* DMA controller clock enable */
505
  __HAL_RCC_DMA1_CLK_ENABLE();
506
507
  /* DMA interrupt init */
508
  /* DMA1_Channel1_IRQn interrupt configuration */
509
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
510
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
511
512
}
513
514
/** Configure pins as 
515
        * Analog 
516
        * Input 
517
        * Output
518
        * EVENT_OUT
519
        * EXTI
520
*/
521
static void MX_GPIO_Init(void)
522
{
523
524
  GPIO_InitTypeDef GPIO_InitStruct;
525
526
  /* GPIO Ports Clock Enable */
527
  __HAL_RCC_GPIOC_CLK_ENABLE();
528
  __HAL_RCC_GPIOA_CLK_ENABLE();
529
  __HAL_RCC_GPIOB_CLK_ENABLE();
530
531
  /*Configure GPIO pin Output Level */
532
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_5, GPIO_PIN_RESET);
533
534
  /*Configure GPIO pin : PC13 */
535
  GPIO_InitStruct.Pin = GPIO_PIN_13;
536
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
537
  GPIO_InitStruct.Pull = GPIO_NOPULL;
538
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
539
540
  /*Configure GPIO pins : PA0 PA5 */
541
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_5;
542
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
543
  GPIO_InitStruct.Pull = GPIO_NOPULL;
544
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
545
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
546
547
  /*Configure GPIO pin : PC12 */
548
  GPIO_InitStruct.Pin = GPIO_PIN_12;
549
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
550
  GPIO_InitStruct.Pull = GPIO_NOPULL;
551
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
552
553
}
554
555
/* USER CODE BEGIN 4 */
556
557
/* USER CODE END 4 */
558
559
/**
560
  * @brief  This function is executed in case of error occurrence.
561
  * @param  None
562
  * @retval None
563
  */
564
void Error_Handler(void)
565
{
566
  /* USER CODE BEGIN Error_Handler */
567
  /* User can add his own implementation to report the HAL error return state */
568
  while(1) 
569
  {
570
  }
571
  /* USER CODE END Error_Handler */ 
572
}
573
574
#ifdef USE_FULL_ASSERT
575
576
/**
577
   * @brief Reports the name of the source file and the source line number
578
   * where the assert_param error has occurred.
579
   * @param file: pointer to the source file name
580
   * @param line: assert_param error line source number
581
   * @retval None
582
   */
583
void assert_failed(uint8_t* file, uint32_t line)
584
{
585
  /* USER CODE BEGIN 6 */
586
  /* User can add his own implementation to report the file name and line number,
587
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
588
  /* USER CODE END 6 */
589
590
}
591
592
#endif
593
594
/**
595
  * @}
596
  */ 
597
598
/**
599
  * @}
600
*/ 
601
602
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

: Bearbeitet durch User
von Patrick J. (ho-bit-hun-ter)


Bewertung
2 lesenswert
nicht lesenswert
Hi

Bitte:
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

mir fällt fast der Scrollrad-Finger ab, bis ich hier unten bin :/

von D. I. (Firma: Fa) (buell)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Habe den Code angehängt und nebenbei noch eine andere Variante für 
Init_Timer2(...) programmiert. Bekomme damit das gleiche Ergebnis wie im 
Bild oben. Mich würde es nun wirklich interessieren, was ich vergesse zu 
schalten oder falsch mache, da ich bereits vieles probiert, aber dabei 
nicht viel gelernt habe, weil ich eben nicht weiss, was ich nicht 
berücksichtige. Jetzt habe ich doch wirklich alles gesetzt, was in 
Christophers Rezept angegeben ist. Dieser alternative Code ist hier:

1
 void Init_Timer2(uint8_t Presc, uint8_t period)
2
{  /* General timer configuration */
3
    
4
    TIM_HandleTypeDef timer2base;
5
    TIM_OC_InitTypeDef timer2oc;
6
    
7
    RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;                    /* Peripheral clock enable */ 
8
    
9
    /* Timer base configuration */
10
    timer2base.Instance = TIM1;
11
    timer2base.Init.Prescaler = Presc;
12
    timer2base.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
13
    timer2base.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
14
    timer2base.Init.Period = period;
15
    timer2base.Init.RepetitionCounter = 0;
16
    
17
    /* Timer Output Compare configuration */
18
    timer2oc.OCMode = TIM_OCMODE_PWM1;
19
    timer2oc.OCPolarity = TIM_OCPOLARITY_HIGH;
20
    timer2oc.OCFastMode = TIM_OCFAST_DISABLE;
21
    timer2oc.OCIdleState = TIM_OCIDLESTATE_RESET;
22
    
23
    HAL_TIM_OC_ConfigChannel(&timer2base, &timer2oc, TIM_CHANNEL_1);
24
    HAL_TIM_OC_ConfigChannel(&timer2base, &timer2oc, TIM_CHANNEL_2);
25
    HAL_TIM_OC_ConfigChannel(&timer2base, &timer2oc, TIM_CHANNEL_3);
26
    HAL_TIM_OC_ConfigChannel(&timer2base, &timer2oc, TIM_CHANNEL_4);
27
28
   
29
   
30
   /* General configuration of GPIO for Timer2 PWM Generation*/
31
    GPIO_InitTypeDef gpio;
32
   
33
   /* GPIO Ports Clock Enable */
34
  __HAL_RCC_GPIOA_CLK_ENABLE();
35
  __HAL_RCC_GPIOB_CLK_ENABLE();
36
  
37
     /**TIM2 GPIO Configuration    
38
    PB3     ------> TIM2_CH2
39
    PB10     ------> TIM2_CH3
40
    PB11     ------> TIM2_CH4
41
    PA15     ------> TIM2_CH1 
42
    */
43
    gpio.Pin = GPIO_PIN_15;
44
    gpio.Mode = GPIO_MODE_AF_PP;
45
    gpio.Pull = GPIO_NOPULL;
46
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
47
    gpio.Alternate = GPIO_AF1_TIM2;
48
    HAL_GPIO_Init(GPIOA, &gpio);
49
50
    gpio.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_3;
51
    gpio.Mode = GPIO_MODE_AF_PP;
52
    gpio.Pull = GPIO_NOPULL;
53
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
54
    gpio.Alternate = GPIO_AF1_TIM2;
55
    HAL_GPIO_Init(GPIOB, &gpio);
56
     
57
}

: Bearbeitet durch User
von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
In den superscharfen Oszi Bildern kann man leider nicht die 
Zeiteinstellung entziffern.
Wenn ich mir aber die Flanke so ansehe, kann es sein das die Zeit viel 
zu klein eingestellt ist?
Bei meinem 500Hz Beispiel waren es 200µs/Teil.

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Morgen

Ich kann das Bild gerne nochmals machen, aber meinst du die 
Zeiteinstellung beim Oszi oder die Werte, die ich den Funktionen 
uebergeben habe. Beim Oszi habe ich die Zeit so eingestellt, dass das 
Signal ganz zu sehen war. Es bleibt nach der Steigung auf high. 
(gespiegeltes z um Ordinate)

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D.I schrieb:
> Zeiteinstellung beim Oszi

genau die. Wie ist die?

von D. I. (Firma: Fa) (buell)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
pegel schrieb:
> D.I schrieb:
>> Zeiteinstellung beim Oszi
>
> genau die. Wie ist die?

Ok, das ist schon mal erfreulich, bei meinem alten Oszi messe ich das 
Signal im Kanal 1 jetzt. Die Einstellung ist 100ms.
An all den anderen Kanälen messe ich nichts. Warum?

Um das Center-aligned festzustellen, brauche ich einen 2. Kanal..
1
void Init_Timer2(uint8_t Presc, uint8_t period)
2
{    
3
       /* General configuration for all Timer 1 Channels 1-4*/  
4
   RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;                    /* Peripheral clock enable */  
5
   TIM2->CR1 |= TIM_CR1_CMS_0;                              /* Select the Counter Centeraligned Mode 1 */
6
   TIM2->CR1 &= ~TIM_CR1_CKD;                               /* Erase bits of CKD */
7
   TIM2->PSC = Presc;                                       /* Set the Prescaler value */
8
   TIM2->ARR = period - 1;                                  /* Set the Auto-reload value - top value counter*/
9
 
10
        /* Configure register bits for Channel 1*/
11
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC1M;                  /* OC1 is low until CCR1, with PWM mode 2 the polarity is set */
12
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC1S;                /* Set CC1 as output */
13
   TIM2->CCER &= ~TIM_CCER_CC1P;                            /* CC1P for OC1 active high */
14
   
15
   
16
          /* Configure register bits for Channel 1*/
17
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC2M;                  /* OC2 is low until CCR1, with PWM mode 2 the polarity is set */
18
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC2S;                /* Set CC2 as output */
19
   TIM2->CCER &= ~TIM_CCER_CC2P;                            /* CC2P for OC2 active high */
20
   
21
          /* Configure register bits for Channel 3*/
22
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC3M;                  /* OC3 is low until CCR1, with PWM mode 2 the polarity is set */
23
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC3S;                /* Set CC3 as output */
24
   TIM2->CCER &= ~TIM_CCER_CC3P;                            /* CC3P for OC3 active high */
25
   
26
          /* Configure register bits for Channel 4*/
27
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC4M;                  /* OC4 is low until CCR1, with PWM mode 2 the polarity is set */
28
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC4S;                /* Set CC4 as output */
29
   TIM2->CCER &= ~TIM_CCER_CC4P;                            /* CC4P for OC4 active high */
30
   
31
   
32
   /* General configuration of GPIO for Timer2 PWM Generation*/
33
    GPIO_InitTypeDef gpio;
34
   
35
   /* GPIO Ports Clock Enable */
36
  __HAL_RCC_GPIOA_CLK_ENABLE();
37
  __HAL_RCC_GPIOB_CLK_ENABLE();
38
  
39
     /**TIM2 GPIO Configuration    
40
    PB3     ------> TIM2_CH2
41
    PB10     ------> TIM2_CH3
42
    PB11     ------> TIM2_CH4
43
    PA15     ------> TIM2_CH1 
44
    */
45
    gpio.Pin = GPIO_PIN_15;
46
    gpio.Mode = GPIO_MODE_AF_PP;
47
    gpio.Pull = GPIO_NOPULL;
48
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
49
    gpio.Alternate = GPIO_AF1_TIM2;
50
    HAL_GPIO_Init(GPIOA, &gpio);
51
52
    gpio.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_3;
53
    gpio.Mode = GPIO_MODE_AF_PP;
54
    gpio.Pull = GPIO_NOPULL;
55
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
56
    gpio.Alternate = GPIO_AF1_TIM2;
57
    HAL_GPIO_Init(GPIOB, &gpio);
58
     
59
}

: Bearbeitet durch User
von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D. S. schrieb:
> An all den anderen Kanälen messe ich nichts. Warum?

200ms für ein PWM Signal?
Das ist schon gewaltig. Da stimmt mit der ganzen Dimensionierung der 
Zeiten etwas nicht.
Das zurück rechnen der ganzen Register Werte darfst du selbst 
übernehmen.
Ich würde bei mir einfach in CubeMX nachsehen ;)

von D. I. (Firma: Fa) (buell)


Bewertung
0 lesenswert
nicht lesenswert
pegel schrieb:
> D. S. schrieb:
>> An all den anderen Kanälen messe ich nichts. Warum?
>
> 200ms für ein PWM Signal?
> Das ist schon gewaltig. Da stimmt mit der ganzen Dimensionierung der
> Zeiten etwas nicht.
> Das zurück rechnen der ganzen Register Werte darfst du selbst
> übernehmen.
> Ich würde bei mir einfach in CubeMX nachsehen ;)

Ja, das komische ist auch jedes mal wenn ich neu starte, wird der Puls 
schmäler und wieder so breit wie der Puls im Bild ist. ??

Das gibts ja nicht.
Was meinst du mit zurückrechnen der Register? Was soll ich rechnen?
Die Werte die ich übergeben habe?
Rein rechnerisch sollte mir doch der Puls bei 80MHz und einem Wert von 
50 --> 625ns breit sein.

Nebenbei: Stimmt der Code so wie er ist oder fehlt noch etwas, das ich 
vergessen habe? Ansonsten brauche ich nichts rechnen, wenn schon das 
falsch ist.

: Bearbeitet durch User
von DraconiX (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christopher J. schrieb:
> Diese Kombination sehe ich zum ersten mal.
>
> Wem der HAL von ST taugt und damit glücklich wird soll es auch
> meinetwegen benutzen. Ich frage mich nur was diese Leute dann machen,
> wenn ein bestimmtes Hardware-Feature nicht in CubeMX per Eingabemaske
> konfigurierbar ist. Die vorgehensweise des TO (CubeMX irgendetwas
> generieren lassen, irgendetwas in die Register schreiben, Trial and
> Error) sehe ich jedenfalls als ultimatives Rezept wie man kurz- und/oder
> langfristig - aber in jedem Fall hart - auf die Nase fällt.

Di HAL Lib an sich ist ja Top. Wenn man einmal dahintergestiegen ist. 
Die Codeerstellung von CubeMX hingegen ist der größte Mist. Da werden, 
wenn man einen Timer generieren läßt nichteinmal die _TIM_START 
gesetzt, somit läuft der Timer nichtmal nach Generierrung und man sucht 
sich einen Wolf.

Genauso mit dem Handler, CubeMX macht da z.b. einfach ein 
"TIM_HandleTypeDef htim2" drauß, welches nicht auf TIM2 instanziert ist.

Genauso der erzeugte Code ist massig überladen mit Dingen die man 
garnicht braucht. Eine Timerinterrupt unter HAL sieht bei mir für 100khz 
bei 64Mhz auf Timer2 normalerweise so aus:
1
static TIM_HandleTypeDef s_TimerInstance = {
2
    .Instance = TIM2
3
};
4
5
void TIM2_IRQHandler()
6
{
7
    //Interrupt Code before Reset
8
9
    HAL_TIM_IRQHandler(&s_TimerInstance);
10
11
    //Interrupt Code after Reset
12
13
}
14
15
16
void InitializeTimer()
17
{
18
    __TIM2_CLK_ENABLE();
19
    s_TimerInstance.Init.Prescaler = 1;
20
    s_TimerInstance.Init.CounterMode = TIM_COUNTERMODE_UP;
21
    s_TimerInstance.Init.Period = 31999;
22
    s_TimerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV2;
23
    s_TimerInstance.Init.RepetitionCounter = 0;
24
    HAL_TIM_Base_Init(&s_TimerInstance);
25
    HAL_TIM_Base_Start(&s_TimerInstance);
26
    HAL_TIM_Base_Start_IT(&s_TimerInstance);
27
28
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
29
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
30
}

Lasse ich das gleiche von CubeMX erzeugen sind da dröffllzig-Tausend 
Zeilen Code und nix läuft.

von pegel (Gast)


Angehängte Dateien:
  • x5.bin (7,12 KB, 11 Downloads)

Bewertung
0 lesenswert
nicht lesenswert
D. S. schrieb:
> Ja, das komische ist auch jedes mal wenn ich neu starte, wird der Puls
> schmäler und wieder so breit wie der Puls im Bild ist. ??

Oha.
Ist die Hardware iO?

DraconiX schrieb:
> Lasse ich das gleiche von CubeMX erzeugen sind da dröffllzig-Tausend
> Zeilen Code und nix läuft.

Nichts desto trotz hänge ich eine bin für das Board das ich selbst nicht 
hier habe für einen Funkionstest an.

An PA8 sollte 500Hz PWM 10% erscheinen und die grüne LED im Sekunden 
Takt fröhlich blinken.

von Christopher J. (christopher_j23)


Bewertung
0 lesenswert
nicht lesenswert
D. S. schrieb:
> Die Einstellung ist 100ms.

Und du bekommst das doppelte weil es ein Up-Down-Counter ist 
(center-aligned).

D. S. schrieb:
> An all den anderen Kanälen messe ich nichts. Warum?

Wahrscheinlich weil das hier nicht funktioniert.
D. S. schrieb:
> gpio.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_3;
>     gpio.Mode = GPIO_MODE_AF_PP;
>     gpio.Pull = GPIO_NOPULL;
>     gpio.Speed = GPIO_SPEED_FREQ_LOW;
>     gpio.Alternate = GPIO_AF1_TIM2;
>     HAL_GPIO_Init(GPIOB, &gpio);

Insbesondere
> gpio.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_3;
funktioniert wahrscheinlich nicht aber das ist nur eine Mutmaßung 
meinerseits. Habe vom ST HAL nicht so den Plan.

von D. I. (Firma: Fa) (buell)


Bewertung
0 lesenswert
nicht lesenswert
Christopher J. schrieb:
> D. S. schrieb:
>> Die Einstellung ist 100ms.
>
> Und du bekommst das doppelte weil es ein Up-Down-Counter ist
> (center-aligned).
>
> D. S. schrieb:
>> An all den anderen Kanälen messe ich nichts. Warum?
>
> Wahrscheinlich weil das hier nicht funktioniert.
> D. S. schrieb:
>> gpio.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_3;
>>     gpio.Mode = GPIO_MODE_AF_PP;
>>     gpio.Pull = GPIO_NOPULL;
>>     gpio.Speed = GPIO_SPEED_FREQ_LOW;
>>     gpio.Alternate = GPIO_AF1_TIM2;
>>     HAL_GPIO_Init(GPIOB, &gpio);
>
> Insbesondere
>> gpio.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_3;
> funktioniert wahrscheinlich nicht aber das ist nur eine Mutmaßung
> meinerseits. Habe vom ST HAL nicht so den Plan.

Hallo Christopher

Also ich habe folgendes versucht (sollte aber meiner Meinung nach nicht 
das Problem sein):

Weisst du was komisch ist? Ich kommentiere alles im main() ausser 
Init_Timer2(..) also die Funktion unten. Und wenn ich das Programm lade 
und auf reset drücke, kommt immer ein Signal auf PA15 aber sonst 
nirgends..
Einmal schaffe ich mehr Signale auf einmal und manchmal auch nur ein 
Einziges und das ohne, überhaupt den Timer gestartet (CEN) und die 
Kanäle freigeschaltet zu haben (CC1E etc).
Ich verzweifel gleich..

1
void Init_Timer2(uint8_t Presc, uint8_t period)
2
{    
3
   /* General configuration for all Timer 1 Channels 1-4*/  
4
   RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;                    /* Peripheral clock enable */  
5
   TIM2->CR1 |= TIM_CR1_CMS_0;                              /* Select the Counter Centeraligned Mode 1 */
6
   TIM2->CR1 &= ~TIM_CR1_CKD;                               /* NO clock division CKD */
7
   TIM2->PSC = Presc;                                       /* Set the Prescaler value */
8
   TIM2->ARR = period - 1;                                  /* Set the Auto-reload value - top value counter*/
9
 
10
   /* Configure register bits for Channel 1*/
11
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC1M;                  /* OC1 is low until CCR1, with PWM mode 2 the polarity is set */
12
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC1S;                /* Set CC1 as output */
13
   TIM2->CCER &= ~TIM_CCER_CC1P;                            /* CC1P for OC1 active high */
14
   
15
   
16
   /* Configure register bits for Channel 1*/
17
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC2M;                  /* OC2 is low until CCR2, with PWM mode 2 the polarity is set */
18
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC2S;                /* Set CC2 as output */
19
   TIM2->CCER &= ~TIM_CCER_CC2P;                            /* CC2P for OC2 active high */
20
   
21
   /* Configure register bits for Channel 3*/
22
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC3M;                  /* OC3 is low until CCR3, with PWM mode 2 the polarity is set */
23
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC3S;                /* Set CC3 as output */
24
   TIM2->CCER &= ~TIM_CCER_CC3P;                            /* CC3P for OC3 active high */
25
   
26
   /* Configure register bits for Channel 4*/
27
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC4M;                  /* OC4 is low until CCR4, with PWM mode 2 the polarity is set */
28
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC4S;                /* Set CC4 as output */
29
   TIM2->CCER &= ~TIM_CCER_CC4P;                            /* CC4P for OC4 active high */
30
   
31
   
32
   /* General configuration of GPIO for Timer2 PWM Generation*/
33
    GPIO_InitTypeDef gpio;
34
   
35
   /* GPIO Ports Clock Enable */
36
  __HAL_RCC_GPIOA_CLK_ENABLE();
37
  __HAL_RCC_GPIOB_CLK_ENABLE();
38
  
39
     /**TIM2 GPIO Configuration    
40
    PB3     ------> TIM2_CH2
41
    PB10     ------> TIM2_CH3
42
    PB11     ------> TIM2_CH4
43
    PA15     ------> TIM2_CH1 
44
    */
45
    gpio.Pin = GPIO_PIN_15;
46
    gpio.Mode = GPIO_MODE_AF_PP;
47
    gpio.Pull = GPIO_NOPULL;
48
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
49
    gpio.Alternate = GPIO_AF1_TIM2;
50
    HAL_GPIO_Init(GPIOA, &gpio);
51
52
    gpio.Pin = GPIO_PIN_10;
53
    gpio.Mode = GPIO_MODE_AF_PP;
54
    gpio.Pull = GPIO_NOPULL;
55
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
56
    gpio.Alternate = GPIO_AF1_TIM2;
57
    HAL_GPIO_Init(GPIOB, &gpio);
58
    
59
    gpio.Pin = GPIO_PIN_3;
60
    gpio.Mode = GPIO_MODE_AF_PP;
61
    gpio.Pull = GPIO_NOPULL;
62
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
63
    gpio.Alternate = GPIO_AF1_TIM2;
64
    HAL_GPIO_Init(GPIOB, &gpio);
65
    
66
    gpio.Pin = GPIO_PIN_11;
67
    gpio.Mode = GPIO_MODE_AF_PP;
68
    gpio.Pull = GPIO_NOPULL;
69
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
70
    gpio.Alternate = GPIO_AF1_TIM2;
71
    HAL_GPIO_Init(GPIOB, &gpio);
72
     
73
}

pegel schrieb:


> Nichts desto trotz hänge ich eine bin für das Board das ich selbst
> nicht  hier habe für einen Funkionstest an.
>
> An PA8 sollte 500Hz PWM 10% erscheinen und die grüne LED im Sekunden
> Takt fröhlich blinken.

Was kann ich nun genau anfangen damit bzw. wo muss ich das 
reinspeichern, um testen zu können?

danke

: Bearbeitet durch User
von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D. S. schrieb:
> Was kann ich nun genau anfangen damit

Deiner Beschreibung nach bin ich nicht sicher ob das Nucleo Board 
wirklich in Ordnung ist.
Du könntest die bin mit dem ST-Link Utility testhalber flashen und sehen 
ob es wie beschrieben funktioniert. Wenn nicht gibt es vielleicht ein 
Problem das mit dem Programm garnichts zu tun hat.

D. S. schrieb:
> Ja, das komische ist auch jedes mal wenn ich neu starte, wird der Puls
> schmäler und wieder so breit wie der Puls im Bild ist.

Ist nicht so ganz eindeutig.

von D. I. (Firma: Fa) (buell)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Christophers Rezept war top. Man muss einfach nur stur das machen, was 
da steht. :P
Danke vielmals

Jetzt funktionierts.
Bei 2 Kanälen tuts, bei anderen nicht..
Keine Ahnung warum, solder bridges sind auch keine dort, aber ok.
Soweit mal gut:

Jetzt passt auch die Zeit
Bei einer Eingabe
Init_Timer2(0, 1000);
Enable_Flash_LED_x(1,20); //Kanal 1
Enable_Flash_LED_x(2,80); // Kanal 2

ergibt sich bei 80MHz --> 1/(80.000.000*20*2) = 0,5us-> 500ns
und im Kanal 2000ns

das stimmt soweit.
und der Code:
1
void Init_Timer2(uint8_t Presc, uint16_t period)
2
{    
3
   /* General configuration for all Timer 1 Channels 1-4*/  
4
   RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;                    /* Peripheral clock enable */  
5
   TIM2->CR1 |= TIM_CR1_CMS_0;                              /* Select the Counter Centeraligned Mode 1 */
6
   TIM2->CR1 &= ~TIM_CR1_CKD;                               /* NO clock division CKD */
7
   TIM2->EGR |= TIM_EGR_UG;                                 /* Update generation - Reinitializes the counter and generates an update of the registers */   
8
   TIM2->PSC = Presc;                                       /* Set the Prescaler value */
9
   TIM2->ARR = period - 1;                                  /* Set the Auto-reload value - top value counter*/
10
 
11
   /* Configure register bits for Channel 1*/
12
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC1M;                  /* OC1 is low until CCR1, with PWM mode 2 the polarity is set */
13
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC1S;                /* Set CC1 as output */
14
   TIM2->CCER |= TIM_CCER_CC1P;                             /* CC1P for OC1 active low */
15
   TIM2->CCMR1 |= TIM_CCMR1_OC1PE;                          /* Preload register has to be set */
16
   
17
   
18
   /* Configure register bits for Channel 1*/
19
   TIM2->CCMR1 |=(uint16_t)TIM_CCMR1_OC2M;                  /* OC2 is low until CCR2, with PWM mode 2 the polarity is set */
20
   TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_CC2S;                /* Set CC2 as output */
21
   TIM2->CCER |= TIM_CCER_CC2P;                             /* CC2P for OC2 active low */
22
   TIM2->CCMR1 |= TIM_CCMR1_OC2PE;                          /* Preload register has to be set */
23
   
24
   /* Configure register bits for Channel 3*/
25
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC3M;                  /* OC3 is low until CCR3, with PWM mode 2 the polarity is set */
26
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC3S;                /* Set CC3 as output */
27
   TIM2->CCER |= TIM_CCER_CC3P;                             /* CC3P for OC3 active low */
28
   TIM2->CCMR2 |= TIM_CCMR2_OC3PE;                          /* Preload register has to be set */
29
   
30
   /* Configure register bits for Channel 4*/
31
   TIM2->CCMR2 |=(uint16_t)TIM_CCMR2_OC4M;                  /* OC4 is low until CCR4, with PWM mode 2 the polarity is set */
32
   TIM2->CCMR2 &= (uint16_t)~TIM_CCMR2_CC4S;                /* Set CC4 as output */
33
   TIM2->CCER |= TIM_CCER_CC4P;                             /* CC4P for OC4 active low */
34
   TIM2->CCMR2 |= TIM_CCMR2_OC4PE;                          /* Preload register has to be set */
35
   
36
   
37
   /* GPIO Ports Clock Enable */
38
    __HAL_RCC_GPIOA_CLK_ENABLE();
39
40
    GPIO_InitTypeDef GPIO_InitStruct;
41
  
42
    /**TIM2 GPIO Configuration    
43
    PA0     ------> TIM2_CH1
44
    PA1     ------> TIM2_CH2
45
    PA2     ------> TIM2_CH3
46
    PA3     ------> TIM2_CH4 
47
    */
48
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
49
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
50
    GPIO_InitStruct.Pull = GPIO_NOPULL;
51
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
52
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
53
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
54
    
55
     GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
56
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
57
    GPIO_InitStruct.Pull = GPIO_NOPULL;
58
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
59
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
60
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
61
     
62
}

: Bearbeitet durch User
von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Damit ist das Board dann in Ordnung.
Beachte das PA2 und PA3 die USART Pins zu ST-Link sind.

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Kanal 3 und 4 kannst du auf PB10 und PB11 legen.

von Forist (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D. S. schrieb:
> 20170411_210054.jpg

D. S. schrieb:
> 20170412_095115_1_.jpg

D. S. schrieb:
> 20170412_210013.jpg

Hat weder das Agilent-, noch das TEK-Scope einen USB-Slot, wo man für 
vernünftige Screen Shots mal einen Speicherstick reinstecken kann?

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
doch aber ich hab kein usb stick gehabt  :)

@pegel

genau pb10 und pb11 gehen nicht pa15 auch nicht. ich kriegs nur mit pa0 
und pa1 zustande..

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D.I schrieb:
> genau pb10 und pb11 gehen nicht

Passt nicht zu

D. S. schrieb:
> GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
>     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
>     GPIO_InitStruct.Pull = GPIO_NOPULL;
>     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
>     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
>     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
pegel schrieb:
> D.I schrieb:
> genau pb10 und pb11 gehen nicht
>
> Passt nicht zu
> D. S. schrieb:
> GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
>     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
>     GPIO_InitStruct.Pull = GPIO_NOPULL;
>     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
>     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
>     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

klar, ich hatte es zuvor auf 10 u 11 und porta bei der uebergabe in der 
funktion. hatte auch so nicht getan. ich glaub das board ist irgendwie 
nich ganz funktionstuechtig...

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
oder nicht mehr..

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D.I schrieb:
> auf 10 u 11 und porta

porta? Sollen aber PB10 und 11 sein.

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
oder nicht mehr..

pegel schrieb:
> D.I schrieb:
> auf 10 u 11 und porta
>
> porta? Sollen aber PB10 und 11 sein.

ach sorry port b. bin im restaurant am pizzaessen. da sind die gedanken 
wo anders ??

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mahlzeit!

von D.I (Gast)


Bewertung
0 lesenswert
nicht lesenswert
danke
ich probiers spaeter mal mit dem stm32f303

von D. I. (Firma: Fa) (buell)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habe es jetzt mal versucht mit dem STM32F303.
Da funktionierte es. Bei einem Pin musste ich aber auf AF10 mappen.
Dann habe ich es nochmals auf dem STM32L476 Nucleo angeschlossen und 
gemessen und dann ging es, nachdem ich wieder den einen Pin auf seinen 
ursprünglichen AF Kanal zurück gemappt habe.

Keine Ahnung was ich falsch bzw. richtig gemacht habe. Das Einzige was 
mich stört dabei ist, dass ich nicht klüger geworden bin.. :(

von Suppunternehmer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
D. S. schrieb:
> Das Einzige was
> mich stört dabei ist, dass ich nicht klüger geworden bin.. :(

Aber dicker:
:)
D.I schrieb:
> bin im restaurant am pizzaessen. da sind die gedanken
> wo anders ??

Hauptsache, Du hast die Pizza an den richtigen Eingang angelegt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.