From 7e2bda83e0d3f9009820f37a18b71cc78f3d677e Mon Sep 17 00:00:00 2001 From: Thomas A Date: Thu, 8 Apr 2021 17:02:35 +0200 Subject: [PATCH 1/5] Add Pwm-Input Example Known issue: Constant signals --- pio/pio_pwmin.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 pio/pio_pwmin.py diff --git a/pio/pio_pwmin.py b/pio/pio_pwmin.py new file mode 100644 index 0000000..e749bee --- /dev/null +++ b/pio/pio_pwmin.py @@ -0,0 +1,95 @@ +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 + + set(x, 0) # Set x = 0 + mov(x, x | (0b01 << 3)) # invert x = Max-Value for 32 bits + + 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 + 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 + 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("\tDiff: {:.2f} Hz".format(diff_freq)) + print("\tDiff: {:.2%} of freq".format(abs(1.0-read["freq"]/f))) + print("\tDiff: {:.5f} duty cycle".format(diff_duty)) From b07f0acda5b75f8a0fdedf9950b09eb742a78037 Mon Sep 17 00:00:00 2001 From: Thomas A Date: Thu, 8 Apr 2021 17:45:58 +0200 Subject: [PATCH 2/5] Update pio_pwmin.py Small beauty fix --- pio/pio_pwmin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pio/pio_pwmin.py b/pio/pio_pwmin.py index e749bee..6ddb62f 100644 --- a/pio/pio_pwmin.py +++ b/pio/pio_pwmin.py @@ -90,6 +90,9 @@ def readPwm(sm): 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: {:.5f} duty cycle".format(diff_duty)) + print("\tDiff: {:.2%} duty cycle".format(diff_duty)) + print("") From df547c6e161225dfa3c60f4858516cb8a38d25a7 Mon Sep 17 00:00:00 2001 From: Thomas A Date: Thu, 8 Apr 2021 17:47:28 +0200 Subject: [PATCH 3/5] Explicitly mention invert bit. --- pio/pio_pwmin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pio/pio_pwmin.py b/pio/pio_pwmin.py index 6ddb62f..b80cd9f 100644 --- a/pio/pio_pwmin.py +++ b/pio/pio_pwmin.py @@ -12,7 +12,7 @@ def pwmin(): pull(block) # wait for activation set(x, 0) # Set x = 0 - mov(x, x | (0b01 << 3)) # invert x = Max-Value for 32 bits + mov(x, x | (0b01 << 3)) # invert x = Max-Value for 32 bits. (0b01 << 3) sets the invert bit. wait(1, pin, 0) # wait for a full PWM cycle to start measurement wait(0, pin, 0) # wait for pin to be low From 91da8c916ec253b57173366cf0ff05e5df016432 Mon Sep 17 00:00:00 2001 From: Thomas A Date: Thu, 8 Apr 2021 19:02:35 +0200 Subject: [PATCH 4/5] Use invert(...) correctly instead of setting the bits manually --- pio/pio_pwmin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pio/pio_pwmin.py b/pio/pio_pwmin.py index b80cd9f..efb8f17 100644 --- a/pio/pio_pwmin.py +++ b/pio/pio_pwmin.py @@ -12,7 +12,7 @@ def pwmin(): pull(block) # wait for activation set(x, 0) # Set x = 0 - mov(x, x | (0b01 << 3)) # invert x = Max-Value for 32 bits. (0b01 << 3) sets the invert bit. + mov(x, invert(x)) # invert x = Max-Value for 32 bits wait(1, pin, 0) # wait for a full PWM cycle to start measurement wait(0, pin, 0) # wait for pin to be low @@ -32,7 +32,7 @@ def pwmin(): mov(isr, x) # move x into ISR push(noblock) # push into fifo - irq(0) + irq(0) # Signal IRQ (optional, may be used for 0%/100% detection base_frq = 100_000_000 sm = rp2.StateMachine(0, pwmin, freq=base_frq, jmp_pin=Pin(16), in_base=Pin(16)) From ccbbf0259b28d42bc823a1d5407328764664928c Mon Sep 17 00:00:00 2001 From: Thomas A Date: Thu, 8 Apr 2021 19:18:10 +0200 Subject: [PATCH 5/5] Merge set(x,0) and mov(x, invert(x)) into a single instruction Thanks to @lurch for finding this. --- pio/pio_pwmin.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pio/pio_pwmin.py b/pio/pio_pwmin.py index efb8f17..138056d 100644 --- a/pio/pio_pwmin.py +++ b/pio/pio_pwmin.py @@ -9,30 +9,28 @@ @asm_pio() def pwmin(): - pull(block) # wait for activation - - set(x, 0) # Set x = 0 - mov(x, invert(x)) # invert x = Max-Value for 32 bits + 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 + 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 - push(noblock) # push into fifo + 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 + mov(isr, x) # move x into ISR for outputting the total period of the signal push(noblock) # push into fifo - irq(0) # Signal IRQ (optional, may be used for 0%/100% detection + irq(0) base_frq = 100_000_000 sm = rp2.StateMachine(0, pwmin, freq=base_frq, jmp_pin=Pin(16), in_base=Pin(16))