cancel
Showing results for 
Search instead for 
Did you mean: 

PWM Interrupts (help me!)

jlamb
Associate II
Posted on January 31, 2013 at 14:11

Hi

I am a power electronics engineer and I have been using the STM32F4 to develop AC motor drives and its great

I am now working on an application with space vector modulation and I have ran into a difficulty which I would love some advice on

For previous programs I could use an interrupt to update a count for timing applications and it was pretty straight forward

For my new program I need three PWM outputs center aligned which I can generate quite easily I can update the frequency and duty cycle but what I need to do is generate an interrupt on the carrier apex and I just don't know if I am barking up the right tree?

I can upload some code when I get in tonight but can anyone advise me if its feasable to use CCR1, CCR2 and CCR3 as the duty cycles of the different PWM outputs so I have three outputs from one timer and what I think would be great is if I could set CCR4 to the same value as the ARR register so that when the CNT is equal to CCR4 I know its the peak of the carrier but I just don't know how to generate an interrupt based on a CCR4 value is this possible? or is there another way to generate an interrupt on the carrier apex? all I can see changing in the registers is the DIR bit

I have been trying for about four days now and I have the manuals etc but I just cant see any useful info in there (it makes terrible reading IMO)

The other option would be to sync two timers together and use a separate timer to generate an interrupt but that seems like it shouldnt be needed?

Any help/advice is most welcome

#center-aligned-pwm
6 REPLIES 6
Posted on January 31, 2013 at 14:19

I could set CCR4 to the same value as the ARR register so that when the CNT is equal to CCR4 I know its the peak of the carrier but I just don't know how to generate an interrupt based on a CCR4 value is this possible?

Like TIM_IT_CC4? but wouldn't that just do what TIM_IT_Update does now?
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
jlamb
Associate II
Posted on January 31, 2013 at 15:45

Thanks for the reply Clive, I was hoping that you would drop in and advise

I will post up my code when I get in tonight however I initially tried to setup a global interrupt on the timer which worked perfectly for another program that didn't use PWM

But my interrupt doesn't fire now I configure the timer in PWM mode and I did briefly try the Timer_IT_CC4 this morning but that didnt work either I was thinking that because its center aligned mode the ARR doesn't refresh so the interrupt doesnt fire like I say all I can see changing is the DIR bit

My programming isn't the best so I know its my fault I just need to fire an interrupt when the CNT = the ARR which is the peak of the carrier

Many thanks

jlamb
Associate II
Posted on February 02, 2013 at 20:36

I managed to get the interrupt firing with PWM on the same timer

I need to use center aligned PWM but my problem now is that the interrupt fires on over flow and underflow where as I need it to fire only once per PWM period = 50us

Heres my code

/* Includes ------------------------------------------------------------------*/

#include ''stm32f4_discovery.h''

#include <stdio.h>

int n=0;

GPIO_InitTypeDef  GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_OCInitTypeDef  TIM_OCInitStructure;

void TIM4_IRQHandler(void)

{

  if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)

  {

    GPIO_ToggleBits(GPIOB, GPIO_Pin_11);

    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);

  }

}

/* Private function prototypes -----------------------------------------------*/

void TIM_Config(void);

void PWM_Config(void);

void PWM_SetDC(uint16_t dutycycle);

void Delay(__IO uint32_t nCount);

void GPIO_Config(void);

/* Private functions ---------------------------------------------------------*/

int main(void)

{

  uint16_t pulse_width = 0;

  GPIO_Config();

  TIM_Config();

  PWM_Config();

  GPIO_ResetBits(GPIOB, GPIO_Pin_11| GPIO_Pin_13| GPIO_Pin_15);

  while (1)

  {

   

    PWM_SetDC(pulse_width++);

    if (pulse_width >= 699)

    {

      pulse_width = 0;

    }

    Delay(100000);

  }

}

void GPIO_Config(void)

{    /* GPIOD clock enable */

      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    /* GPIOD For PWM Configuration:  TIM4 CH1 (PD12), TIM4 CH2 (PD13), TIM3 CH3 (PD14), TIM3 CH4 (PD15) */

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;

      GPIO_Init(GPIOD, &GPIO_InitStructure);

      /* Connect TIM3 pins to AF2 */

      GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM3);

      GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM3);

      GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM3);

      GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM3);

  /* GPIOB Periph clock enable */

      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

  /* Configure  PB11, PB13 and PB15 in output pushpull mode */

      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_13| GPIO_Pin_15;

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

      GPIO_Init(GPIOB, &GPIO_InitStructure);

}

void TIM_Config(void)

{

      NVIC_InitTypeDef NVIC_InitStructure;

      NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

     /* TIM4 clock enable */

      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

   /* Time base configuration */

      TIM_TimeBaseStructure.TIM_Period = 700;

      TIM_TimeBaseStructure.TIM_Prescaler = 2;

      TIM_TimeBaseStructure.TIM_ClockDivision = 0;

      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned3;

      TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

   /* TIM IT enable */

      TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

   /* TIM2 enable counter */

      TIM_Cmd(TIM4, ENABLE);

}

void PWM_Config(void)

{

  /* PWM1 Mode configuration: */

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = 0;

  /* PWM2 Mode TIM4 CH1 = PD 12 */

  TIM_OC1Init(TIM4, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);

  /* PWM2 Mode TIM4 CH2 = PD 13 */

  TIM_OC2Init(TIM4, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);

  /* PWM2 Mode TIM4 CH3 = PD 14 */

  TIM_OC3Init(TIM4, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);

  /* PWM2 Mode TIM4 CH4 = PD 15 */

  TIM_OC4Init(TIM4, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM4, ENABLE);

  /* TIM4 enable counter */

  TIM_Cmd(TIM4, ENABLE);

}

void PWM_SetDC(uint16_t dutycycle)

{

    TIM4->CCR1 = dutycycle;

    TIM4->CCR2 = dutycycle;

    TIM4->CCR3 = dutycycle;

    TIM4->CCR4 = dutycycle;

}

void Delay(__IO uint32_t nCount)

{

  while(nCount--)

  {

  }

}

If anyone can tell me a way to only interrupt when the CNT=ARR that would be great

I could use CC4 interrupt and set CCR4 to ARR but is there a better way?

Thanks in advance

jlamb
Associate II
Posted on February 02, 2013 at 20:39

A separate question I have is regarding PWM polarity

I can use PWM1 or PWM2 to swap polarity but I can also use TIM_OCPolarity to swap the polarity so is there any difference between the two?

What method should I be using to change the polarity? and what is the purpose of two different ways

Thanks

jlamb
Associate II
Posted on February 03, 2013 at 13:30

Anyone got any ideas?

jlamb
Associate II
Posted on February 10, 2013 at 14:58

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6mV&d=%2Fa%2F0X0000000bvI%2FH7Ssdbl77KwTPhlXA8vZjPzndZ.fOiD7syOOY6ScAHg&asPdf=false