aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc <[email protected]>2025-04-25 00:40:32 +0200
committerMarc <[email protected]>2025-04-25 01:14:38 +0200
commit2a4b380cb715fface63a438185502f2a96d58d80 (patch)
treee3251154e03e6cf5eacb9cfd57d547344b1f54bf
parent29bcddaa10276df2bce1acd80f51ddcec251af50 (diff)
Search can use the normal write/read instructions
-rw-r--r--embassy-rp/src/pio_programs/onewire.rs117
1 files changed, 56 insertions, 61 deletions
diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs
index 9f2ed5695..82fd98b96 100644
--- a/embassy-rp/src/pio_programs/onewire.rs
+++ b/embassy-rp/src/pio_programs/onewire.rs
@@ -12,7 +12,6 @@ pub struct PioOneWireProgram<'a, PIO: Instance> {
12 prg: LoadedProgram<'a, PIO>, 12 prg: LoadedProgram<'a, PIO>,
13 reset_addr: u8, 13 reset_addr: u8,
14 next_bit_addr: u8, 14 next_bit_addr: u8,
15 search_addr: u8,
16} 15}
17 16
18impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { 17impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> {
@@ -53,35 +52,17 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> {
53 ; The low pulse was already done, we only need to delay and poll the bit in case we are reading 52 ; The low pulse was already done, we only need to delay and poll the bit in case we are reading
54 write_1: 53 write_1:
55 nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin 54 nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin
56 in pins, 1 side 0 [(54 / CLK) - 1] ; This writes the state of the pin into the ISR 55 in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR
57 ; Fallthrough 56 ; Fallthrough
58 57
59 ; This is the entry point when reading and writing data 58 ; This is the entry point when reading and writing data
60 public next_bit: 59 public next_bit:
61 .wrap_target 60 .wrap_target
62 out x, 1 side 0 [(18 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR 61 out x, 1 side 0 [(12 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR
63 jmp x--, write_1 side 1 [(12 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit 62 jmp x--, write_1 side 1 [( 6 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit
64 in null, 1 side 1 [(60 / CLK) - 1] ; Do the remainder of the low part of a 0 bit 63 in null, 1 side 1 [(54 / CLK) - 1] ; Do the remainder of the low part of a 0 bit
65 ; This writes 0 into the ISR so that the shift count stays in sync 64 ; This writes 0 into the ISR so that the shift count stays in sync
66 .wrap 65 .wrap
67
68 public search:
69 set x, 1 side 0 [(78 / CLK) - 1] ; Set x to 1 for the inner loop
70 search_inner:
71 ; Read 2 bits
72 nop side 1 [(12 / CLK) - 1] ; Do the always low part of a bit
73 nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin
74 in pins, 1 side 0 [(54 / CLK) - 1] ; This writes the state of the pin into the ISR
75 jmp x--, search_inner side 0 [(18 / CLK) - 1]
76 ; Fallthrough
77
78 ; Write output
79 out x, 1 side 0 [( 6 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR
80 jmp x--, search side 1 [(12 / CLK) - 1] ; Do the always low part of a bit, jump to search to write a 1 bit
81 ; Fallthrough
82
83 set x, 1 side 1 [(60 / CLK) - 1] ; Set x to 1 for the inner loop, write the remainder of the low part of a 0 bit
84 jmp search_inner side 0 [(18 / CLK) - 1]
85 "# 66 "#
86 ); 67 );
87 68
@@ -89,7 +70,6 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> {
89 prg: common.load_program(&prg.program), 70 prg: common.load_program(&prg.program),
90 reset_addr: prg.public_defines.reset as u8, 71 reset_addr: prg.public_defines.reset as u8,
91 next_bit_addr: prg.public_defines.next_bit as u8, 72 next_bit_addr: prg.public_defines.next_bit as u8,
92 search_addr: prg.public_defines.search as u8,
93 } 73 }
94 } 74 }
95} 75}
@@ -98,7 +78,6 @@ pub struct PioOneWire<'d, PIO: Instance, const SM: usize> {
98 sm: StateMachine<'d, PIO, SM>, 78 sm: StateMachine<'d, PIO, SM>,
99 cfg: Config<'d, PIO>, 79 cfg: Config<'d, PIO>,
100 reset_addr: u8, 80 reset_addr: u8,
101 search_addr: u8,
102 next_bit_addr: u8, 81 next_bit_addr: u8,
103} 82}
104 83
@@ -119,13 +98,16 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
119 cfg.use_program(&program.prg, &[&pin]); 98 cfg.use_program(&program.prg, &[&pin]);
120 cfg.set_in_pins(&[&pin]); 99 cfg.set_in_pins(&[&pin]);
121 100
122 let byte_shift = ShiftConfig { 101 cfg.shift_in = ShiftConfig {
102 auto_fill: true,
103 direction: ShiftDirection::Right,
104 threshold: 8,
105 };
106 cfg.shift_out = ShiftConfig {
123 auto_fill: true, 107 auto_fill: true,
124 direction: ShiftDirection::Right, 108 direction: ShiftDirection::Right,
125 threshold: 8, 109 threshold: 8,
126 }; 110 };
127 cfg.shift_in = byte_shift;
128 cfg.shift_out = byte_shift;
129 111
130 let divider = (clk_sys_freq() / 1000000) as u16 * 6; 112 let divider = (clk_sys_freq() / 1000000) as u16 * 6;
131 cfg.clock_divider = divider.into(); 113 cfg.clock_divider = divider.into();
@@ -142,11 +124,11 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
142 sm, 124 sm,
143 cfg, 125 cfg,
144 reset_addr: program.reset_addr, 126 reset_addr: program.reset_addr,
145 search_addr: program.search_addr,
146 next_bit_addr: program.next_bit_addr, 127 next_bit_addr: program.next_bit_addr,
147 } 128 }
148 } 129 }
149 130
131 /// Perform an initialization sequence, will return true if a presence pulse was detected from a device
150 pub async fn reset(&mut self) -> bool { 132 pub async fn reset(&mut self) -> bool {
151 // The state machine immediately starts running when jumping to this address 133 // The state machine immediately starts running when jumping to this address
152 unsafe { 134 unsafe {
@@ -164,18 +146,18 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
164 found 146 found
165 } 147 }
166 148
167 /// Write bytes over the wire 149 /// Write bytes to the onewire bus
168 pub async fn write_bytes(&mut self, data: &[u8]) { 150 pub async fn write_bytes(&mut self, data: &[u8]) {
169 let (rx, tx) = self.sm.rx_tx(); 151 let (rx, tx) = self.sm.rx_tx();
170 for b in data { 152 for b in data {
171 tx.wait_push(*b as u32).await; 153 tx.wait_push(*b as u32).await;
172 154
173 // Empty the buffer that is always filled 155 // Empty the buffer that is being filled with every write
174 let _ = rx.wait_pull().await; 156 let _ = rx.wait_pull().await;
175 } 157 }
176 } 158 }
177 159
178 /// Read bytes from the wire 160 /// Read bytes from the onewire bus
179 pub async fn read_bytes(&mut self, data: &mut [u8]) { 161 pub async fn read_bytes(&mut self, data: &mut [u8]) {
180 let (rx, tx) = self.sm.rx_tx(); 162 let (rx, tx) = self.sm.rx_tx();
181 for b in data { 163 for b in data {
@@ -187,19 +169,29 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
187 } 169 }
188 170
189 async fn search(&mut self, state: &mut PioOneWireSearch) -> Option<u64> { 171 async fn search(&mut self, state: &mut PioOneWireSearch) -> Option<u64> {
190 let _ = self.reset().await; 172 if !self.reset().await {
191 self.write_bytes(&[0xF0]).await; 173 // No device present, no use in searching
174 state.finished = true;
175 return None;
176 }
177 self.write_bytes(&[0xF0]).await; // 0xF0 is the search rom command
192 178
193 let shift_cfg = self.prepare_search(); 179 self.prepare_search();
194 180
195 let (rx, tx) = self.sm.rx_tx(); 181 let (rx, tx) = self.sm.rx_tx();
196 182
197 let mut value = 0u64; 183 let mut value = 0;
198 let mut last_zero = 0; 184 let mut last_zero = 0;
199 185
200 for bit in 0..64 { 186 for bit in 0..64 {
201 let push = match rx.wait_pull().await { 187 // Write 2 dummy bits to read a bit and its complement
202 0b00 => { 188 tx.wait_push(0x1).await;
189 tx.wait_push(0x1).await;
190 let in1 = rx.wait_pull().await;
191 let in2 = rx.wait_pull().await;
192 let push = match (in1, in2) {
193 (0, 0) => {
194 // If both are 0, it means we have devices with 0 and 1 bits in this position
203 let write_value = if bit < state.last_discrepancy { 195 let write_value = if bit < state.last_discrepancy {
204 (state.last_rom & (1 << bit)) != 0 196 (state.last_rom & (1 << bit)) != 0
205 } else { 197 } else {
@@ -213,10 +205,11 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
213 0 205 0
214 } 206 }
215 } 207 }
216 0b01 => 0, 208 (0, 1) => 0, // Only devices with a 0 bit in this position
217 0b10 => 1, 209 (1, 0) => 1, // Only devices with a 1 bit in this position
218 _ => { 210 _ => {
219 self.restore_after_search(&shift_cfg); 211 // If both are 1, it means there is no device active and there is no point in continuing
212 self.restore_after_search();
220 state.finished = true; 213 state.finished = true;
221 return None; 214 return None;
222 } 215 }
@@ -226,9 +219,10 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
226 value |= 1 << 63; 219 value |= 1 << 63;
227 } 220 }
228 tx.wait_push(push).await; 221 tx.wait_push(push).await;
222 let _ = rx.wait_pull().await; // Discard the result of the write action
229 } 223 }
230 224
231 self.restore_after_search(&shift_cfg); 225 self.restore_after_search();
232 226
233 state.last_discrepancy = last_zero; 227 state.last_discrepancy = last_zero;
234 state.finished = last_zero == 0; 228 state.finished = last_zero == 0;
@@ -236,44 +230,42 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
236 Some(value) 230 Some(value)
237 } 231 }
238 232
239 fn prepare_search(&mut self) -> ShiftConfig { 233 fn prepare_search(&mut self) {
240 let shift_cfg = self.cfg.shift_in; 234 self.cfg.shift_in.threshold = 1;
241 self.cfg.shift_in = ShiftConfig { 235 self.cfg.shift_in.direction = ShiftDirection::Left;
242 auto_fill: true, 236 self.cfg.shift_out.threshold = 1;
243 direction: ShiftDirection::Left,
244 threshold: 2,
245 };
246 self.cfg.shift_out = ShiftConfig {
247 auto_fill: true,
248 direction: ShiftDirection::Right,
249 threshold: 1,
250 };
251 237
252 self.sm.set_enable(false); 238 self.sm.set_enable(false);
253 self.sm.set_config(&self.cfg); 239 self.sm.set_config(&self.cfg);
254 240
241 // set_config jumps to the wrong address so jump to the right one here
255 unsafe { 242 unsafe {
256 self.sm.exec_jmp(self.search_addr); 243 self.sm.exec_jmp(self.next_bit_addr);
257 } 244 }
258 self.sm.set_enable(true); 245 self.sm.set_enable(true);
259 shift_cfg
260 } 246 }
261 247
262 fn restore_after_search(&mut self, cfg: &ShiftConfig) { 248 fn restore_after_search(&mut self) {
263 self.cfg.shift_in = *cfg; 249 self.cfg.shift_in.threshold = 8;
264 self.cfg.shift_out = *cfg; 250 self.cfg.shift_in.direction = ShiftDirection::Right;
251 self.cfg.shift_out.threshold = 8;
265 252
266 self.sm.set_enable(false); 253 self.sm.set_enable(false);
267 self.sm.set_config(&self.cfg); 254 self.sm.set_config(&self.cfg);
255
256 // Clear the state in case we aborted prematurely with some bits still in the shift registers
257 self.sm.clear_fifos();
258 self.sm.restart();
259
260 // set_config jumps to the wrong address so jump to the right one here
268 unsafe { 261 unsafe {
269 self.sm.exec_jmp(self.next_bit_addr); 262 self.sm.exec_jmp(self.next_bit_addr);
270 } 263 }
271 self.sm.clear_fifos();
272 self.sm.restart();
273 self.sm.set_enable(true); 264 self.sm.set_enable(true);
274 } 265 }
275} 266}
276 267
268/// Onewire search state
277pub struct PioOneWireSearch { 269pub struct PioOneWireSearch {
278 last_rom: u64, 270 last_rom: u64,
279 last_discrepancy: u8, 271 last_discrepancy: u8,
@@ -281,6 +273,7 @@ pub struct PioOneWireSearch {
281} 273}
282 274
283impl PioOneWireSearch { 275impl PioOneWireSearch {
276 /// Create a new Onewire search state
284 pub fn new() -> Self { 277 pub fn new() -> Self {
285 Self { 278 Self {
286 last_rom: 0, 279 last_rom: 0,
@@ -289,6 +282,7 @@ impl PioOneWireSearch {
289 } 282 }
290 } 283 }
291 284
285 /// Search for the next address on the bus
292 pub async fn next<PIO: Instance, const SM: usize>(&mut self, pio: &mut PioOneWire<'_, PIO, SM>) -> Option<u64> { 286 pub async fn next<PIO: Instance, const SM: usize>(&mut self, pio: &mut PioOneWire<'_, PIO, SM>) -> Option<u64> {
293 if self.finished { 287 if self.finished {
294 None 288 None
@@ -297,6 +291,7 @@ impl PioOneWireSearch {
297 } 291 }
298 } 292 }
299 293
294 /// Is finished when all devices have been found
300 pub fn is_finished(&self) -> bool { 295 pub fn is_finished(&self) -> bool {
301 self.finished 296 self.finished
302 } 297 }