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?


  • \$\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
    Mar 10, 2022 at 12:52
  • \$\begingroup\$ @rdtsc There isn't an AC coupling capacitor -- I'll put that in the next revision. \$\endgroup\$ 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
    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


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.