PWM sync on STM32

I will not particularly go into the theory, there are many resources in the network where everything is described in great detail. But when it comes to practice, you understand that everything is much more complicated. Used microcontroller stm32l152c-discovery. The article will describe the process of starting the PWM of two timers at the same time (full synchronization):

image

As well as the launch with a lag (in the photo the lag in the floor of the period)

image

Create a function for initPWM initialization, declare variables for convenience

void initPWM() { const uint32_t Period = 20 - 1;//  const uint32_t prescaler = 1 - 1;// //-1      0 const uint32_t pulse = 15;//  } 

First you need to initialize the structures to configure the timers:

  GPIO_InitTypeDef port; TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef timerPWM; 

Next, we activate the necessary peripherals. We will use TIM3 and TIM4, simply because it wanted to:

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 

GPIOB activate, because Timer outputs sit on this PB5 and PB9 bus. This information can be found in the user manual for the microcontroller in the table MCU pin description versus board function.

image

We configure the outputs in the alternative function mode:

  GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF;//  ,    port.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_9; port.GPIO_Speed = GPIO_Speed_2MHz;//  2 port.GPIO_OType = GPIO_OType_PP;//  "push-pull" " " GPIO_Init(GPIOB, &port); //    PB5 GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3); //    PB9 GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_TIM4); 

Configuring the timer in the PWM mode:

  TIM_TimeBaseStructInit(&timer); timer.TIM_ClockDivision = TIM_CKD_DIV1; timer.TIM_CounterMode = TIM_CounterMode_Up;//  timer.TIM_Prescaler = prescaler;// timer.TIM_Period = Period;// TIM_TimeBaseInit(TIM4, &timer);//     TIM_TimeBaseInit(TIM3, &timer); TIM_OCStructInit(&timerPWM); timerPWM.TIM_Pulse = pulse;//  timerPWM.TIM_OCMode = TIM_OCMode_PWM1;//   timerPWM.TIM_OutputState = TIM_OutputState_Enable;//  timerPWM.TIM_OCPolarity = TIM_OCPolarity_High;//  3.3 

We initialize the necessary channels for timers, we look for channels in the user manual:

  TIM_OC2Init(TIM3, &timerPWM); TIM_OC4Init(TIM4, &timerPWM); 

And now the most important is the synchronization setting. It is necessary to make one timer master, another slave:

 //  TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_Enable);//  TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);//  TIM_SelectInputTrigger(TIM3, TIM_TS_ITR3);// , //  TIM4  4,    ,  TIM_TS_ITR3 TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated);//  

If we need to make a backlog, let's say for the half of the period, then we need to set the initial value of the sub-timer count equal to half the period. For full synchronization, we start the account from 0:

  TIM_SetCounter(TIM3, 10);// 20,       10 //    5,     15 

Activate the timers:

  TIM_Cmd(TIM3, ENABLE);//   TIM_Cmd(TIM4, ENABLE);//    

I post the whole code in full:

 #include "stm32l1xx.h" //  const uint32_t Period = 20 - 1;//  const uint32_t prescaler = 1 - 1; const uint32_t pulse = 15; void initPWM() { GPIO_InitTypeDef port; TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef timerPWM; //  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //   PB5, PB9 GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF; port.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_9; port.GPIO_Speed = GPIO_Speed_2MHz; port.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOB, &port); //    PB5 GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3); //    PB9 GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_TIM4); //  TIM_TimeBaseStructInit(&timer); timer.TIM_ClockDivision = TIM_CKD_DIV1; timer.TIM_CounterMode = TIM_CounterMode_Up; timer.TIM_Prescaler = prescaler; timer.TIM_Period = Period; TIM_TimeBaseInit(TIM4, &timer); TIM_TimeBaseInit(TIM3, &timer); TIM_OCStructInit(&timerPWM); timerPWM.TIM_Pulse = pulse; timerPWM.TIM_OCMode = TIM_OCMode_PWM1; timerPWM.TIM_OutputState = TIM_OutputState_Enable; timerPWM.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &timerPWM); TIM_OC4Init(TIM4, &timerPWM); //  TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_Enable);//  TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable); TIM_SelectInputTrigger(TIM3, TIM_TS_ITR3);//  TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated); TIM_SetCounter(TIM3, 10); // TIM_Cmd(TIM4, ENABLE); TIM_Cmd(TIM3, ENABLE); TIM_Cmd(TIM4, ENABLE); } int main() { initPWM(); while(1) { } } 

That's all. In my task, it was necessary to control two stepper motors. Additionally, the code for smooth overclocking was written, it began work with a longer period and gradually reduced it with the TIM_SetAutoreload function.

Source: https://habr.com/ru/post/415523/


All Articles