diff --git a/pio/pio_pwmin.py b/pio/pio_pwmin.py new file mode 100644 index 0000000..138056d --- /dev/null +++ b/pio/pio_pwmin.py @@ -0,0 +1,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("")