aboutsummaryrefslogtreecommitdiff
path: root/examples/rp/src/bin/pio_stepper.rs
diff options
context:
space:
mode:
authorCaleb Jamison <[email protected]>2024-10-09 10:04:35 -0400
committerCaleb Jamison <[email protected]>2024-10-09 10:18:00 -0400
commit57c1fbf3089e2a2dc9fe5b7d1f1e094596566395 (patch)
tree833856b7da855b8de56dec1494c2da88ac29e415 /examples/rp/src/bin/pio_stepper.rs
parent456c226b29799f7db56ab60b0ae3d95cc7d6a32a (diff)
Move pio programs into embassy-rp
Diffstat (limited to 'examples/rp/src/bin/pio_stepper.rs')
-rw-r--r--examples/rp/src/bin/pio_stepper.rs135
1 files changed, 8 insertions, 127 deletions
diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs
index 6ee45a414..3862c248b 100644
--- a/examples/rp/src/bin/pio_stepper.rs
+++ b/examples/rp/src/bin/pio_stepper.rs
@@ -3,143 +3,20 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6use core::mem::{self, MaybeUninit};
7 6
8use defmt::info; 7use defmt::info;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 9use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::PIO0; 10use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; 11use embassy_rp::pio::{InterruptHandler, Pio};
12use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram};
13use embassy_time::{with_timeout, Duration, Timer}; 13use embassy_time::{with_timeout, Duration, Timer};
14use fixed::traits::ToFixed;
15use fixed::types::extra::U8;
16use fixed::FixedU32;
17use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
18 15
19bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
20 PIO0_IRQ_0 => InterruptHandler<PIO0>; 17 PIO0_IRQ_0 => InterruptHandler<PIO0>;
21}); 18});
22 19
23pub struct PioStepper<'d, T: Instance, const SM: usize> {
24 irq: Irq<'d, T, SM>,
25 sm: StateMachine<'d, T, SM>,
26}
27
28impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
29 pub fn new(
30 pio: &mut Common<'d, T>,
31 mut sm: StateMachine<'d, T, SM>,
32 irq: Irq<'d, T, SM>,
33 pin0: impl PioPin,
34 pin1: impl PioPin,
35 pin2: impl PioPin,
36 pin3: impl PioPin,
37 ) -> Self {
38 let prg = pio_proc::pio_asm!(
39 "pull block",
40 "mov x, osr",
41 "pull block",
42 "mov y, osr",
43 "jmp !x end",
44 "loop:",
45 "jmp !osre step",
46 "mov osr, y",
47 "step:",
48 "out pins, 4 [31]"
49 "jmp x-- loop",
50 "end:",
51 "irq 0 rel"
52 );
53 let pin0 = pio.make_pio_pin(pin0);
54 let pin1 = pio.make_pio_pin(pin1);
55 let pin2 = pio.make_pio_pin(pin2);
56 let pin3 = pio.make_pio_pin(pin3);
57 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
58 let mut cfg = Config::default();
59 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
60 cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed();
61 cfg.use_program(&pio.load_program(&prg.program), &[]);
62 sm.set_config(&cfg);
63 sm.set_enable(true);
64 Self { irq, sm }
65 }
66
67 // Set pulse frequency
68 pub fn set_frequency(&mut self, freq: u32) {
69 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
70 assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
71 assert!(clock_divider >= 1, "clkdiv must be >= 1");
72 self.sm.set_clock_divider(clock_divider);
73 self.sm.clkdiv_restart();
74 }
75
76 // Full step, one phase
77 pub async fn step(&mut self, steps: i32) {
78 if steps > 0 {
79 self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await
80 } else {
81 self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await
82 }
83 }
84
85 // Full step, two phase
86 pub async fn step2(&mut self, steps: i32) {
87 if steps > 0 {
88 self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await
89 } else {
90 self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await
91 }
92 }
93
94 // Half step
95 pub async fn step_half(&mut self, steps: i32) {
96 if steps > 0 {
97 self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await
98 } else {
99 self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await
100 }
101 }
102
103 async fn run(&mut self, steps: i32, pattern: u32) {
104 self.sm.tx().wait_push(steps as u32).await;
105 self.sm.tx().wait_push(pattern).await;
106 let drop = OnDrop::new(|| {
107 self.sm.clear_fifos();
108 unsafe {
109 self.sm.exec_instr(
110 pio::InstructionOperands::JMP {
111 address: 0,
112 condition: pio::JmpCondition::Always,
113 }
114 .encode(),
115 );
116 }
117 });
118 self.irq.wait().await;
119 drop.defuse();
120 }
121}
122
123struct OnDrop<F: FnOnce()> {
124 f: MaybeUninit<F>,
125}
126
127impl<F: FnOnce()> OnDrop<F> {
128 pub fn new(f: F) -> Self {
129 Self { f: MaybeUninit::new(f) }
130 }
131
132 pub fn defuse(self) {
133 mem::forget(self)
134 }
135}
136
137impl<F: FnOnce()> Drop for OnDrop<F> {
138 fn drop(&mut self) {
139 unsafe { self.f.as_ptr().read()() }
140 }
141}
142
143#[embassy_executor::main] 20#[embassy_executor::main]
144async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
145 let p = embassy_rp::init(Default::default()); 22 let p = embassy_rp::init(Default::default());
@@ -147,14 +24,18 @@ async fn main(_spawner: Spawner) {
147 mut common, irq0, sm0, .. 24 mut common, irq0, sm0, ..
148 } = Pio::new(p.PIO0, Irqs); 25 } = Pio::new(p.PIO0, Irqs);
149 26
150 let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); 27 let prg = PioStepperProgram::new(&mut common);
28 let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7, &prg);
151 stepper.set_frequency(120); 29 stepper.set_frequency(120);
152 loop { 30 loop {
153 info!("CW full steps"); 31 info!("CW full steps");
154 stepper.step(1000).await; 32 stepper.step(1000).await;
155 33
156 info!("CCW full steps, drop after 1 sec"); 34 info!("CCW full steps, drop after 1 sec");
157 if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)).await { 35 if with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX))
36 .await
37 .is_err()
38 {
158 info!("Time's up!"); 39 info!("Time's up!");
159 Timer::after(Duration::from_secs(1)).await; 40 Timer::after(Duration::from_secs(1)).await;
160 } 41 }