I need to generate two opposite PWM signals (when one is high the other one is low) using timers in STM32. I have read several examples and this is the code I came up with:
void TM_PINS_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* Alternating functions for pins */
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);
/* Set pins */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
}
void TM_TIMER_Init(void) {
TIM_TimeBaseInitTypeDef TIM_BaseStruct;
/* Enable clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
uint16_t Period;
Period = 1000000 / 200000; // 200 KHz from 1MHz
TIM_BaseStruct.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1MHz
TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_BaseStruct.TIM_Period = Period - 1;
TIM_BaseStruct.TIM_ClockDivision = 0;
TIM_BaseStruct.TIM_RepetitionCounter = 0;
/* Initialize TIM4 */
TIM_TimeBaseInit(TIM4, &TIM_BaseStruct);
/* Start count on TIM4 */
TIM_Cmd(TIM4, ENABLE);
}
void TM_PWM_Init(void) {
TIM_OCInitTypeDef TIM_OCStruct;
/* PWM mode 2 = Clear on compare match */
/* PWM mode 1 = Set on compare match */
TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OC1Init(TIM4, &TIM_OCStruct);
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OC2Init(TIM4, &TIM_OCStruct);
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCStruct.TIM_Pulse = Period/2; /* 50% duty cycle */
}
I have several questions:
Since I need frequencies in terms of tens of kHz, do I need 100MHz setting for the GPIO speed? Is there any benefit to make it slower?
Would my PWM function generate what I need? I think the opposite PWM signals are actually achieved using PWM modes 1 and 2, but I am afraid I may be missing something there.
I want to be able to stop the timers, and to set high/low state to the same pins. Would the following code work?
GPIOD-> MODER |= (5 << 24); //set pin 12 and 13 to GPIO, 5 gives us 101, shifted 23 bits so that '1's are in pos. 24 and 26
GPIOD->regs->BSRR = (3<<12); // 3 gives us 11 pattern, shifted 12 bits so that pins 12 and 13 are set to high
GPIOD-> MODER |= (5 << 24); //set pin 12 and 13 to AF, 5 gives us 101, shifted 24 bits so that '1's are in pos. 25 and 27
When the AF is restored, are the previous pwm settings restored or must be set again.
Would it be better to use MODER as above to change pins to GPIO and then set to high/low, or I can use 100% duty cycle for high and 0% duty cycle for low?