I am playing a tune on a speaker on an STM32G0B1 using PWM, however, sometimes after playing a tune the speaker continues to be driven despite Stop
being called and the "idle state" being set to "Reset":
Idle state is set to "Reset" in Cube MX:
Cube MX screenshot showing CH Idle State set to Reset
When stopped the channel is driven High:
Scope Trace Showing Set at Idle
Code used to stop the PWM:
int bzStop(void)
{
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);
return 0;
}
Any ideas what I'm doing wrong here?
Thanks
-
\$\begingroup\$ Is the speaker directly connected? Or is a (say 10µF) AC coupling capacitor used? If the latter, "stopping high" shouldn't be an issue. \$\endgroup\$rdtsc– rdtsc2022年03月10日 12:52:52 +00:00Commented Mar 10, 2022 at 12:52
-
\$\begingroup\$ @rdtsc There isn't an AC coupling capacitor -- I'll put that in the next revision. \$\endgroup\$Harry Beadle– Harry Beadle2022年03月10日 13:05:28 +00:00Commented Mar 10, 2022 at 13:05
-
\$\begingroup\$ Is the "other side" of speaker connected to the same PWM, but with inverted levels? If so, does that "other side" idle high or low at the end? \$\endgroup\$brhans– brhans2022年03月10日 14:09:00 +00:00Commented Mar 10, 2022 at 14:09
3 Answers 3
I offer not a full solution or explanation, but a bandaid, having ran into the same.
When stopping the PWM (For example, in an appropriate interrupt handler), set the GPIO mode to output, and set it to the idle state you wish. When starting again, set its mode back to alternate.
I think what should you do is leave the timer channel running, e.g. not call
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);
which in turn calls TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_DISABLE);
and stops the channel completely. What worked for me was setting the output always low by setting appropriate bits in the OC1M
field in the CCMR1
register. Something like
htim4.Instance->CCMR1 = (TIM_CCMR1_OC1M_2);
which effectively sets the channel to mode always low. If you want to, you can stop the counter using __HAL_TIM_DISABLE()
macro. Don't forget to start it again when you resume operation. When you want to resume the PWM, revert the bits to your wanted values accordingly.
I think that the Idle state setting applies only when you first start the channel and it is running.
Other thing to note is that output compare channel remembers its state even after completely resetting the peripheral.
CH Idle State "reset" means the output pin will be pull high while stoped generate PWM, change it to "set" will solve your issue