PWM mit den HAL-Bibliotheken von ST auf STM32F4 zum Laufen bringen


7

Ich versuche, zu den ST HAL-Bibliotheken zu wechseln, und kann die PWM anscheinend nicht zum Laufen bringen. Kompiliert gut, startet einfach nicht.

In meinem main () rufe ich die Timer-Initialisierungsfunktion auf:

/* TIM3 init function */
void MX_TIM3_Init(void)
{

  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 1300;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_PWM_Init(&htim3);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_SET;
  sConfigOC.Pulse = 650;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;

  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3);
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4);
  HAL_TIM_PWM_MspInit(&htim3);

} 

Das GPIO wird in der HAL_TIM_PWM_MspInit()Funktion initialisiert :

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(htim_pwm->Instance==TIM3)
  {
    /* Peripheral clock enable */
    __TIM3_CLK_ENABLE();

    /**TIM3 GPIO Configuration    
    PC9     ------> TIM3_CH4
    PC8     ------> TIM3_CH3
    PC7     ------> TIM3_CH2
    PC6     ------> TIM3_CH1 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8|GPIO_PIN_7|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  }

}}

Schließlich sieht mein main () folgendermaßen aus: (Ich rufe SystemInit () von main auf, weil ich STCube-generierte Dateien mit coocox coide verwende.)

int main(void)
{

    SystemInit() ;

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_TIM3_Init();
  MX_GPIO_Init();
  MX_LWIP_Init();
  while (1)
  {

  }

}

Am Ende ging ich zurück zu den alten Bibliotheken, weil sie kein Problem hatten - ich arbeitete an einem Protoboard mit dem stm32F417IG und wollte es einfach wieder zum Laufen bringen! Hoffentlich habe ich Zeit, darauf zurückzukommen und das HAL-Zeug zum Laufen zu bringen. Danke für alle Antworten!
Oboist B

Antworten:


6

Ich bin zu spät zur Party, aber ich befand mich in einer ähnlichen Situation und habe die richtige Antwort oder zumindest die Antwort, die ich persönlich überprüft habe, um mit meinem eigenen STM32-Board und den STM32CubeMx-Treibern zu arbeiten.

  1. Stellen Sie sicher, dass Sie Ihre vom Stapel zugewiesenen Strukturen initialisieren (auf Null setzen). zB memset(&sConfigOC, 0, sizeof(sConfigOC));Lokale Variablen werden nicht automatisch initialisiert und Sie haben eine unerwartete / unbeabsichtigte Konfiguration, da die HAL basierend auf diesen Handle-Variablen sehr grundlegende Annahmen über den Peripheriezustand trifft. Es ist besonders ärgerlich, wenn sich das Verhalten von Kompilieren zu Kompilieren oder von Funktionsaufruf zu Funktionsaufruf ändert, wenn sich der Stapelspeicher ändert.
  2. Rufen Sie nicht HAL_TIM_PWM_MspInit()manuell an. Es wird automatisch aufgerufen, wenn Sie aufrufen HAL_TIM_PWM_Init(), aber Sie müssen sicherstellen, dass Ihre Handle-Variablen ordnungsgemäß initialisiert sind (siehe Nr. 1 oben).
  3. Sie müssen nicht anrufen, HAL_TIMEx_MasterConfigSynchronization()wenn Sie nicht von der Standardkonfiguration (nicht verkettet / synchronisiert) wechseln. Es wird nichts schaden, aber es ist auch nicht notwendig.
  4. Ihre MspInit()Funktion ist gut, außer dass Sie auch die Uhr des GPIOC-Peripheriegeräts aktivieren sollten.

Und die Magie, die verhindert, dass es funktioniert:

  1. Sie MÜSSEN rufen HAL_TIM_PWM_Start()nach jedem Anruf HAL_TIM_PWM_ConfigChannel()- das erste , was HAL_TIM_PWM_ConfigChannel()tut , ist die Timer - Ausgänge (die deaktivieren CCxEBits in TIMx_CCER). HAL_TIM_PWM_ConfigChannel()aktiviert die Timer-Ausgänge nicht wieder!

Da die einzige HAL-Methode zum manuellen Aktualisieren des PWM-Arbeitszyklus abgeschlossen ist HAL_TIM_PWM_ConfigChannel(), müssen Sie immer anrufen, da HAL_TIM_PWM_Start()Sie sonst keinen PWM-Ausgang haben. Ich denke, dies geschieht, weil die normale Arbeitsweise mit PWM darin besteht, die _IT()oder _DMA()Varianten von zu verwenden HAL_TIM_PWM_Start(), und Sie daher den Arbeitszyklus sozusagen "im Hintergrund" aktualisieren.

Einige der anderen Antworten (einschließlich der, die Sie als akzeptiert markiert haben) sind falsch:

  1. Rufen Sie HAL_TIM_Base_Start()weder HAL_TIM_Base_Init()noch andere Nicht-PWM-Anrufe an. Erstens ruft die HAL Ihre PWM_MspInit()Funktion nicht auf, da sich das Peripherie-Handle nicht mehr im Reset-Zustand befindet. Noch wichtiger ist jedoch, dass die PWM (und OC und andere Varianten) die internen Funktionen auf niedriger Ebene ordnungsgemäß aufrufen, ohne dass Sie dies manuell tun. Der ganze Sinn der HAL ist es, sich nicht so sehr um die Details kümmern zu müssen, aber Sie müssen einen guten Überblick darüber haben, was die HAL tut und was sie erwartet. Die vollständige Quelle ist verfügbar und ziemlich gut dokumentiert. Sie müssen es nur lesen.
  2. Sie müssen keine HAL_TIMEx_PWMN_Start()der anderen TIMExFunktionen aufrufen, es sei denn, Sie verwenden die kostenlosen Ausgänge. Auch dies ist in der HAL-Quelle ziemlich gut dokumentiert.

Versuchte andere Vorschläge, aber keiner funktionierte, dies funktionierte für mich unter Verwendung des Olimex H103-Boards. Dies basiert auf dem STM32F103RBT6. Ich habe einfach die folgende Zeile zwischen USER CODE BEGIN 2 und USER CODE END 2 in main.c hinzugefügt. HAL_TIM_PWM_Start (& htim3, TIM_CHANNEL_1);
Pop24

6

Ich verwende STCubeMX und die generierten HAL-Initialisierungsdateien. Prozess auf meinem F302 Nucleo Board überprüft. Ich habe den erweiterten Timer 1 (TIM1) mit einem normalen und komplementären Ausgang ohne Totzeit eingerichtet.

So habe ich PWM in CubeMX konfiguriert:

  1. In der Pinbelegungsansicht habe ich zwei Pins als TIM1_CH- und TIM1_CHN-Pins ausgewählt. Stellen Sie im linken Bereich TIM1-Kanal 1 als "PWM-Generation CH1 CH1N" ein.
  2. Auf der Registerkarte Konfiguration habe ich die folgende Einstellung vorgenommen (TIM1 clk ist 64MHz) CubeMX TIM1 Konfigurationseinstellungen
  3. Nachdem der Code generiert wurde, müssen wir die PWM noch starten. Dies erfolgt durch Aufrufen der folgenden Funktionen in der Benutzercode-Region vor while (1) in main ():

    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //starts PWM on CH1 pin HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); //starts PWM on CH1N pin

  4. Verwenden Sie die folgenden Makros in stm32f3xx_hal_tim.h, um die Konfigurationseinstellungen zu ändern. HAL_TIM_PWM_ConfigChannel()ist nicht die einzige Möglichkeit, die PWM-Einstellung manuell zu aktualisieren, wie von @akohlsmith angegeben.

    __HAL_TIM_GET_AUTORELOAD(&htim1); //gets the Period set for PWm __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyCycle); //sets the PWM duty cycle (Capture Compare Value)

Sie müssen nicht erneut anrufen HAL_TIM_PWM_Start(). Diese Makros ändern die Einstellung zur Laufzeit.


6

Bei Verwendung von Cube Mx initialisiert der generierte Code das Timer-Peripheriegerät, startet es jedoch nicht. Die Lösung ist wie von anderen vorgeschlagen: Fügen Sie die Startfunktionen hinzu.

HAL_TIM_Base_Start(&htim3); 
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_ALL); 

Platzieren Sie diesen Code im Abschnitt "USER CODE" nach dem generierten Code, der aufgerufen wird MX_TIM3_Init().


2
Ich habe dies für einen Nucleo-32 (Mikrocontroller STM32F042K6) versucht, auch für Timer 3. Es hat beim zweiten Aufruf nicht funktioniert TIM_CHANNEL_ALL, aber TIM_CHANNEL1 stattdessen funktioniert (es hat die tatsächliche PWM-Ausgabe am Ausgangspin gestartet). In ähnlicher Weise für die anderen Kanäle 3, unter Verwendung von TIM_CHANNEL2, TIM_CHANNEL3und TIM_CHANNEL14jeweils in dem Aufruf HAL_TIM_PWM_Start()(SO4 Anrufe in all HAL_TIM_PWM_Start()).
Peter Mortensen

Der Aufruf an HAL_TIM_Base_Start(&htim3);wird nicht benötigt (empirisch ermittelt und auch in Akohlsmiths Antwort ).
Peter Mortensen

@PeterMortensen das ist genial. Erstaunlich, wie wenig Informationen so viel bedeuten können. Vielen Dank für das Teilen. Dies war auch für ein benutzerdefiniertes STM32F412-Board von entscheidender Bedeutung.
Heath Raftery

2

Sie müssen zuerst den Timer starten. Fügen Sie die nächste Zeile hinzu main(), um timer3 zu starten CH1:

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);

0
        void PWM_Output(void)
        {


          TimerPeriod = 1000;



          /* TIM1 clock enable */
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);

          /* Time Base configuration */
          TIM_TimeBaseStructure.TIM_Prescaler = 48;
          TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
          TIM_TimeBaseStructure.TIM_Period = TimerPeriod;
          TIM_TimeBaseStructure.TIM_ClockDivision = 1;
          TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

          TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

          /* Channel 1, 2, 3 and 4 Configuration in PWM mode */
          TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
          TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
          TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;



          TIM_OCInitStructure.TIM_Pulse = 899;
          TIM_OC1Init(TIM1, &TIM_OCInitStructure);

          TIM_OCInitStructure.TIM_Pulse = 899;
          TIM_OC2Init(TIM1, &TIM_OCInitStructure);

          TIM_OCInitStructure.TIM_Pulse = 899;
          TIM_OC3Init(TIM1, &TIM_OCInitStructure);

          TIM_OCInitStructure.TIM_Pulse = 899;
          TIM_OC4Init(TIM1, &TIM_OCInitStructure);

          /* TIM1 counter enable */
          TIM_Cmd(TIM1, ENABLE);

          /* TIM1 Main Output Enable */
          TIM_CtrlPWMOutputs(TIM1, DISABLE);

        }

    void GPIO_init(){
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);


              GPIO_PWMEnPins.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
              GPIO_PWMEnPins.GPIO_Mode = GPIO_Mode_AF;
              GPIO_PWMEnPins.GPIO_Speed = GPIO_Speed_Level_1;
              GPIO_PWMEnPins.GPIO_OType = GPIO_OType_PP;
              GPIO_PWMEnPins.GPIO_PuPd = GPIO_PuPd_NOPULL;
              GPIO_Init(GPIOA, &GPIO_PWMEnPins);

 /*SMT32F0 has different config for Alternate Function assignment; below is the example. STM32F4 might have less code footprint to configure alternate func.*/
              GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_2);
              GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_2);
              GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_2);
              GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_2);

    }

Dieser Code funktioniert in CooCox mit Standardbibliotheken STM32f0xx_yyy. Sie müssen auch die GPIOC-Uhr in GPIO init aktivieren.


Das mag funktionieren, aber die Frage war nach der Verwendung der ST HAL-Bibliotheken.
Peter Mortensen

0

Ich denke, Sie müssen die GPIO-Uhr durch einen Anruf initialisieren __GPIOC_CLK_ENABLE();

Ich habe ähnlichen Code - aber ich habe das Master-Konfigurationsmaterial weggelassen.

Im Ordner stm32g-eval gibt es ein Beispiel, das an das Discovery Board angepasst werden kann (wenn dies das Board ist, das Sie verwenden).


0

Sie müssen dazu:

HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_ALL);
HAL_TIMEx_PWMN_Start(&htim3,TIM_CHANNEL_ALL);

3
Bitte erklären Sie wo und warum.
JRE

Das "_IT" bezieht sich auf etwas Interrupt-bezogenes. Warum sollte das nur benötigt werden, um eine PWM-Ausgabe zu erhalten?
Peter Mortensen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.