rs-dht-pio/src/lib.rs

116 lines
3 KiB
Rust
Raw Normal View History

2023-09-08 21:09:15 +00:00
#![no_std]
use cortex_m::delay::Delay;
use pio_proc::pio_file;
use rp2040_hal::gpio::AnyPin;
use rp2040_hal::pio::{PIOExt, Running, StateMachine, StateMachineIndex, Tx};
use rp2040_hal::pio::{Rx, UninitStateMachine};
#[derive(Debug)]
pub enum DhtError {
/// Timeout during communication.
Timeout,
/// CRC mismatch.
2023-09-09 19:41:19 +00:00
CrcMismatch(u32, u32),
2023-09-08 21:13:58 +00:00
/// FIFO Read error
ReadError,
2023-09-08 21:09:15 +00:00
}
#[derive(Debug)]
pub struct DhtResult {
pub temperature: f32,
pub humidity: f32,
}
2023-09-09 19:41:19 +00:00
pub struct DhtPio<P: PIOExt, STI: StateMachineIndex> {
2023-09-08 21:09:15 +00:00
// sm: PicoStateMachine<P, STI>,
sm: StateMachine<(P, STI), Running>,
rx_fifo: Rx<(P, STI)>,
tx_fifo: Tx<(P, STI)>,
}
2023-09-09 19:41:19 +00:00
impl<P: PIOExt, STI: StateMachineIndex> DhtPio<P, STI> {
2023-09-08 21:09:15 +00:00
pub fn new<I: AnyPin<Function = P::PinFunction>>(
mut pio: rp2040_hal::pio::PIO<P>,
sm: UninitStateMachine<(P, STI)>,
dht_pin: I,
) -> Self {
let program = pio_file!("./src/dht.pio");
let pin = dht_pin.into();
let installed = pio.install(&program.program).unwrap();
let (int, frac) = (125, 0);
let (mut sm, rx, tx) = rp2040_hal::pio::PIOBuilder::from_program(installed)
.set_pins(pin.id().num, 1)
.clock_divisor_fixed_point(int, frac)
2023-09-09 19:41:19 +00:00
.push_threshold(32)
2023-09-08 21:09:15 +00:00
.build(sm);
sm.set_pindirs([(pin.id().num, rp2040_hal::pio::PinDir::Output)]);
Self {
sm: sm.start(),
rx_fifo: rx,
tx_fifo: tx,
}
}
2023-09-08 21:13:58 +00:00
/// Read data from the sensor. This blocking function (for maximum timeout of 2 seconds).
2023-09-08 21:09:15 +00:00
pub fn read_data(&mut self, delay: &mut Delay) -> Result<DhtResult, DhtError> {
let mut timeout = 2000;
2023-09-09 19:41:19 +00:00
let mut raw: [Option<u32>; 2] = [None; 2];
2023-09-08 21:09:15 +00:00
self.tx_fifo.write(1);
2023-09-09 19:41:19 +00:00
while timeout > 0 && raw[1].is_none() {
match self.rx_fifo.read() {
Some(d) => {
if raw[0].is_none() {
raw[0] = Some(d);
} else {
raw[1] = Some(d);
}
}
None => (),
}
2023-09-08 21:09:15 +00:00
delay.delay_ms(1);
timeout -= 1;
}
if timeout <= 0 {
self.sm.restart();
return Err(DhtError::Timeout);
}
2023-09-09 19:41:19 +00:00
let data = raw[0].unwrap();
let crc = raw[1].unwrap();
if Self::compute_crc(data) != crc {
return Err(DhtError::CrcMismatch(
raw[0].unwrap_or(0),
raw[1].unwrap_or(0),
));
}
2023-09-08 21:09:15 +00:00
2023-09-09 19:41:19 +00:00
let t_raw = data & 0x0000FFFF;
let h_raw = (data & 0xFFFF0000) >> 16;
2023-09-08 21:09:15 +00:00
Ok(DhtResult {
temperature: t_raw as f32 / 10.0,
humidity: h_raw as f32 / 10.0,
})
}
2023-09-09 19:41:19 +00:00
fn compute_crc(data: u32) -> u32 {
let mut crc: u32 = 0;
crc += data & 0x000000FF;
crc += (data & 0x0000FF00) >> 8;
crc += (data & 0x00FF0000) >> 16;
crc += (data & 0xFF000000) >> 24;
crc % 256
}
2023-09-08 21:09:15 +00:00
}