← index #5737PR #6654
Related · medium · value 1.239
QUERY · ISSUE

ESP32 Confusing behaviour of PWM after soft reset

openby peterhinchopened 2020-03-08updated 2023-09-17
port-esp32

Consider:

from machine import Pin, PWM
pin = Pin(23, Pin.OUT)
pwm = PWM(pin, freq=38000, duty=338)

This works as expected. If you issue ctrl-d the waveform on the pin continues unchanged. If you paste the above code again, you cause a low output with

pwm.duty(0)

Subsequently changing the duty value to a value > 0 has no effect. This is surprising.

There is a simple workround of issuing pwm.deinit() at the start. The current state could be confusing to newcomers. It should either be documented or changed so that a soft reset de-initialises any PWM instance.

CANDIDATE · PULL REQUEST

esp32/machine_pwm.c: Handle multiple timers: Bugfix PWM.deinit() critical error and fix pwm_print()

closedby IhorNehrutsaopened 2020-11-27updated 2021-09-21
port-esp32

This PR is inherited from esp32/machine_pwm: handle multiple timers. #6276 and replace it.
This PR uses PR ESP32: New feature: EspError exception #6638
This PR was tested together with PR ESP32: New features PCNT() and QUAD() #6639
It is tested with 4 different frequencies at 8 different channels with different duties.
Frequencies and duties are right on proper pins.

from machine import Pin, PWM
import pcnt

P1 = 15
P2 = 2
P3 = 0
P4 = 4
P5 = 18
P6 = 21
P7 = 22
P8 = 23

C1 = 14
C2 = 27
C3 = 26
C4 = 25
C5 = 33
C6 = 32
C7 = 35
C8 = 34

DIR1 = 5

f = 1 # 1..4
d = int(1024 / 9)

cnt1 = None
cnt2 = None
cnt3 = None
cnt4 = None
cnt5 = None
cnt6 = None
cnt7 = None
cnt8 = None

pwm1 = None
pwm2 = None
pwm3 = None
pwm4 = None
pwm5 = None
pwm6 = None
pwm7 = None
pwm8 = None

def prnt():
    global cnt1, cnt2, cnt3, cnt4, cnt5, cnt6, cnt7, cnt8
    global pwm1, pwm2, pwm3, pwm4, pwm5, pwm6, pwm7, pwm8
    cnt1.filter_disable()
    cnt2.filter_disable()
    cnt3.filter_disable()
    cnt4.filter_disable()
    cnt5.filter_disable()
    cnt6.filter_disable()
    cnt7.filter_disable()
    cnt8.filter_disable()

    print(pwm1)
    print(pwm2)
    print(pwm3)
    print(pwm4)
    print(pwm5)
    print(pwm6)
    print(pwm7)
    print(pwm8)

    print(cnt1)
    print(cnt2)
    print(cnt3)
    print(cnt4)
    print(cnt5)
    print(cnt6)
    print(cnt7)
    print(cnt8)

def init1():
    global cnt1, cnt2, cnt3, cnt4, cnt5, cnt6, cnt7, cnt8
    global pwm1, pwm2, pwm3, pwm4, pwm5, pwm6, pwm7, pwm8
    pwm1 = PWM(Pin(P1), freq=f*1, duty=d*1)  # 1024-1 == 100% # 512-1 == 50%
    pwm2 = PWM(Pin(P2), freq=f*1, duty=d*2)  
    pwm3 = PWM(Pin(P3), freq=f*100, duty=d*3)  
    pwm4 = PWM(Pin(P4), freq=f*100, duty=d*4-10)  
    pwm5 = PWM(Pin(P5), freq=f*100000, duty=d*5)  
    pwm6 = PWM(Pin(P6), freq=f*100000, duty=d*6)  
    pwm7 = PWM(Pin(P7), freq=f*10000000, duty=1000)#512)
    pwm8 = PWM(Pin(P8), freq=f*10000000, duty=256)#512)

    cnt1 = pcnt.PCNT(pcnt.Edge.FALL, C1, DIR1, pcnt.PinPull.UP)
    cnt2 = pcnt.PCNT(pcnt.Edge.FALL, C2, DIR1, pcnt.PinPull.UP)
    cnt3 = pcnt.PCNT(pcnt.Edge.FALL, C3, DIR1, pcnt.PinPull.UP)
    cnt4 = pcnt.PCNT(pcnt.Edge.FALL, C4, DIR1, pcnt.PinPull.UP)
    cnt5 = pcnt.PCNT(pcnt.Edge.FALL, C5, DIR1, pcnt.PinPull.UP)
    cnt6 = pcnt.PCNT(pcnt.Edge.FALL, C6, DIR1, pcnt.PinPull.UP)
    cnt7 = pcnt.PCNT(pcnt.Edge.FALL, C7, DIR1, pcnt.PinPull.UP)
    cnt8 = pcnt.PCNT(pcnt.Edge.FALL, C8, DIR1, pcnt.PinPull.UP)
    prnt()

def init2():
    global cnt1, cnt2, cnt3, cnt4, cnt5, cnt6, cnt7, cnt8
    global pwm1, pwm2, pwm3, pwm4, pwm5, pwm6, pwm7, pwm8
    pwm1 = PWM(Pin(P1), freq=f*10000000, duty=512)  # 1024 == 100% # 512 == 50%
    pwm2 = PWM(Pin(P2), freq=f*10000000, duty=512)  
    pwm3 = PWM(Pin(P3), freq=f*10000, duty=d*6)  
    pwm4 = PWM(Pin(P4), freq=f*10000, duty=d*5)  
    pwm5 = PWM(Pin(P5), freq=f*100, duty=d*4)  
    pwm6 = PWM(Pin(P6), freq=f*100, duty=d*3)  
    pwm7 = PWM(Pin(P7), freq=f*1, duty=d*2)
    pwm8 = PWM(Pin(P8), freq=f*1, duty=d*1)

    cnt1 = pcnt.PCNT(pcnt.Edge.BOTH, C1, DIR1, pcnt.PinPull.NONE)
    cnt2 = pcnt.PCNT(pcnt.Edge.BOTH, C2, DIR1, pcnt.PinPull.NONE)
    cnt3 = pcnt.PCNT(pcnt.Edge.BOTH, C3, DIR1, pcnt.PinPull.NONE)
    cnt4 = pcnt.PCNT(pcnt.Edge.BOTH, C4, DIR1, pcnt.PinPull.NONE)
    cnt5 = pcnt.PCNT(pcnt.Edge.BOTH, C5, DIR1, pcnt.PinPull.NONE)
    cnt6 = pcnt.PCNT(pcnt.Edge.BOTH, C6, DIR1, pcnt.PinPull.NONE)
    cnt7 = pcnt.PCNT(pcnt.Edge.BOTH, C7, DIR1, pcnt.PinPull.NONE)
    cnt8 = pcnt.PCNT(pcnt.Edge.BOTH, C8, DIR1, pcnt.PinPull.NONE)
    prnt()

def deinit_all():
    global cnt1, cnt2, cnt3, cnt4, cnt5, cnt6, cnt7, cnt8
    global pwm1, pwm2, pwm3, pwm4, pwm5, pwm6, pwm7, pwm8
    print('deinit_all():')
    try:
        pwm1.deinit()
    except:
        pass
    try:
        pwm2.deinit()
    except:
        pass
    try:
        pwm3.deinit()
    except:
        pass
    try:
        pwm4.deinit()
    except:
        pass
    try:
        pwm5.deinit()
    except:
        pass
    try:
        pwm6.deinit()
    except:
        pass
    try:
        pwm7.deinit()
    except:
        pass
    try:
        pwm8.deinit()
    except:
        pass
    try:
        cnt1.__del__()
    except:
        pass
    try:
        cnt2.__del__()
    except:
        pass
    try:
        cnt3.__del__()
    except:
        pass
    try:
        cnt4.__del__()
    except:
        pass
    try:
        cnt5.__del__()
    except:
        pass
    try:
        cnt6.__del__()
    except:
        pass
    try:
        cnt7.__del__()
    except:
        pass
    try:
        cnt8.__del__()
    except:
        pass
    

try:
    _c = None
    
    init1()
    while True:
        c = cnt1.count(), cnt2.count(), cnt3.count(), cnt4.count(), cnt5.count(), cnt6.count(), cnt7.count(), cnt8.count()
        if _c != c[1]:
            _c = c[1]
            #print(c, end='        \r')
            print(c)
        if _c == 10:
            break
            pass
    deinit_all()

    print('')
    init2()
    while True:
        c = cnt1.count(), cnt2.count(), cnt3.count(), cnt4.count(), cnt5.count(), cnt6.count(), cnt7.count(), cnt8.count()
        if _c != c[7]:
            _c = c[7]
            #print(c, end='        \r')
            print(c)
        if _c == 10:
            break
    deinit_all()
finally:
    print('finally:')
    deinit_all()

Output is

>>> %Run -c $EDITOR_CONTENT
PWM(15, freq=1, duty=4(4/1023))
PWM(2, freq=1, duty=4(4/1023))
PWM(0, freq=100, duty=512(512/1023))
PWM(4, freq=100, duty=565(565/1023))
PWM(18, freq=100000, duty=564(282/511))
PWM(21, freq=100000, duty=678(339/511))
PWM(22, freq=10000000, duty=896(7/7))
PWM(23, freq=10000000, duty=256(2/7))
PCNT(unit=0, Pin(14), Pin(5), pin_pull_type=2)
PCNT(unit=1, Pin(27), Pin(5), pin_pull_type=2)
PCNT(unit=2, Pin(26), Pin(5), pin_pull_type=2)
PCNT(unit=3, Pin(25), Pin(5), pin_pull_type=2)
PCNT(unit=4, Pin(33), Pin(5), pin_pull_type=2)
PCNT(unit=5, Pin(32), Pin(5), pin_pull_type=2)
PCNT(unit=6, Pin(35), Pin(5), pin_pull_type=2)
PCNT(unit=7, Pin(34), Pin(5), pin_pull_type=2)
(1, 1, 5, 4, 4846, 4846, 484659, 484723)
(2, 2, 23, 22, 22613, 22613, 2261315, 2261358)
(3, 3, 123, 122, 122612, 122612, 12261240, 12261283)
(4, 4, 223, 222, 222616, 222616, 22261628, 22261670)
(5, 5, 323, 322, 322604, 322604, 32260413, 32260456)
(6, 6, 423, 422, 422610, 422610, 42261029, 42261072)
(7, 7, 523, 522, 522616, 522616, 52261652, 52261694)
(8, 8, 623, 622, 622614, 622614, 62261425, 62261467)
(9, 9, 723, 722, 722609, 722609, 72260934, 72260976)
(10, 10, 823, 822, 822606, 822606, 82260679, 82260722)
deinit_all():

PWM(15, freq=10000000, duty=512(4/7))
PWM(2, freq=10000000, duty=512(4/7))
PWM(0, freq=10000, duty=678(678/1023))
PWM(4, freq=10000, duty=565(565/1023))
PWM(18, freq=100, duty=452(452/1023))
PWM(21, freq=100, duty=339(339/1023))
PWM(22, freq=1, duty=226(226/1023))
PWM(23, freq=1, duty=113(113/1023))
PCNT(unit=0, Pin(14), Pin(5), pin_pull_type=0)
PCNT(unit=1, Pin(27), Pin(5), pin_pull_type=0)
PCNT(unit=2, Pin(26), Pin(5), pin_pull_type=0)
PCNT(unit=3, Pin(25), Pin(5), pin_pull_type=0)
PCNT(unit=4, Pin(33), Pin(5), pin_pull_type=0)
PCNT(unit=5, Pin(32), Pin(5), pin_pull_type=0)
PCNT(unit=6, Pin(35), Pin(5), pin_pull_type=0)
PCNT(unit=7, Pin(34), Pin(5), pin_pull_type=0)
(1029082, 1030001, 1041, 1039, 11, 10, 2, 2)
(2339568, 2339659, 2351, 2349, 24, 24, 2, 3)
(20134572, 20134666, 20145, 20144, 202, 201, 4, 4)
(22341441, 22341537, 22352, 22351, 224, 224, 4, 5)
(40133566, 40133661, 40145, 40143, 402, 401, 6, 6)
(42338735, 42338831, 42349, 42348, 424, 424, 6, 7)
(60147638, 60147733, 60159, 60157, 602, 602, 8, 8)
(62339969, 62340064, 62351, 62349, 624, 624, 8, 9)
(80133437, 80133530, 80144, 80143, 802, 801, 10, 10)
deinit_all():
finally:
deinit_all():
>>> 

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied