2011-07-24 08:03 AM
Has now been running myself crazy here today when I took on the next problem.
Have long known that there are small errors in the PWM signal that is off.
And after my solution that I post earlier, this has been more than before, probably anyway.
The thing is that I update the PWM duty cycle each ms, and sometimes it does not seem that the PWM signal is working after the update.
the PWM signal is lost untill the next update.
the error is not regular, it come and go.
I have been looking for how to update the PWM channels on the STM32 MCU, which I'm working towards.
Have seen this problem before on other designs that I've driven Buzzers via PWM, then I solved it by not updating as often to minimize the problem.
But this is not a solution in this case.
I have another card that I have tested the same code on and it is the same error there, so it's not wrong on the chip if it is not a bug.
I've looked directly at the output pin of the STM32 and the same error there.
Here can you seen that the signal is quiet in for a millisecond
it is updating the PWM channels with the same value every time duty = 50% Someone that knows how to update the PWM timer in the best way?update code
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 code that I use for TIM2 and channel 2 & 3
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); }2011-07-26 12:07 PM
You need to be aware that Period is programmed to N-1
TIM_TimeBaseStructure.TIM_Period = 4000 - 1; Programming pulse to 0 results in always OFF, to N results in always ON. To merely update the PWM you should consider just writing the registers directly TIM2->CCR2 = (unsigned int)(MotorA + 2000); TIM2->CCR3 = (unsigned int)(MotorB + 2000); If you use the library function, you need to fully initialize the data structure, so it isn't full of random junk left on the stack. Will having TIM_OutputState, or TIM_OCPolarity, being an odd value impact your settings? I'd wager it will. You should also enable the APB clock to GPIOA before configuring it.