Add RP2 fast encoder.

pull/29/head
Peter Hinch 2022-01-01 15:43:20 +00:00
rodzic 388034195e
commit f1ac15a327
2 zmienionych plików z 76 dodań i 1 usunięć

Wyświetl plik

@ -129,7 +129,9 @@ the rate at which callbacks occur.
practice this is likely to need filtering to reduce jitter caused by practice this is likely to need filtering to reduce jitter caused by
imperfections in the encoder geometry. With a mechanical knob turned by an imperfections in the encoder geometry. With a mechanical knob turned by an
anthropoid ape it's debatable whether it produces anything useful :) anthropoid ape it's debatable whether it produces anything useful :)
3. `encoder.py` An old Pyboard-specific version. 3. `encoder_rp2.py` Version specific to Raspberry Pico RP2 chip. This uses the
PIO and Viper code to achieve fast response - upto ~10K transitions/s.
4. `encoder.py` An old Pyboard-specific version.
These were written for encoders producing logic outputs. For switches, adapt These were written for encoders producing logic outputs. For switches, adapt
the pull definition to provide a pull up or pull down as required, or provide the pull definition to provide a pull up or pull down as required, or provide

Wyświetl plik

@ -0,0 +1,73 @@
# encoder_rp2.py Uses the PIO for rapid response on RP2 chips (Pico)
# Copyright (c) 2022 Peter Hinch
# Released under the MIT License (MIT) - see LICENSE file
# PIO and SM code written by Sandor Attila Gerendi (@sanyi)
# https://github.com/micropython/micropython/pull/6894
from machine import Pin
from array import array
import rp2
# Test with encoder on pins 2 and 3:
#e = Encoder(0, Pin(2))
#while True:
#time.sleep(1)
#print(e.value())
# Closure enables Viper to retain state. Currently (V1.17) nonlocal doesn't
# work: https://github.com/micropython/micropython/issues/8086
# so using arrays.
def make_isr(pos):
old_x = array('i', (0,))
@micropython.viper
def isr(sm):
i = ptr32(pos)
p = ptr32(old_x)
while sm.rx_fifo():
v : int = int(sm.get()) & 3
x : int = v & 1
y : int = v >> 1
s : int = 1 if (x ^ y) else -1
i[0] = i[0] + (s if (x ^ p[0]) else (0 - s))
p[0] = x
return isr
# Args:
# StateMachine no. (0-7): each instance must have a different sm_no.
# An initialised input Pin: this and the next pin are the encoder interface.
class Encoder:
def __init__(self, sm_no, base_pin, scale=1):
self.scale = scale
self._pos = array("i", (0,)) # [pos]
self.sm = rp2.StateMachine(sm_no, self.pio_quadrature, in_base=base_pin)
self.sm.irq(make_isr(self._pos)) # Instantiate the closure
self.sm.exec("set(y, 99)") # Initialise y: guarantee different to the input
self.sm.active(1)
@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()
def position(self, value=None):
if value is not None:
self._pos[0] = round(value / self.scale)
return self._pos[0] * self.scale
def value(self, value=None):
if value is not None:
self._pos[0] = value
return self._pos[0]