-
Notifications
You must be signed in to change notification settings - Fork 233
/
Copy pathpio_pwmin.py
96 lines (73 loc) · 2.83 KB
/
pio_pwmin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from machine import Pin, PWM
from rp2 import PIO, StateMachine, asm_pio
from time import sleep, ticks_ms, ticks_diff
pwm_out = PWM(Pin(16))
pwm_out.freq(100)
pwm_out.duty_u16((2**16-1)//2)
@asm_pio()
def pwmin():
pull(block) # wait for activation by doing a blocking pull on the input
mov(x, invert(null)) # invert(null) = Max. 32 Bit value
wait(1, pin, 0) # wait for a full PWM cycle to start measurement
wait(0, pin, 0) # wait for pin to be low
label("count_low")
jmp(pin, "out_low") # jump to output if pin is high
jmp(x_dec, "count_low") # jump back to count loop, decrement X
label("out_low")
mov(isr, x) # move x into ISR for outputting low counter of PWM signal
push(noblock) # push into fifo
label("count_high")
jmp(x_dec, "next") # count down X, jump to next instruction
label("next")
jmp(pin, "count_high") # as long as the pin is high, jump back up to continue countdown
mov(isr, x) # move x into ISR for outputting the total period of the signal
push(noblock) # push into fifo
irq(0)
base_frq = 100_000_000
sm = rp2.StateMachine(0, pwmin, freq=base_frq, jmp_pin=Pin(16), in_base=Pin(16))
sm.active(1)
'''
W A R N I N G
This example code will hang, if no PWM signal is present,
e.g. when the PWM is at 0% or 100% duty cycle.
'''
def readPwm(sm):
# Send data to start measurement
sm.put(0)
low = sm.get()
total = sm.get()
# Convert to duration
low = 2**32 - 1 - low
total = 2**32 - 1 - total
# Total is in ticks, based on base_frq.
# Due to the code, it counts by 1 for every 2 clock cycles
period = total / base_frq * 2
return {
"period":period,
"duty_low":low/total,
"duty":1.0-(low/total),
"freq":1/period
}
print("PWMIn Selfcheck")
for f in [100, 200, 500,
1_000, 2_000, 5_000,
10_000, 20_000, 50000,
100_000, 200_000, 500_000]:
for d in [0.1, 0.25, 0.5, 0.75, 0.9]:
# Set new output
pwm_out.freq(f)
pwm_out.duty_u16(int((2**16-1)*d))
# Wait a bit
sleep(0.5)
read = readPwm(sm)
diff_freq = abs(read["freq"]-f)
diff_duty = abs(read["duty"]-d)
if (diff_freq <= f*0.01) and (diff_duty < 0.01):
print("{} Hz / {} duty OK".format(f, d))
else:
print("{} Hz / {} duty OUTSIDE LIMITS ---------".format(f, d))
print("\t{:.2f} Hz / {:.2f} duty cycle measured".format(read["freq"], read["duty"]))
print("\tDiff: {:.2f} Hz".format(diff_freq))
print("\tDiff: {:.2%} of freq".format(abs(1.0-read["freq"]/f)))
print("\tDiff: {:.2%} duty cycle".format(diff_duty))
print("")