Sida 1 av 1

STM32 PWM problem

Postat: 24 juli 2011, 16:39:44
av lizerdboy
Har nu drivit mig själv till vansinne här i dag då jag tog mig an nästa problem.

Har länge sett att det kommer små fel i PWM signalen lite till och från.
Och efter min Motor H-bridge lösning som jag posta tidigare så har detta kommit mer än tidigare, troligtvis iaf.

Saken är att jag uppdaterar PWM duty cycle varje ms, och i bland verkar inte PWM signalen funka efter uppdateringen.
utan hoppar igång nästa uppdatering ist.
felet är inte regelbundet utan kommer och går.

Jag har länge letat efter hur man uppdaterar PWM kanalerna på STM32 mcu som jag jobbar mot.
Har sett detta problem tidigare på andra konstruktioner när jag har styrt buzzers via PWM, då löste jag det med att inte uppdatera så ofta vilket minimera problemet.
Men de vill/kan jag inte göra här.

Jag har ytterligare ett kort som jag har testat och det är samma fel där, så det är inte fel på chippet om det inte är en bugg.
Jag har kollat direkt på utgången på STM32 och det är samma fel där.

Bild

här kan man se att signalen är tyst i en millisekund
Bild

vid dessa tester så uppdaterar jag med samma värden , duty = 50%

Någon som har koll på hur man uppdaterar PWM timer på bästa sätt ?

uppdaterings koden

Kod: Markera allt

void SetMotorPWM(signed int MotorA, signed int MotorB)
{
      TIM_OCInitTypeDef  TIM_OCInitStructure;
    // Normalize values
    if(MotorA < -2000)
    {MotorA = -2000;}
    else if(MotorA > 2000)
    {MotorA = 2000;}
    
    if(MotorB < -2000)
    {MotorB = -2000;}
    else if(MotorB > 2000)
    {MotorB = 2000;}

      /* PWM1 Mode configuration: Motor Channel A */
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_Pulse = (unsigned int)(MotorA + 2000);
      TIM_OC2Init(TIM2, &TIM_OCInitStructure);


    /* PWM1 Mode configuration: Motor Channel B */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_Pulse = (unsigned int)(MotorB + 2000);
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);
}

Init koden som jag använder för TIM2 och kanal 2 & 3

Kod: Markera allt

void MotorPWMInit(void) 
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    unsigned int PrescalerValue;

     // Configure the Motor A PWM output pin
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_PWM_A, ENABLE);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = PWM_A_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(PWM_A_PORT, &GPIO_InitStructure); 


     // Configure the Motor B PWM output pin
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_PWM_B, ENABLE);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = PWM_B_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(PWM_B_PORT, &GPIO_InitStructure); 


    // Timer clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    /* Time Base configuration */
    TIM_TimeBaseStructure.TIM_Period = 4000;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  
    /* PWM1 Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 2000;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
  
    // Motor A channel
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    // Motor B channel 
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); 

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

    /* TIM1 Main Output Enable */
    TIM_CtrlPWMOutputs(TIM2, ENABLE);
}

Re: STM32 PWM problem

Postat: 24 juli 2011, 18:01:54
av Stalker
TIM_OCInitStructure i SetMotorPWM är inte initierad helt utan övriga fält får slumpmässiga värden från stacken. Om man inte sätter alla bör man anropa *StructInit-funktionen (eller vad den heter, har inte dokumentationen framme här). Init-funktionen är dock inte riktigt rätt att använda för att ändra pulsbredd då den (försöker) initiera allt igen. Det finns specifika funktioner för att sätta pulsbredd för de olika CC-kanalerna.

Re: STM32 PWM problem

Postat: 24 juli 2011, 18:14:44
av lizerdboy
Jag misstänkte att det inte var rätt.
Men jag har inte funnit något annat som funkar.

Detta sätt har jag sett flera andra som använder.
Jag har dock inte sett någon specifik funktion för att bara ändra puls bredden.

ST har inget exempel där dom uppdaterar pulsbredden, bara hur man startar den.

ska kolla mer om en stund

Re: STM32 PWM problem

Postat: 24 juli 2011, 18:27:34
av Stalker
Kollade några gamla filer. TIM_SetCompare1 till TIM_SetCompare4 är det de heter.

Re: STM32 PWM problem

Postat: 24 juli 2011, 18:34:58
av SvenW
Tror inte att man ska använda TIM_OC2Init(TIM2, &TIM_OCInitStructure) i den löpande delen utan endast i inintieringskoden.

Man kan i stället använda
TIM_SetCompare2 (TIM2, (uint16_t)(MotorA + 2000)) i den löpande delen.
TIM_OC2Init() gör en massa extra.

För du vill väl inte uppdatera PWM-timern utan bara komparatorregistret (TIM_Pulse)?

Re: STM32 PWM problem

Postat: 24 juli 2011, 19:19:36
av lizerdboy
Aaah Sweet Thanks , det ser ut som det löste sig, har inte sett felet än, kvällen räddad :D

Har dock inte pysslat med PWM biten så mycket.

dock så har jag samma symptom när jag ändrar TIM_Pulse

som här så ändrar jag puls och får en dö tid
Bild

Någon som har någon aning om hur man ändrar TIM_Pulse utan att störa allt för mycket ?

Så här gör jag nu och jag vet att jag gör fel då jag måste nolla räknaren både innan och efter för att det ska funka.

Kod: Markera allt

void MotorPWM_HighFreq(void) 
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    TIM_SetCounter(TIM2, 0);

    /* Time Base configuration */
    TIM_TimeBaseStructure.TIM_Period = 999;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_SetCounter(TIM2, 0);
}

Re: STM32 PWM problem

Postat: 24 juli 2011, 20:05:14
av SvenW
Har du tillgång till dokumentet RM0008 figur 100?

Re: STM32 PWM problem

Postat: 24 juli 2011, 20:11:43
av lizerdboy
Jo då, det är referens manualen.

Är det CNT counter som är puls registret ?? är inte helt säker på detta men det är min gissning ??

finner denna i TIM_TimeBaseInit

/* Set the Autoreload value */
TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;

Ska testa det igen, har för mig att jag redan testat detta. dock utan resultat. kanske måste till något mer kommando för att det ska laddas ordentligt

Re: STM32 PWM problem

Postat: 24 juli 2011, 20:27:55
av SvenW
I den normala enklaste moden räknar CNT upp och ner.
(TIM_CounterMode_CenterAligned1 eller vilken det nu är.)
PWM signalen bildas när compare-register jämförs med CNT.

Man sätter alltså upp CNT vid initiering och sedan får den löpa fritt.
Det enda man sedan ändrar är compare-registret mha t.ex. TIM_SetCompare2().

Jag gör så vid motorstyrning och det är aldrig några problem med luckor eller signalfördröjningar. Då hade motorerna protesterat högljutt.

Här är min initiering, om det kan vara till hjälp:

Kod: Markera allt

void
TIM_Configuration (void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef TIM_OC2InitStructure;

  TIM_TimeBaseStructure.TIM_Period = MY_TIM_PERIOD;     /* ( / 2047.0 24 )  = 85.29 us */
  /* TIM_TimeBaseStructure.TIM_Period = 0x4FF;  *//* ( / ( + 1024.0 256)  24 )  = 53us */
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit (TIM2, &TIM_TimeBaseStructure);

  /* Output Compare Timing Mode configuration: Channel1 */
  TIM_OC2InitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  TIM_OC2InitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OC2InitStructure.TIM_Pulse = 1000;

  TIM_OC2Init (TIM2, &TIM_OC2InitStructure);
  TIM_OC3Init (TIM2, &TIM_OC2InitStructure);
  TIM_OC4Init (TIM2, &TIM_OC2InitStructure);

  TIM_CounterModeConfig (TIM2, TIM_CounterMode_CenterAligned1);

  
  /* 
   * TIM_SelectInputTrigger (TIM2, TIM_TS_ITR0);   /\* se tab 84 sidd 375  i 13902.pdf *\/
   * TIM_SelectSlaveMode (TIM2, TIM_SlaveMode_Trigger);
   * TIM_SelectOnePulseMode (TIM2, TIM_OPMode_Single);
   */
 
  
  TIM_SelectOutputTrigger (TIM2, TIM_TRGOSource_Update);
  TIM_ClearFlag (TIM2, TIM_FLAG_Update);

  /* Enable TIM2 Update interrupt */
   TIM_ITConfig (TIM2, TIM_FLAG_Update, ENABLE);
   
  /* 
   * TIM_SelectOCxM (TIM2,  TIM_Channel_2, TIM_OCMode_PWM1);
   * TIM_GenerateEvent (TIM2, TIM_EventSource_CC2);
   */

  TIM_Cmd (TIM1, ENABLE);
  TIM_Cmd (TIM2, ENABLE);

}



Re: STM32 PWM problem

Postat: 24 juli 2011, 20:36:27
av lizerdboy
Tack Sven.

Testade de jag hittade och det funkade fint.
Dock så var fördröjningen som jag hade i senaste bilden kod struktur fel.
Jag hade satt puls förändring före pulslängds förändringen vilket gjorde att puls var kortare än pulslängd.

bytte plats och vips så försvann det felet med :D
Ooo så här glad har jag inte vart på hela dagen, tackar :D