diff options
Diffstat (limited to 'embassy-rp/src/pio_programs/onewire.rs')
| -rw-r--r-- | embassy-rp/src/pio_programs/onewire.rs | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 287ddab41..980d0fe5f 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs | |||
| @@ -52,7 +52,8 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { | |||
| 52 | 52 | ||
| 53 | ; The low pulse was already done, we only need to delay and poll the bit in case we are reading | 53 | ; The low pulse was already done, we only need to delay and poll the bit in case we are reading |
| 54 | write_1: | 54 | write_1: |
| 55 | nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin | 55 | jmp y--, continue_1 side 0 [( 6 / CLK) - 1] ; Delay before sampling input. Always decrement y |
| 56 | continue_1: | ||
| 56 | in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR | 57 | in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR |
| 57 | ; Fallthrough | 58 | ; Fallthrough |
| 58 | 59 | ||
| @@ -61,9 +62,24 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { | |||
| 61 | .wrap_target | 62 | .wrap_target |
| 62 | out x, 1 side 0 [(12 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR | 63 | 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 [( 6 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit | 64 | 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 [(54 / CLK) - 1] ; Do the remainder of the low part of a 0 bit | 65 | jmp y--, continue_0 side 1 [(48 / 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 | 66 | jmp pullup side 1 [( 6 / CLK) - 1] ; Remain low while jumping |
| 67 | continue_0: | ||
| 68 | in null, 1 side 1 [( 6 / CLK) - 1] ; This writes 0 into the ISR so that the shift count stays in sync | ||
| 66 | .wrap | 69 | .wrap |
| 70 | |||
| 71 | ; Assume that strong pullup commands always have MSB (the last bit) = 0, | ||
| 72 | ; since the rising edge can be used to start the operation. | ||
| 73 | ; That's the case for DS18B20 (44h and 48h). | ||
| 74 | pullup: | ||
| 75 | set pins, 1 side 1[( 6 / CLK) - 1] ; Drive pin high output immediately. | ||
| 76 | ; Strong pullup must be within 10us of rise. | ||
| 77 | in null, 1 side 1[( 6 / CLK) - 1] ; Keep ISR in sync. Must occur after the y--. | ||
| 78 | out null, 8 side 1[( 6 / CLK) - 1] ; Wait for write_bytes_pullup() delay to complete. | ||
| 79 | ; The delay is hundreds of ms, so done externally. | ||
| 80 | set pins, 0 side 0[( 6 / CLK) - 1] ; Back to open drain, pin low when driven | ||
| 81 | in null, 8 side 1[( 6 / CLK) - 1] ; Inform write_bytes_pullup() it's ready | ||
| 82 | jmp next_bit side 0[( 6 / CLK) - 1] ; Continue | ||
| 67 | "# | 83 | "# |
| 68 | ); | 84 | ); |
| 69 | 85 | ||
| @@ -98,6 +114,7 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { | |||
| 98 | let mut cfg = Config::default(); | 114 | let mut cfg = Config::default(); |
| 99 | cfg.use_program(&program.prg, &[&pin]); | 115 | cfg.use_program(&program.prg, &[&pin]); |
| 100 | cfg.set_in_pins(&[&pin]); | 116 | cfg.set_in_pins(&[&pin]); |
| 117 | cfg.set_set_pins(&[&pin]); | ||
| 101 | 118 | ||
| 102 | let shift_cfg = ShiftConfig { | 119 | let shift_cfg = ShiftConfig { |
| 103 | auto_fill: true, | 120 | auto_fill: true, |
| @@ -146,6 +163,19 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { | |||
| 146 | 163 | ||
| 147 | /// Write bytes to the onewire bus | 164 | /// Write bytes to the onewire bus |
| 148 | pub async fn write_bytes(&mut self, data: &[u8]) { | 165 | pub async fn write_bytes(&mut self, data: &[u8]) { |
| 166 | unsafe { self.sm.set_y(u32::MAX as u32) }; | ||
| 167 | let (rx, tx) = self.sm.rx_tx(); | ||
| 168 | for b in data { | ||
| 169 | tx.wait_push(*b as u32).await; | ||
| 170 | |||
| 171 | // Empty the buffer that is being filled with every write | ||
| 172 | let _ = rx.wait_pull().await; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | /// Write bytes to the onewire bus, then apply a strong pullup | ||
| 177 | pub async fn write_bytes_pullup(&mut self, data: &[u8], pullup_time: embassy_time::Duration) { | ||
| 178 | unsafe { self.sm.set_y(data.len() as u32 * 8 - 1) }; | ||
| 149 | let (rx, tx) = self.sm.rx_tx(); | 179 | let (rx, tx) = self.sm.rx_tx(); |
| 150 | for b in data { | 180 | for b in data { |
| 151 | tx.wait_push(*b as u32).await; | 181 | tx.wait_push(*b as u32).await; |
| @@ -153,10 +183,19 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { | |||
| 153 | // Empty the buffer that is being filled with every write | 183 | // Empty the buffer that is being filled with every write |
| 154 | let _ = rx.wait_pull().await; | 184 | let _ = rx.wait_pull().await; |
| 155 | } | 185 | } |
| 186 | |||
| 187 | // Perform the delay, usually hundreds of ms. | ||
| 188 | embassy_time::Timer::after(pullup_time).await; | ||
| 189 | |||
| 190 | // Signal that delay has completed | ||
| 191 | tx.wait_push(0 as u32).await; | ||
| 192 | // Wait until it's back at 0 low, open drain | ||
| 193 | let _ = rx.wait_pull().await; | ||
| 156 | } | 194 | } |
| 157 | 195 | ||
| 158 | /// Read bytes from the onewire bus | 196 | /// Read bytes from the onewire bus |
| 159 | pub async fn read_bytes(&mut self, data: &mut [u8]) { | 197 | pub async fn read_bytes(&mut self, data: &mut [u8]) { |
| 198 | unsafe { self.sm.set_y(u32::MAX as u32) }; | ||
| 160 | let (rx, tx) = self.sm.rx_tx(); | 199 | let (rx, tx) = self.sm.rx_tx(); |
| 161 | for b in data { | 200 | for b in data { |
| 162 | // Write all 1's so that we can read what the device responds | 201 | // Write all 1's so that we can read what the device responds |
