Skip to main content

embassy_rp/pio_programs/
rotary_encoder.rs

1//! PIO backed quadrature encoder
2
3use crate::Peri;
4use crate::gpio::Pull;
5use crate::pio::{
6    Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
7};
8use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
9
10/// This struct represents an Encoder program loaded into pio instruction memory.
11pub struct PioEncoderProgram<'a, PIO: Instance> {
12    prg: LoadedProgram<'a, PIO>,
13}
14
15impl<'a, PIO: Instance> PioEncoderProgram<'a, PIO> {
16    /// Load the program into the given pio
17    pub fn new(common: &mut Common<'a, PIO>) -> Self {
18        let prg = pio::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",);
19
20        let prg = common.load_program(&prg.program);
21
22        Self { prg }
23    }
24}
25
26/// Pio Backed quadrature encoder reader
27pub struct PioEncoder<'d, T: Instance, const SM: usize> {
28    sm: StateMachine<'d, T, SM>,
29}
30
31impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
32    /// Configure a state machine with the loaded [PioEncoderProgram]
33    pub fn new(
34        pio: &mut Common<'d, T>,
35        mut sm: StateMachine<'d, T, SM>,
36        pin_a: Peri<'d, impl PioPin>,
37        pin_b: Peri<'d, impl PioPin>,
38        program: &PioEncoderProgram<'d, T>,
39    ) -> Self {
40        let mut pin_a = pio.make_pio_pin(pin_a);
41        let mut pin_b = pio.make_pio_pin(pin_b);
42        pin_a.set_pull(Pull::Up);
43        pin_b.set_pull(Pull::Up);
44        sm.set_pin_dirs(PioDirection::In, &[&pin_a, &pin_b]);
45
46        let mut cfg = Config::default();
47        cfg.set_in_pins(&[&pin_a, &pin_b]);
48        cfg.fifo_join = FifoJoin::RxOnly;
49        cfg.shift_in.direction = ShiftDirection::Left;
50
51        // Target 12.5 KHz PIO clock
52        cfg.clock_divider = calculate_pio_clock_divider(12_500);
53
54        cfg.use_program(&program.prg, &[]);
55        sm.set_config(&cfg);
56        sm.set_enable(true);
57        Self { sm }
58    }
59
60    /// Read a single count from the encoder
61    pub async fn read(&mut self) -> Direction {
62        loop {
63            match self.sm.rx().wait_pull().await {
64                0 => return Direction::CounterClockwise,
65                1 => return Direction::Clockwise,
66                _ => {}
67            }
68        }
69    }
70}
71
72/// Encoder Count Direction
73pub enum Direction {
74    /// Encoder turned clockwise
75    Clockwise,
76    /// Encoder turned counter clockwise
77    CounterClockwise,
78}