Skip to main content
Associate II
January 21, 2016
Question

How to generate PWM output using timers on PB0 and PB1

  • January 21, 2016
  • 11 replies
  • 2955 views
Posted on January 21, 2016 at 15:58

Hi all,

I have the stm32F429 micro and I need to generate 2 PWM Output (see below) using pin PB0 and PB1. I tried with toggle mode and TM3 on ch3 and 4, but the duty is 50/50 and is not good. There is a phase shift of 2,4us. Do you have any suggestions?

0690X00000605KoQAI.png

stm32f429

This topic has been closed for replies.

11 replies

waclawek.jan
Super User
January 21, 2016
Posted on January 21, 2016 at 16:39

There is only one counting element in a timer, so you can't produce this using a single timer.

You can chain TIM1 and TIM3, running with the same period (they are on different APB buses so you might need to think about the particular ARR setting for both), triggering one (with the phase difference set in CNT) from the other. Don't forget to set TIM1_BDTR.MOE for TIM1 and don't forget that it's the inverted outputs of TIM1 on PB0/PB1, so you might compensate for this by different timing or setting the other PWM mode or negating by CCER.CCxNP.

Do this step by step - first achieve the two PWMs on two timers, then learn how to chain them/trigger.

JW

marco2Author
Associate II
January 21, 2016
Posted on January 21, 2016 at 19:38

Timer1 output is negated. How can I change the negation, using libraries?

Tesla DeLorean
Guru
January 21, 2016
Posted on January 21, 2016 at 19:45

I think you have to change your model about what's ON vs OFF

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
January 21, 2016
Posted on January 21, 2016 at 20:19

> Timer1 output is negated. How can I change the negation, using libraries?

Well, use those functions of those libraries which allow you to achieve different timing, or to set the other type of PWM, or setting of CCER.CCxNP.

JW

marco2Author
Associate II
January 26, 2016
Posted on January 26, 2016 at 13:18

Below the code I use. The problem is that I have jittering between the two generated PWN waves. Can anyone tell me ho w can I solve this?

void TIM3_IOConfig(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

/* GPIOB Configuration: TIM3 CH3 (PB0) and TIM3 CH4 (PB1) */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

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(GPIOB, &GPIO_InitStructure);

/* Connect TIM3 pins to AF2 */

GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_TIM3);

}

void Delay(__IO uint32_t nTime)

{

TimingDelay = nTime;

while(TimingDelay != 0);

}

void TimingDelay_Decrement(void)

{

if (TimingDelay != 0x00)

{

TimingDelay--;

}

}

void TIM1_Configuration(void)

{

TimerPeriod = (SystemCoreClock / 208000) - 1;

Channel2Pulse = (uint16_t) (((uint32_t) 33 * (TimerPeriod - 1)) / 100);

/* Time Base configuration */

TIM_TimeBaseStructure.TIM_Prescaler = 0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseStructure.TIM_Period = TimerPeriod;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

TIM_OC2Init(TIM1, &TIM_OCInitStructure);

/* Automatic Output enable, Break, dead time and lock configuration*/

TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;

TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;

TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;

TIM_BDTRInitStructure.TIM_DeadTime = 0;

TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;

TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;

TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;

TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

}

void TIM3_Configuration()

{

TimerPeriod /= 2;

Channel3Pulse = (uint16_t) (((uint32_t) 66 * (TimerPeriod - 1)) / 100);

/* Time base configuration */

TIM_TimeBaseStructure.TIM_Prescaler = 0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseStructure.TIM_Period = TimerPeriod;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_Low;

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

TIM_OC4Init(TIM3, &TIM_OCInitStructure);

TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;

TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;

TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;

TIM_BDTRInitStructure.TIM_DeadTime = 0;

TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;

TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;

TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;

TIM_BDTRConfig(TIM3, &TIM_BDTRInitStructure);

}

void TIM1_TIM3_Enable(uint8_t delay_10uc)

{

/* TIM1 counter enable */

TIM_Cmd(TIM1, ENABLE);

TIM_CtrlPWMOutputs(TIM1, ENABLE);

//delay

/* TIM3 counter enable */

TIM_Cmd(TIM3, ENABLE);

TIM_CtrlPWMOutputs(TIM3, ENABLE);

}

void TIM1_TIM3_Disable(uint8_t delay_10uc)

{

/* TIM1 counter enable */

TIM_Cmd(TIM1, DISABLE);

TIM_CtrlPWMOutputs(TIM1, DISABLE);

//delay

/* TIM3 counter enable */

TIM_Cmd(TIM3, DISABLE);

TIM_CtrlPWMOutputs(TIM3, DISABLE);

}

void TIM1_IOConfig(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/*GPIOB clocks enable */

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

/* TIM1 clock enable */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

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_NOPULL;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM1);

}

int main(void)

{

STM_EVAL_LEDInit(LED3);

STM_EVAL_LEDOn(LED3);

STM_EVAL_LEDOff(LED3);

TIM1_IOConfig();

TIM3_IOConfig();

TIM1_Configuration();

TIM3_Configuration();

TIM1_TIM3_Enable(0);

if (SysTick_Config(SystemCoreClock / 1000))

{

/* Capture error */

while (1);

}

/* Infinite loop */

while (1)

{

STM_EVAL_LEDToggle(LED3);

Delay(500);

}

}

Walid FTITI_O
Visitor II
February 1, 2016
Posted on February 01, 2016 at 16:06

Hi stevasway,

Try to do this by generating two complementary signals with a dead time inserted.

To get more information about this topic, read the relevant section in the reference manual; TIM1/TIM8 chapter. And check the example in standard library '' TIM_ComplementarySignals '' following this path : Project\STM32F4xx_StdPeriph_Examples\TIM\TIM_ComplementarySignals

-Hannibal-
marco2Author
Associate II
February 3, 2016
Posted on February 03, 2016 at 18:33

Thanks I'll try.

waclawek.jan
Super User
February 3, 2016
Posted on February 03, 2016 at 19:58

> Subject: How to generate PWM output using timers on PB0 and PB1

> Try to do this by generating two complementary signals with a dead time inserted.

How? There is no complementary-timer-channel-pin-pair on PB0 and PB1.

JW

gregstm
Senior II
February 4, 2016
Posted on February 04, 2016 at 03:26

A possible alternative..... use 32 bit DMA to the GPIOB BSRR register (in circular mode) to send the required bit pattern (set up in an array beforehand).

marco2Author
Associate II
February 5, 2016
Posted on February 05, 2016 at 09:56

Thanks to all for your precious suggestions. Below the code to generate PWM as the picture posted above. Little trick on TIM1_PWMOut_Disable (maybe yet a little settings problem??)

#define CMD_SIGNAL_HZ    208000  //200..210 kHz

void TIM1_IOConfig(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

                         

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

  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_NOPULL;

   

  GPIO_Init(GPIOB, &GPIO_InitStructure);

    

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM1);

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_TIM1);

}

void TIM1_Configuration(void)

{

uint16_t TimerPeriod = 0;

  TIM_DeInit(TIM1);

 

  TimerPeriod = ((SystemCoreClock / 2) / CMD_SIGNAL_HZ) - 1;

  /* Time Base configuration */

  TIM_TimeBaseStructure.TIM_Prescaler = 0;

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned2;

  TIM_TimeBaseStructure.TIM_Period = TimerPeriod;

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;

  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  /* Channel 3 Configuration in PWM mode */

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

  TIM_OCInitStructure.TIM_Pulse = (uint16_t) (((uint32_t) 66 * (TimerPeriod - 1)) / 100);

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;

  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

  TIM_OC3Init(TIM1, &TIM_OCInitStructure);

  /* Channel 2 Configuration in PWM mode */

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

  TIM_OCInitStructure.TIM_Pulse = (uint16_t) (((uint32_t) 33 * (TimerPeriod - 1)) / 100);

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

  TIM_OC2Init(TIM1, &TIM_OCInitStructure);

 

  /* Automatic Output enable, Break, dead time and lock configuration*/

  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;

  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;

  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;

  TIM_BDTRInitStructure.TIM_DeadTime = 0;

  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;

  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;

  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;

  TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

}

void TIM1_PWMOut_Enable(void)

{

  TIM_Cmd(TIM1, ENABLE);

  TIM_CtrlPWMOutputs(TIM1, ENABLE);

}

void TIM1_PWMOut_Disable(void)

{

  TIM_Cmd(TIM1, DISABLE);

  TIM_OC3Init(TIM1, &TIM_OCInitStructure); //trick!!

  TIM_DeInit(TIM1);

}