Skip to content

Add RPI PIO example for quadrature encoder. #6894

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions examples/rp2/pio_quadrature_encoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""
This implementation offloads the quadrature sensor continuous pooling to the StateMachine pio_quadrature,
pio_quadrature will detect state changes and push the values then raises an interrupt that is handled by
encoder_state_changed_irq_handler

encoder_state_changed_irq_handler was inspired from
https://electronics.stackexchange.com/questions/360637/quadrature-encoder-most-efficient-software-implementation

"""

from machine import Pin
import rp2
from rp2 import PIO, StateMachine
import utime
import array


state_look_up_table = array.array("b", [
#Direction = 1
0, # 00 to 00
-1, # 00 to 01
+1, # 00 to 10
+2, # 00 to 11

+1, # 01 to 00
0, # 01 to 01
+2, # 01 to 10
-1, # 01 to 11

-1, # 10 to 00
+2, # 10 to 01
0, # 10 to 10
+1, # 10 to 11

+2, # 11 to 00
+1, # 11 to 01
-1, # 11 to 10
0, # 11 to 11

#Direction = 0
0, # 00 to 00
-1, # 00 to 01
+1, # 00 to 10
-2, # 00 to 11

+1, # 01 to 00
0, # 01 to 01
-2, # 01 to 10
-1, # 01 to 11

-1, # 10 to 00
-2, # 10 to 01
0, # 10 to 10
+1, # 10 to 11

-2, # 11 to 00
+1, # 11 to 01
-1, # 11 to 10
0, # 11 to 11
])


counter = 0
direction = 0
lut_index = 0

def encoder_state_changed_irq_handler(sm):
global counter, direction, lut_index
while sm.rx_fifo():
lut_index |= sm.get() & 3
counter += state_look_up_table[lut_index]
if state_look_up_table[lut_index] != 0:
direction = 1 if (state_look_up_table[lut_index] > 0) else 0
lut_index = ((lut_index << 2) & 0b1100) | (direction << 4)


@rp2.asm_pio()
def pio_quadrature(in_init=rp2.PIO.IN_LOW):
wrap_target()
label("again")
in_(pins, 2)
mov(x, isr)
jmp(x_not_y, "push_data")
mov(isr, null)
jmp("again")
label("push_data")
push()
irq(block, rel(0))
mov(y, x)
wrap()



sm = StateMachine(0, pio_quadrature, freq=160000, in_base=Pin(2))
sm.irq(encoder_state_changed_irq_handler)
sm.exec("set(y, 99)") # add a last value for y that would be always different then the input
sm.active(1)

while True:
utime.sleep(2)
print(counter)