Page 1 of 1
PIO measuring time between pin change
Posted: Fri Nov 19, 2021 6:41 pm
by podex
Hi,
I would like to measure the time of a pulse in low level. So I used the PWM example in order to generate a pulse on the LED. And I wrote a PIO script that first waits for the pin being low and then decrements scratch register x untkl the pin goes high. At least this was the intention of this script. But it does not work, I hope that somebody can give me a hint what I did wrong or misunderstood.
Many thanks for any help!
KR,
Ch.
Code: Select all
# Example using PWM to fade an LED.
import time
import rp2
from machine import Pin, PWM
# measure time between falling edges
@rp2.asm_pio(set_init=rp2.PIO.IN_HIGH)
def perMeas():
label('mainloop')
set(x,0)
wait(0, pin, 0)
label('lo_loop')
jmp(x_dec,'next')
label('next')
jmp(pin,'hi')
jmp('lo_loop')
label('hi')
mov(isr,x)
push()
jmp('mainloop')
# Construct PWM object, with LED on Pin(25).
pwm = PWM(Pin(25))
# Set the PWM frequency.
pwm.freq(10)
# Fade the LED in and out a few times.
duty = 10
direction = 1
# for _ in range(8 * 256):
sm4 = rp2.StateMachine(1, perMeas, freq=200000, in_base=Pin(25)) # pin16 used
sm4.active(1)
while True:
duty += direction
if duty > 255:
duty = 255
direction = -1
elif duty < 0:
duty = 0
direction = 1
pwm.duty_u16(duty * duty)
time.sleep(1.0)
while sm4.rx_fifo():
print(2**32-sm4.get(),end=' ')
else:
print('empty',end=' ')
print()
Re: PIO measuring time between pin change
Posted: Fri Nov 19, 2021 9:26 pm
by Roberthh
I made scripts to create and time pulses using pio. See the scripts pulses at
https://github.com/robert-hh/RP2040-Examples
Re: PIO measuring time between pin change
Posted: Sat Nov 20, 2021 10:10 am
by pythoncoder
This script returns the period between pulses and also the pulse duration (mark) and duty ratio (mark/period):
Code: Select all
from machine import Pin, PWM
from rp2 import PIO, StateMachine, asm_pio
import time
@rp2.asm_pio(set_init=rp2.PIO.IN_LOW, autopush=True, push_thresh=32)
def period():
wrap_target()
set(x, 0)
wait(0, pin, 0) # Wait for pin to go low
wait(1, pin, 0) # Low to high transition
label('low_high')
jmp(x_dec, 'next') [1] # unconditional
label('next')
jmp(pin, 'low_high') # while pin is high
label('low') # pin is low
jmp(x_dec, 'nxt')
label('nxt')
jmp(pin, 'done') # pin has gone high: all done
jmp('low')
label('done')
in_(x, 32) # Auto push: SM stalls if FIFO full
wrap()
@rp2.asm_pio(set_init=rp2.PIO.IN_LOW, autopush=True, push_thresh=32)
def mark():
wrap_target()
set(x, 0)
wait(0, pin, 0) # Wait for pin to go low
wait(1, pin, 0) # Low to high transition
label('low_high')
jmp(x_dec, 'next') [1] # unconditional
label('next')
jmp(pin, 'low_high') # while pin is high
in_(x, 32) # Auto push: SM stalls if FIFO full
wrap()
pin16 = Pin(16, Pin.IN, Pin.PULL_UP)
sm0 = rp2.StateMachine(0, period, in_base=pin16, jmp_pin=pin16)
sm0.active(1)
sm1 = rp2.StateMachine(1, mark, in_base=pin16, jmp_pin=pin16)
sm1.active(1)
pwm = PWM(Pin(17))
pwm.freq(1000)
pwm.duty_u16(0xffff // 3)
# Clock is 125MHz. 3 cycles per iteration, so unit is 24.0ns
def scale(v):
return (1 + (v ^ 0xffffffff)) * 24e-6 # Scale to ms
while True:
period = scale(sm0.get())
mark = scale(sm1.get())
print(period, mark, mark/period)
time.sleep(0.2)
Re: PIO measuring time between pin change
Posted: Mon Nov 22, 2021 7:15 pm
by podex
Hi,
Many thanks, that's exactly what I am searching for!
My first thought is not true because when I change the pin to 25, the PIO works. I will check and double-check my code to see why it's not working as expected.
KR,
Christof
Re: PIO measuring time between pin change
Posted: Fri Jan 07, 2022 12:44 pm
by podex
After a while I come back to the time measurement. It took a little bit because of the festival season and I had to get the answer of the sensor correct, I have level-shifters with pull-up resistors and have to switch from drive to open-drain. But now it works, now I can focus on the measurement between falling edges.
I tried to modify my script with your example in mind. There I got a strange effect, I did not expect:
Code: Select all
from machine import Pin
import time,utime,rp2
@rp2.asm_pio(set_init=rp2.PIO.IN_HIGH, autopush=True, push_thresh=16) # push() is done automatically win in_()!
def period():
set(x, 1023)
in_(x, 16) # Auto push : SM stalls if FIFO full
wrap_target()
nop()
wrap()
pin16 = Pin(16, Pin.IN, Pin.PULL_UP)
sm_meas = rp2.StateMachine(0, period, freq=100000, in_base=pin16, jmp_pin=pin16)
sm_meas.active(1)
while True:
print("\nrestart ... ",end="")
sm_meas.restart()
print("got ",end="")
while sm_meas.rx_fifo()>0:
period_ticks=sm_meas.get()
print(period_ticks,end=" ")
utime.sleep(1)
With this code I would expect that I get the value 1023 printed, but it's not the case:
Code: Select all
MicroPython v1.17 on 2021-09-02; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
restart ... got 0 0
restart ... got 0
restart ... got 0
What's my fault, it also does not work with bit-range 32...
Thanks for any hints!
Christof
Re: PIO measuring time between pin change
Posted: Fri Jan 07, 2022 2:13 pm
by podex
Maybe I should explain what I would like to do. I have a sensor with SPC interface (for an explaination see
https://www.nxp.com/docs/en/application-note/AN4219.pdf) where the time between falling edges of the signal line defines the data transferred.
This is a screenshot of the Master trigger pulse with 33us low time (measurement of channel 1) and the synchronization pulse starting 272us after the start of the trigger pulse ending at 440us. So the unit time of this sensor is 3us.

- DS1Z_QuickPrint18.png (48.27 KiB) Viewed 21415 times
In order to decode the sensor output, I need the times of the falling edges. This with the unit time gives the data nibbles.
Of course I could do it with one of the Cortex-M0+ cores, but I think this is also possible with PIO "in the background".
My concept would be the following:
The register X is set to a predefined value with the trigger pulse and then decremented. At each falling edge the register value is then pulled into the RX-FIFO. At the end from the deltas of the time of the falling edges the data nibbles can be computed with the help of the length of the synchronization pulse.
KR,
Christof
Re: PIO measuring time between pin change
Posted: Fri Jan 07, 2022 7:00 pm
by podex
Well, maybe I should have read the docu a little bit more carefully. set() works with data up to 31, because the number of bits in the command is limited.
Code: Select all
@rp2.asm_pio(set_init=rp2.PIO.IN_HIGH, autopush=True, push_thresh=32) # push() is done automatically win in_()!
def period():
set(x, 31)
in_(x, 32) # Auto push : SM stalls if FIFO full
wrap_target()
nop() [1]
wrap()
This works as expected.
Re: PIO measuring time between pin change
Posted: Sat Jan 08, 2022 6:26 pm
by hippy
podex wrote: ↑Fri Jan 07, 2022 7:00 pm
Well, maybe I should have read the docu a little bit more carefully. set() works with data up to 31, because the number of bits in the command is limited.
The "@asm_pio" assembler is unfortunately almost completely lacking when it comes to error reporting and identifying user mistakes, is likely silently creating an instruction which is entirely different to what you wanted.
The other common mistakes which don't get reported are using 'set' with a register source, 'mov' with a numeric constant, and using registers which are not valid for a particular instruction.
If I ever get my version of the assembler which includes error reporting and allows pure text source to be specified completed and tested I will publish that.