Repository navigation
esp32: PWM duty will be changed when changing the frequency if more than one channel is used. #8345
Description
Activity
meet same problem by v1.18,work fine by v1.17
Fixed since a while. Please use a recent nightly build, and ignore the "unstable" label. The nightly builds are tested the same way than the release build.
Fixed since a while. Please use a recent nightly build, and ignore the "unstable" label. The nightly builds are tested the same way than the release build.
Thank you very much,I just tested the version "esp32-20220226-unstable-v1.18-160-g0a217624e.bin", it can work in 1Hz now, but... the duty will be changed when changing the freq.
>>> >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=1024, resolution=15, (duty=100.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.duty(512) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=20000, duty=8192, resolution=11, (duty=800.00%, resolution=0.049%), mode=0, channel=0, timer=1) >>> pwm0.duty(512) >>> pwm0.freq(20000) >>> pwm0 PWM(Pin(0), freq=20000, duty=512, resolution=11, (duty=50.00%, resolution=0.049%), mode=0, channel=0, timer=1) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=32, resolution=15, (duty=3.13%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.duty(512) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=256, resolution=16, (duty=25.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.duty(512) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(20) >>> pwm0 PWM(Pin(0), freq=20, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(2) >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>>maybe #8306 is the related issue.
I created this issue and closed it soon when I realized that this is fixed in the nightly build. but it seems not really fixed.
No. It is not. That is something which show up only once after hard reset. I just tested you sequence with my own builds, and it works fine. I just downloaded the nightly build and verify, which esp-idf and version is used.
I cannot verify your findings. Everything looks as intended. Both the reporting in the print and the actual signal are fine.
MicroPython v1.18 on 2022-02-26; ESP32 module (spiram) with ESP32 Type "help()" for more information. >>> p0=PWM(Pin(0), 2, duty=512) >>> p0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> p0.freq(200) >>> p0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> p0.freq(2000) >>> p0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=0) >>> p0.freq(20000) >>> p0 PWM(Pin(0), freq=20000, duty=512, resolution=11, (duty=50.00%, resolution=0.049%), mode=0, channel=0, timer=0) >>> p0.freq(2000) >>> p0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=0) >>> p0.freq(200) >>> p0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> p0.freq(2) >>> p0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> import platform >>> platform.platform() 'MicroPython-1.18.0-xtensa-IDFv4.2.2-with-newlib3.0.0' >>>I test twice,
at the first time,only use one PWM0 channel,it works well。
at the second time,use PWM0,PWM2,PWM4 channel,it seems timers for each pwm channel will be changed when changing the freq, and it will cause the changing of duty , maybe the problem is the counter of the timer is not set right value,`>>> >>> from machine import PWM >>> pwm0 = PWM(Pin(0), freq=2, duty=512) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'Pin' isn't defined >>> from machine import Pin >>> pwm0 = PWM(Pin(0), freq=2, duty=512) >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(20) >>> pwm0 PWM(Pin(0), freq=20, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=0) >>> pwm0.freq(20000) >>> pwm0 PWM(Pin(0), freq=20000, duty=512, resolution=11, (duty=50.00%, resolution=0.049%), mode=0, channel=0, timer=0) >>> pwm0.freq(200000) >>> pwm0 PWM(Pin(0), freq=200000, duty=512, resolution=8, (duty=50.00%, resolution=0.391%), mode=0, channel=0, timer=0) >>> pwm0.freq(20000) >>> pwm0 PWM(Pin(0), freq=20000, duty=512, resolution=11, (duty=50.00%, resolution=0.049%), mode=0, channel=0, timer=0) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=0) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(20) >>> pwm0 PWM(Pin(0), freq=20, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(2) >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 load:0x3fff0030,len:4540 ho 0 tail 12 room 4 load:0x40078000,len:12344 ho 0 tail 12 room 4 load:0x40080400,len:4124 entry 0x40080680 MicroPython v1.18 on 2022-02-26; ESP32 module with ESP32 Type "help()" for more information. >>> from machine import Pin >>> from machine import PWM >>> pwm0 = PWM(Pin(0), freq=2, duty=512) >>> pwm2 = PWM(Pin(2), freq=200, duty=512) >>> pwm4 = PWM(Pin(4), freq=2000, duty=512) >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(20) >>> pwm0 PWM(Pin(0), freq=20, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=1) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=1024, resolution=15, (duty=100.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.duty(512) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.freq(20000) >>> pwm0 PWM(Pin(0), freq=20000, duty=512, resolution=11, (duty=50.00%, resolution=0.049%), mode=0, channel=0, timer=0) >>> pwm0.freq(200000) >>> pwm0 PWM(Pin(0), freq=200000, duty=512, resolution=8, (duty=50.00%, resolution=0.391%), mode=0, channel=0, timer=0) >>> pwm0.freq(20000) >>> pwm0 PWM(Pin(0), freq=20000, duty=512, resolution=11, (duty=50.00%, resolution=0.049%), mode=0, channel=0, timer=0) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=32, resolution=15, (duty=3.13%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.duty(512) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=256, resolution=16, (duty=25.00%, resolution=0.002%), mode=0, channel=0, timer=1) >>> pwm0.duty(512) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=1) >>> pwm0.freq(20) >>> pwm0 PWM(Pin(0), freq=20, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> pwm0.freq(2) >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=16, (duty=50.00%, resolution=0.002%), mode=0, channel=0, timer=0) >>> import platform >>> platform.platform() 'MicroPython-1.18.0-xtensa-IDFv4.2.2-with-newlib3.0.0' >>> >>> >>> `maybe #8306 is the related issue.
I created this issue and closed it soon when I realized that this is fixed in the nightly build. but it seems not really fixed.
could you reopen this issue? thanks
You are right. If more than one channel is used, there will be issues with the duty cycle. The basic PR which changed that behavior is #7817. The PR message explains the function and one can see the root of the problem, which is also visible in your log. If a channel's frequency is set to a frequency used by the other channel, it uses this channels timer. That does not take care of potentially different duty cycles.
Dropping the timer re-use mechanism makes the PWM work as intended. However, it is then again limited to 8 channels.could you reopen this issue? thanks
sure
- changed the title
[-]esp32: PWM has no output when frequencies < 611Hz.[/-][+]esp32: PWM duty will be changed when changing the frequency if more than one channel is used.[/+]on Feb 27, 2022 So I made a small change to the code which forces the duty rate to be set on frequency changes. That was omitted when setting to a frequency which was already used in a different channel. The timer for that channel was reused, but still the duty rate had to be adapted. The change is based on a different PR I made earlier, and by chance it fixes #8306 as well. Output from going though the same series as @xky183 above:
MicroPython v1.18-160-g0a217624e-dirty on 2022-02-27; ESP32 module (spiram) with ESP32 Type "help()" for more information. >>> import platform >>> platform.platform() 'MicroPython-1.18.0-xtensa-IDFv4.2.2-dirty-with-newlib3.0.0' >>> pwm0 = PWM(Pin(0), freq=2, duty=512) >>> pwm2 = PWM(Pin(22), freq=200, duty=512) >>> pwm4 = PWM(Pin(4), freq=2000, duty=512) >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=18, (duty=50.00%, resolution=0.000%), mode=0, channel=0, timer=0) >>> pwm0.freq(20) >>> pwm0 PWM(Pin(0), freq=20, duty=512, resolution=20, (duty=50.00%, resolution=0.000%), mode=0, channel=0, timer=0) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=18, (duty=50.00%, resolution=0.000%), mode=0, channel=0, timer=1) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.freq(20000) >>> pwm0 PWM(Pin(0), freq=20000, duty=512, resolution=11, (duty=50.00%, resolution=0.049%), mode=0, channel=0, timer=0) >>> pwm0.freq(2000) >>> pwm0 PWM(Pin(0), freq=2003, duty=512, resolution=15, (duty=50.00%, resolution=0.003%), mode=0, channel=0, timer=2) >>> pwm0.freq(200) >>> pwm0 PWM(Pin(0), freq=200, duty=512, resolution=18, (duty=50.00%, resolution=0.000%), mode=0, channel=0, timer=1) >>> pwm0.freq(20) >>> pwm0 PWM(Pin(0), freq=20, duty=512, resolution=20, (duty=50.00%, resolution=0.000%), mode=0, channel=0, timer=0) >>> pwm0.freq(2) >>> pwm0 PWM(Pin(0), freq=2, duty=512, resolution=18, (duty=50.00%, resolution=0.000%), mode=0, channel=0, timer=0) >>>- added a commit that references this issue
on Mar 7, 2022 Fixed by 55a0125
- added a commit that references this issue
on May 23, 2026 - added a commit that references this issue
on Sep 21, 2026
After upgrading mpy from 1.17 to 1.18, my buzzer can't play low frequency sounds any more.
With further test, it shows that the pwm has no output when frequencies < 611Hz.
And after switching back to mpy 1.17,
pwm.freq(610)works fine. I'v tested with another board and I still got the same result. I'm sure this is an issue introduced by v1.18.