Commit 97709724 authored by Michael Watzko's avatar Michael Watzko
Browse files

Include AM2302, fix it and use MonoTimer (to be replaced by CountDown-timer)

parent df935ef8
......@@ -12,7 +12,7 @@
[package]
name = "bluepill_sensor"
version = "0.3.3"
version = "0.3.4"
authors = ["Michael Watzko <michael@watzko.de>"]
description = "Stm32f103/Bluepill with W5500 ethernet chip, OneWire interface and sensor_common communication"
keywords = ["arm", "cortex-m", "onewire", "ethernet"]
......@@ -61,9 +61,6 @@ path = "../pcd8544"
[dependencies.sensor_common]
path = "../sensor_common"
[dependencies.am2302]
path = "../am2302"
[dependencies.stm32f103xx-hal]
version = "0.1.0"
path = "../stm32f103xx-hal"
......
use stm32f103xx_hal;
use core::f32;
use embedded_hal::digital::OutputPin;
use embedded_hal::digital::InputPin;
use embedded_hal::blocking::delay::DelayUs;
use embedded_hal::timer::CountDown;
use stm32f103xx_hal::time::Instant;
use stm32f103xx_hal::time::MonoTimer;
use stm32f103xx_hal::time::Hertz;
pub trait OpenDrainOutput: OutputPin + InputPin {}
impl<P: OutputPin + InputPin> OpenDrainOutput for P {}
pub struct Am2302<'a> {
pin: &'a mut OpenDrainOutput,
timer: &'a MonoTimer,
}
impl<'a> Am2302<'a> {
pub fn new(pin: &'a mut OpenDrainOutput, timer: &'a MonoTimer) -> Am2302<'a> {
pin.set_high();
Am2302 {
pin,
timer,
}
}
pub fn read(&mut self) -> Result<ReadValue, Error> {
match self.read_set() {
Ok(raw) => {
self.pin.set_high();
Ok(Self::parse(raw)?)
}
Err(e) => {
self.pin.set_high();
Err(e)
}
}
}
fn parse(buffer: [u8; 5]) -> Result<ReadValue, Error> {
if buffer[0] + buffer[1] + buffer[2] + buffer[3] != buffer[4] {
return Err(Error::Crc);
}
Ok(ReadValue {
humidity: ((buffer[0] as u16) << 8 | buffer[1] as u16) as f32 * 0.1_f32,
temperature: ((buffer[2] as u16) << 8 | buffer[3] as u16) as f32 * 0.1_f32,
})
}
fn read_set(&mut self) -> Result<[u8; 5], Error> {
self.pin.set_low();
//delay.delay_us(5_000);
let start = self.timer.now();
// pull low 'beyond at least 1~10ms'
while start.elapsed() < 5_000 as u32 * (self.timer.frequency().0 / 1_000_000) {
}
self.pin.set_high();
// sensor pulls down after 20-40us
self.expect_low_within(45)?;
// sensor should pull up after 80us
self.expect_high_within(85)?;
// sensor should pull low after 80us
self.expect_low_within(85)?;
let mut buffer = [0u8; 5];
for i in 0..buffer.len() * 8 {
// sensor should keep low for 50us
self.expect_high_within(70)?;
// if sensor pulls low after 26us-28us it sends a 0 bit
if self.expect_low_within(30).is_ok() {
// 0 bit
} else {
// not low, so a 1 bit is sent
buffer[i / 8] |= (1 << 7 - (i % 8)) as u8;
// high in total 70us
self.expect_low_within(40)?;
}
}
Ok(buffer)
}
fn expect_high_within(&self, timeout: u16) -> Result<(), Error> {
if self.wait_for(true, timeout) {
Ok(())
} else {
Err(Error::NotHighWithin(timeout))
}
}
fn expect_low_within(&self, timeout: u16) -> Result<(), Error> {
if self.wait_for(false, timeout) {
Ok(())
} else {
Err(Error::NotLowWithin(timeout))
}
}
fn wait_for(&self, state: bool, timeout: u16) -> bool {
// 1us is nearly nothing for a 8MHz chip (8 clock ticks = 1us),
// so step in 10us to reduce relative overhead an keep somehow
// near the requested timeout
// TODO MonoTimer?
let now = self.timer.now();
while now.elapsed() <= timeout as u32 * (self.timer.frequency().0 / 1_000_000) {
if self.pin.is_high() == state {
return true;
}
}
return false;
}
}
pub struct ReadValue {
pub humidity: f32,
pub temperature: f32,
}
pub enum Error {
Crc,
NotHighWithin(u16),
NotLowWithin(u16),
}
\ No newline at end of file
......@@ -18,12 +18,12 @@ extern crate byteorder;
#[macro_use(block)]
extern crate nb;
extern crate am2302;
extern crate onewire;
extern crate pcd8544;
extern crate sensor_common;
extern crate w5500;
mod am2302;
mod ds93c46;
mod platform;
......@@ -98,6 +98,10 @@ pub fn main() -> ! {
let mut gpiob = peripherals.GPIOB.split(&mut rcc.apb2);
let mut gpioc = peripherals.GPIOC.split(&mut rcc.apb2);
let mut led_red = gpioa.pa1.into_push_pull_output(&mut gpioa.crl);
let mut led_yellow = gpioa.pa2.into_push_pull_output(&mut gpioa.crl);
let mut led_blue = gpioa.pa3.into_push_pull_output(&mut gpioa.crl);
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); //.into_push_pull_output(&mut gpioc.crh);//.into_floating_input().is_high();
let mut one = gpioc
.pc15
......@@ -151,18 +155,21 @@ pub fn main() -> ! {
&mut rcc.apb2,
);
let timer = ::stm32f103xx_hal::time::MonoTimer::new(cp.DWT, clocks);
// let countdown = ::stm32f103xx_hal::timer::Timer::syst(cp.SYST, 1.hz(), clocks);
let information = DeviceInformation::new(&timer, cp.CPUID.base.read());
let mut am2302 = gpiob.pb9.into_open_drain_output(&mut gpiob.crh);
let mut w5500 = W5500::new(&mut spi, &mut cs_w5500);
let mut ds93c46 = DS93C46::new(&mut cs_eeprom);
let mut am2302 = Am2302::new(&mut am2302);
let mut am2302 = Am2302::new(&mut am2302, &timer);
let mut wire = OneWire::new(&mut one, false);
let timer = ::stm32f103xx_hal::time::MonoTimer::new(cp.DWT, clocks);
let mut platform = Platform {
information: DeviceInformation::new(&timer, cp.CPUID.base.read()),
information,
delay: &mut delay,
onewire: &mut wire,
......@@ -204,7 +211,7 @@ pub fn main() -> ! {
}
}
match handle_udp_requests(&mut platform, &mut [0u8; 2048]) {
match handle_udp_requests(&mut platform, &mut [0u8; 2048], &mut led_red, &mut led_yellow, &mut led_blue) {
Err(e) => {
// writeln!(display, "Error:");
// writeln!(display, "{:?}", e);
......@@ -224,6 +231,9 @@ pub fn main() -> ! {
fn handle_udp_requests(
platform: &mut Platform,
buffer: &mut [u8],
led_red: &mut OutputPin,
led_yellow: &mut OutputPin,
led_blue: &mut OutputPin,
) -> Result<Option<(IpAddress, u16)>, HandleError> {
if let Some((ip, port, size)) = platform.receive_udp(buffer)? {
let (whole_request_buffer, response_buffer) = buffer.split_at_mut(size);
......@@ -257,6 +267,9 @@ fn handle_udp_requests(
platform.spi,
request_content_buffer,
writer,
led_red,
led_yellow,
led_blue,
)?;
available - writer.available()
......@@ -289,6 +302,9 @@ fn handle_udp_requests_legacy(
spi: &mut FullDuplex<u8, Error=spi::Error>,
request_content_buffer: &[u8],
writer: &mut ::sensor_common::Write,
led_red: &mut OutputPin,
led_yellow: &mut OutputPin,
led_blue: &mut OutputPin,
) -> Result<bool, HandleError> {
let mut reset = false;
......@@ -301,17 +317,33 @@ fn handle_udp_requests_legacy(
Request::ReadSpecified(id, Bus::Custom(bus)) => {
match bus {
0x01 => { // am2302
if let Ok(value) = am2302.read(delay) {
Response::Ok(id, Format::ValueOnly(Type::F32)).write(writer)?;
let mut buffer = [0u8; 4];
NetworkEndian::write_f32(&mut buffer[..], value.humidity);
writer.write_all(&buffer[..]);
NetworkEndian::write_f32(&mut buffer[..], value.temperature);
writer.write_all(&buffer[..]);
} else {
Response::NotAvailable(id).write(writer)?;
led_red.set_low();
led_yellow.set_low();
led_blue.set_low();
match am2302.read() {
Ok(value) => {
Response::Ok(id, Format::ValueOnly(Type::F32)).write(writer)?;
let mut buffer = [0u8; 4];
NetworkEndian::write_f32(&mut buffer[..], value.humidity);
writer.write_all(&buffer[..]);
NetworkEndian::write_f32(&mut buffer[..], value.temperature);
writer.write_all(&buffer[..]);
}
Err(e) => {
Response::NotAvailable(id).write(writer)?;
match e {
::am2302::Error::Crc => led_red.set_high(),
::am2302::Error::NotHighWithin(time) => {
led_yellow.set_high();
writer.write_u8(time as u8)?;
},
::am2302::Error::NotLowWithin(time) => {
led_blue.set_high();
writer.write_u8(time as u8)?;
},
}
}
}
},
_ => {
Response::NotImplemented(id).write(writer)?;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment