aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/src/bin/pio_onewire.rs155
1 files changed, 155 insertions, 0 deletions
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs
new file mode 100644
index 000000000..5076101ec
--- /dev/null
+++ b/examples/rp/src/bin/pio_onewire.rs
@@ -0,0 +1,155 @@
1//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor.
2
3#![no_std]
4#![no_main]
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0;
9use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 PIO0_IRQ_0 => InterruptHandler<PIO0>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 let mut pio = Pio::new(p.PIO0, Irqs);
21 let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2);
22
23 loop {
24 sensor.start().await; // Start a new measurement
25 Timer::after_secs(1).await; // Allow 1s for the measurement to finish
26 match sensor.temperature().await {
27 Ok(temp) => info!("temp = {:?} deg C", temp),
28 _ => error!("sensor error"),
29 }
30 Timer::after_secs(1).await;
31 }
32}
33
34/// DS18B20 temperature sensor driver
35pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
36 sm: StateMachine<'d, PIO, SM>,
37}
38
39impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> {
40 /// Create a new instance the driver
41 pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self {
42 let prg = pio_proc::pio_asm!(
43 r#"
44 .wrap_target
45 again:
46 pull block
47 mov x, osr
48 jmp !x, read
49 write:
50 set pindirs, 1
51 set pins, 0
52 loop1:
53 jmp x--,loop1
54 set pindirs, 0 [31]
55 wait 1 pin 0 [31]
56 pull block
57 mov x, osr
58 bytes1:
59 pull block
60 set y, 7
61 set pindirs, 1
62 bit1:
63 set pins, 0 [1]
64 out pins,1 [31]
65 set pins, 1 [20]
66 jmp y--,bit1
67 jmp x--,bytes1
68 set pindirs, 0 [31]
69 jmp again
70 read:
71 pull block
72 mov x, osr
73 bytes2:
74 set y, 7
75 bit2:
76 set pindirs, 1
77 set pins, 0 [1]
78 set pindirs, 0 [5]
79 in pins,1 [10]
80 jmp y--,bit2
81 jmp x--,bytes2
82 .wrap
83 "#,
84 );
85
86 let pin = common.make_pio_pin(pin);
87 let mut cfg = Config::default();
88 cfg.use_program(&common.load_program(&prg.program), &[]);
89 cfg.set_out_pins(&[&pin]);
90 cfg.set_in_pins(&[&pin]);
91 cfg.set_set_pins(&[&pin]);
92 cfg.shift_in = ShiftConfig {
93 auto_fill: true,
94 direction: ShiftDirection::Right,
95 threshold: 8,
96 };
97 cfg.clock_divider = 255_u8.into();
98 sm.set_config(&cfg);
99 sm.set_enable(true);
100 Self { sm }
101 }
102
103 /// Write bytes over the wire
104 async fn write_bytes(&mut self, bytes: &[u8]) {
105 self.sm.tx().wait_push(250).await;
106 self.sm.tx().wait_push(bytes.len() as u32 - 1).await;
107 for b in bytes {
108 self.sm.tx().wait_push(*b as u32).await;
109 }
110 }
111
112 /// Read bytes from the wire
113 async fn read_bytes(&mut self, bytes: &mut [u8]) {
114 self.sm.tx().wait_push(0).await;
115 self.sm.tx().wait_push(bytes.len() as u32 - 1).await;
116 for b in bytes.iter_mut() {
117 *b = (self.sm.rx().wait_pull().await >> 24) as u8;
118 }
119 }
120
121 /// Calculate CRC8 of the data
122 fn crc8(data: &[u8]) -> u8 {
123 let mut temp;
124 let mut data_byte;
125 let mut crc = 0;
126 for b in data {
127 data_byte = *b;
128 for _ in 0..8 {
129 temp = (crc ^ data_byte) & 0x01;
130 crc >>= 1;
131 if temp != 0 {
132 crc ^= 0x8C;
133 }
134 data_byte >>= 1;
135 }
136 }
137 crc
138 }
139
140 /// Start a new measurement. Allow at least 1000ms before getting `temperature`.
141 pub async fn start(&mut self) {
142 self.write_bytes(&[0xCC, 0x44]).await;
143 }
144
145 /// Read the temperature. Ensure >1000ms has passed since `start` before calling this.
146 pub async fn temperature(&mut self) -> Result<f32, ()> {
147 self.write_bytes(&[0xCC, 0xBE]).await;
148 let mut data = [0; 9];
149 self.read_bytes(&mut data).await;
150 match Self::crc8(&data) == 0 {
151 true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.),
152 false => Err(()),
153 }
154 }
155}