aboutsummaryrefslogtreecommitdiff
path: root/cyw43-pio/src
diff options
context:
space:
mode:
authorkbleeke <[email protected]>2023-03-27 18:04:48 +0200
committerkbleeke <[email protected]>2023-03-27 19:00:20 +0200
commit20ea35fc9639487eaa21f1dcee6c32d8a66a0fbb (patch)
tree20b44e30e4bce17d3c5c6cc342c0888bf60c3bbe /cyw43-pio/src
parentd918919cb20a3b8139013638193c22b3744b0f1d (diff)
Move pio driver to separate crate
Diffstat (limited to 'cyw43-pio/src')
-rw-r--r--cyw43-pio/src/lib.rs185
1 files changed, 185 insertions, 0 deletions
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
new file mode 100644
index 000000000..2159796cd
--- /dev/null
+++ b/cyw43-pio/src/lib.rs
@@ -0,0 +1,185 @@
1#![no_std]
2#![allow(incomplete_features)]
3#![feature(async_fn_in_trait)]
4
5use core::slice;
6
7use cyw43::SpiBusCyw43;
8use embassy_rp::dma::Channel;
9use embassy_rp::gpio::{Drive, Output, Pin, Pull, SlewRate};
10use embassy_rp::pio::{PioStateMachine, ShiftDirection};
11use embassy_rp::relocate::RelocatedProgram;
12use embassy_rp::{pio_instr_util, Peripheral};
13use pio::Wrap;
14use pio_proc::pio_asm;
15
16pub struct PioSpi<CS: Pin, SM, DMA> {
17 cs: Output<'static, CS>,
18 sm: SM,
19 dma: DMA,
20 wrap_target: u8,
21}
22
23impl<CS, SM, DMA> PioSpi<CS, SM, DMA>
24where
25 SM: PioStateMachine,
26 DMA: Channel,
27 CS: Pin,
28{
29 pub fn new<DIO, CLK>(mut sm: SM, cs: Output<'static, CS>, dio: DIO, clk: CLK, dma: DMA) -> Self
30 where
31 DIO: Pin,
32 CLK: Pin,
33 {
34 let program = pio_asm!(
35 ".side_set 1"
36 // "set pindirs, 1 side 0"
37 // "set pins, 0 side 0"
38 ".wrap_target"
39 "lp:",
40 "out pins, 1 side 0"
41 "jmp x-- lp side 1"
42 "set pindirs, 0 side 0"
43 "nop side 1"
44 "lp2:"
45 "in pins, 1 side 1"
46 "jmp y-- lp2 side 0"
47
48 "wait 1 pin 0 side 0"
49 "irq 0 side 0"
50
51 ".wrap"
52 );
53
54 let relocated = RelocatedProgram::new(&program.program);
55
56 let mut pin_io = sm.make_pio_pin(dio);
57 pin_io.set_pull(Pull::Down);
58 pin_io.set_schmitt(true);
59 pin_io.set_input_sync_bypass(true);
60
61 let mut pin_clk = sm.make_pio_pin(clk);
62 pin_clk.set_drive_strength(Drive::_12mA);
63 pin_clk.set_slew_rate(SlewRate::Fast);
64
65 sm.write_instr(relocated.origin() as usize, relocated.code());
66
67 // 32 Mhz
68 sm.set_clkdiv(0x03E8);
69
70 // 16 Mhz
71 // sm.set_clkdiv(0x07d0);
72
73 // 8Mhz
74 // sm.set_clkdiv(0x0a_00);
75
76 // 1Mhz
77 // sm.set_clkdiv(0x7d_00);
78
79 // slowest possible
80 // sm.set_clkdiv(0xffff_00);
81
82 sm.set_autopull(true);
83 // sm.set_pull_threshold(32);
84 sm.set_autopush(true);
85 // sm.set_push_threshold(32);
86
87 sm.set_out_pins(&[&pin_io]);
88 sm.set_in_base_pin(&pin_io);
89
90 sm.set_set_pins(&[&pin_clk]);
91 pio_instr_util::set_pindir(&mut sm, 0b1);
92 sm.set_set_pins(&[&pin_io]);
93 pio_instr_util::set_pindir(&mut sm, 0b1);
94
95 sm.set_sideset_base_pin(&pin_clk);
96 sm.set_sideset_count(1);
97
98 sm.set_out_shift_dir(ShiftDirection::Left);
99 sm.set_in_shift_dir(ShiftDirection::Left);
100
101 let Wrap { source, target } = relocated.wrap();
102 sm.set_wrap(source, target);
103
104 // pull low for startup
105 pio_instr_util::set_pin(&mut sm, 0);
106
107 Self {
108 cs,
109 sm,
110 dma,
111 wrap_target: target,
112 }
113 }
114
115 pub async fn write(&mut self, write: &[u32]) -> u32 {
116 self.sm.set_enable(false);
117 let write_bits = write.len() * 32 - 1;
118 let read_bits = 31;
119
120 defmt::trace!("write={} read={}", write_bits, read_bits);
121
122 let mut dma = Peripheral::into_ref(&mut self.dma);
123 pio_instr_util::set_x(&mut self.sm, write_bits as u32);
124 pio_instr_util::set_y(&mut self.sm, read_bits as u32);
125 pio_instr_util::set_pindir(&mut self.sm, 0b1);
126 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target);
127
128 self.sm.set_enable(true);
129
130 self.sm.dma_push(dma.reborrow(), write).await;
131
132 let mut status = 0;
133 self.sm.dma_pull(dma.reborrow(), slice::from_mut(&mut status)).await;
134 status
135 }
136
137 pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 {
138 self.sm.set_enable(false);
139 let write_bits = 31;
140 let read_bits = read.len() * 32 + 32 - 1;
141
142 defmt::trace!("write={} read={}", write_bits, read_bits);
143
144 let mut dma = Peripheral::into_ref(&mut self.dma);
145 pio_instr_util::set_y(&mut self.sm, read_bits as u32);
146 pio_instr_util::set_x(&mut self.sm, write_bits as u32);
147 pio_instr_util::set_pindir(&mut self.sm, 0b1);
148 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target);
149 // self.cs.set_low();
150 self.sm.set_enable(true);
151
152 self.sm.dma_push(dma.reborrow(), slice::from_ref(&cmd)).await;
153 self.sm.dma_pull(dma.reborrow(), read).await;
154
155 let mut status = 0;
156 self.sm.dma_pull(dma.reborrow(), slice::from_mut(&mut status)).await;
157 status
158 }
159}
160
161impl<CS, SM, DMA> SpiBusCyw43 for PioSpi<CS, SM, DMA>
162where
163 CS: Pin,
164 SM: PioStateMachine,
165 DMA: Channel,
166{
167 async fn cmd_write(&mut self, write: &[u32]) -> u32 {
168 self.cs.set_low();
169 let status = self.write(write).await;
170 self.cs.set_high();
171 status
172 }
173
174 async fn cmd_read(&mut self, write: u32, read: &mut [u32]) -> u32 {
175 self.cs.set_low();
176 let status = self.cmd_read(write, read).await;
177 self.cs.set_high();
178 status
179 }
180
181 async fn wait_for_event(&mut self) {
182 self.sm.wait_irq(0).await;
183 self.sm.clear_irq(0);
184 }
185}