8000 esp32: PWM duty will be changed when changing the frequency if more than one channel is used. · Issue #8345 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

esp32: PWM duty will be changed when changing the frequency if more than one channel is used. #8345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Dreagonmon opened this issue Feb 23, 2022 · 12 comments

Comments

@Dreagonmon
Copy link

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.

from machine import PWM, Pin
pwm = PWM(Pin(5)) # also tested with Pin(2)
pwm.duty(512)
pwm.freq(611) # it works, digital multimeters shows freq 1222Hz
pwm.freq(610) # no pwm output, digital multimeters says freq is 0

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.

@xky183
Copy link
xky183 commented Feb 26, 2022

meet same problem by v1.18,work fine by v1.17

@robert-hh
Copy link
Contributor

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.

@xky183
Copy link
xky183 commented Feb 26, 2022

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)
>>> 

@Dreagonmon
Copy link
Author

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.

@robert-hh
Copy link
Contributor

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.

@robert-hh
Copy link
Contributor

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'
>>> 

@xky183
Copy link
xky183 commented Feb 27, 2022

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'
>>> 
>>> 
>>> `


@xky183
Copy link
xky183 commented Feb 27, 2022

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

@robert-hh
Copy link
Contributor

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.

@Dreagonmon
Copy link
Author

could you reopen this issue? thanks

sure

@Dreagonmon Dreagonmon reopened this Feb 27, 2022
@Dreagonmon Dreagonmon 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. Feb 27, 2022
@robert-hh
Copy link
Contributor
robert-hh commented 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)
>>> 

dpgeorge pushed a commit that referenced this issue Mar 7, 2022
If setting the frequency to a value used already by an existing timer, this
timer will be used.  But still, the duty cycle for that channel may have to
be changed.

Fixes issues #8306 and #8345.
@dpgeorge
Copy link
Member
dpgeorge commented Mar 7, 2022

Fixed by 55a0125

@dpgeorge dpgeorge closed this as completed Mar 7, 2022
Wind-stormger pushed a commit to BPI-STEAM/micropython that referenced this issue Sep 14, 2023
Forbidden pins are now correctly "in use" on ESP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants
0