diff options
| author | Matt Johnston <[email protected]> | 2025-09-14 16:30:31 +0800 |
|---|---|---|
| committer | Matt Johnston <[email protected]> | 2025-09-14 16:54:14 +0800 |
| commit | 8f10e3638d77cadf058b9083de09fc7189048b0b (patch) | |
| tree | 804739dd75306154351460b0ee4dde51a3170caa /examples | |
| parent | be794533d3929e316c65b4296de47292ae0eae67 (diff) | |
rp/pio: Add onewire strong pullups, parasite power
DS18B20 sensors require a strong pullup to be applied for the duration
of the temperature conversion, within 10us of the command. The rp2xxx
pins have sufficient drive strength to use as the pullup (no external
mosfet needed).
Add a new write_bytes_pullup() that will apply the pullup after
bytes are written. Existing read_bytes()/write_bytes() has no change to
onewire timing.
A pio_onewire_parasite example reads multiple sensors individually,
applying the strong pullup.
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/rp/src/bin/pio_onewire.rs | 1 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_onewire_parasite.rs | 89 |
2 files changed, 90 insertions, 0 deletions
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 379e2b8f9..102f13c45 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | //! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors. | 1 | //! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors. |
| 2 | //! This uses externally powered sensors. For parasite power, see the pio_onewire_parasite.rs example. | ||
| 2 | 3 | ||
| 3 | #![no_std] | 4 | #![no_std] |
| 4 | #![no_main] | 5 | #![no_main] |
diff --git a/examples/rp/src/bin/pio_onewire_parasite.rs b/examples/rp/src/bin/pio_onewire_parasite.rs new file mode 100644 index 000000000..fd076dee0 --- /dev/null +++ b/examples/rp/src/bin/pio_onewire_parasite.rs | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | //! This example shows how you can use PIO to read one or more `DS18B20` | ||
| 2 | //! one-wire temperature sensors using parasite power. | ||
| 3 | //! It applies a strong pullup during conversion, see "Powering the DS18B20" in the datasheet. | ||
| 4 | //! For externally powered sensors, use the pio_onewire.rs example. | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::peripherals::PIO0; | ||
| 12 | use embassy_rp::pio::{InterruptHandler, Pio}; | ||
| 13 | use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch}; | ||
| 14 | use embassy_time::Duration; | ||
| 15 | use heapless::Vec; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 20 | }); | ||
| 21 | |||
| 22 | #[embassy_executor::main] | ||
| 23 | async fn main(_spawner: Spawner) { | ||
| 24 | let p = embassy_rp::init(Default::default()); | ||
| 25 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 26 | |||
| 27 | let prg = PioOneWireProgram::new(&mut pio.common); | ||
| 28 | let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); | ||
| 29 | |||
| 30 | info!("Starting onewire search"); | ||
| 31 | |||
| 32 | let mut devices = Vec::<u64, 10>::new(); | ||
| 33 | let mut search = PioOneWireSearch::new(); | ||
| 34 | for _ in 0..10 { | ||
| 35 | if !search.is_finished() { | ||
| 36 | if let Some(address) = search.next(&mut onewire).await { | ||
| 37 | if crc8(&address.to_le_bytes()) == 0 { | ||
| 38 | info!("Found address: {:x}", address); | ||
| 39 | let _ = devices.push(address); | ||
| 40 | } else { | ||
| 41 | warn!("Found invalid address: {:x}", address); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | info!("Search done, found {} devices", devices.len()); | ||
| 48 | |||
| 49 | loop { | ||
| 50 | // Read all devices one by one | ||
| 51 | for device in &devices { | ||
| 52 | onewire.reset().await; | ||
| 53 | onewire.write_bytes(&[0x55]).await; // Match rom | ||
| 54 | onewire.write_bytes(&device.to_le_bytes()).await; | ||
| 55 | // 750 ms delay required for default 12-bit resolution. | ||
| 56 | onewire.write_bytes_pullup(&[0x44], Duration::from_millis(750)).await; | ||
| 57 | |||
| 58 | onewire.reset().await; | ||
| 59 | onewire.write_bytes(&[0x55]).await; // Match rom | ||
| 60 | onewire.write_bytes(&device.to_le_bytes()).await; | ||
| 61 | onewire.write_bytes(&[0xBE]).await; // Read scratchpad | ||
| 62 | |||
| 63 | let mut data = [0; 9]; | ||
| 64 | onewire.read_bytes(&mut data).await; | ||
| 65 | if crc8(&data) == 0 { | ||
| 66 | let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; | ||
| 67 | info!("Read device {:x}: {} deg C", device, temp); | ||
| 68 | } else { | ||
| 69 | warn!("Reading device {:x} failed. {:02x}", device, data); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | fn crc8(data: &[u8]) -> u8 { | ||
| 76 | let mut crc = 0; | ||
| 77 | for b in data { | ||
| 78 | let mut data_byte = *b; | ||
| 79 | for _ in 0..8 { | ||
| 80 | let temp = (crc ^ data_byte) & 0x01; | ||
| 81 | crc >>= 1; | ||
| 82 | if temp != 0 { | ||
| 83 | crc ^= 0x8C; | ||
| 84 | } | ||
| 85 | data_byte >>= 1; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | crc | ||
| 89 | } | ||
