|
|
@ -33,7 +33,7 @@ use hal::{
|
|
|
|
},
|
|
|
|
},
|
|
|
|
pac::I2C1,
|
|
|
|
pac::I2C1,
|
|
|
|
prelude::*,
|
|
|
|
prelude::*,
|
|
|
|
timer::{Alarm, Alarm0, Alarm1},
|
|
|
|
timer::{Alarm, Alarm0, Alarm1, Alarm2},
|
|
|
|
Adc,
|
|
|
|
Adc,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -44,8 +44,8 @@ const HEAP_SIZE: usize = 1024;
|
|
|
|
|
|
|
|
|
|
|
|
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
|
|
|
|
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
|
|
|
|
const MVG_AVG_COUNT: u16 = 20;
|
|
|
|
const MVG_AVG_COUNT: u16 = 20;
|
|
|
|
const DISPLAY_UPDATE_INT_TICKS: u32 = 500_000;
|
|
|
|
const DISPLAY_UPDATE_INT_TICKS: u32 = 2_000_000;
|
|
|
|
const SENSOR_READ_INT_TICKS: u32 = 50_000;
|
|
|
|
const SENSOR_READ_INT_TICKS: u32 = 1_000_000;
|
|
|
|
const AIR_QUALITY_THRESHOLD: u16 = 480;
|
|
|
|
const AIR_QUALITY_THRESHOLD: u16 = 480;
|
|
|
|
const AIR_QUALITY_THRESHOLD_LOWER: u16 = 400;
|
|
|
|
const AIR_QUALITY_THRESHOLD_LOWER: u16 = 400;
|
|
|
|
|
|
|
|
|
|
|
@ -72,8 +72,8 @@ mod app {
|
|
|
|
struct Shared {
|
|
|
|
struct Shared {
|
|
|
|
alarm0: Alarm0,
|
|
|
|
alarm0: Alarm0,
|
|
|
|
alarm1: Alarm1,
|
|
|
|
alarm1: Alarm1,
|
|
|
|
|
|
|
|
alarm2: Alarm2,
|
|
|
|
sensor_value: u16,
|
|
|
|
sensor_value: u16,
|
|
|
|
led: LED,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[local]
|
|
|
|
#[local]
|
|
|
@ -83,6 +83,8 @@ mod app {
|
|
|
|
adc_pin: Pin<hal::gpio::bank0::Gpio29, hal::gpio::FloatingInput>,
|
|
|
|
adc_pin: Pin<hal::gpio::bank0::Gpio29, hal::gpio::FloatingInput>,
|
|
|
|
watchdog: hal::Watchdog,
|
|
|
|
watchdog: hal::Watchdog,
|
|
|
|
use_lower_limit: bool,
|
|
|
|
use_lower_limit: bool,
|
|
|
|
|
|
|
|
led: LED,
|
|
|
|
|
|
|
|
led_color: smart_leds::RGB<u8>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[init()]
|
|
|
|
#[init()]
|
|
|
@ -121,6 +123,10 @@ mod app {
|
|
|
|
let _ = alarm1.schedule(MicrosDurationU32::from_ticks(SENSOR_READ_INT_TICKS));
|
|
|
|
let _ = alarm1.schedule(MicrosDurationU32::from_ticks(SENSOR_READ_INT_TICKS));
|
|
|
|
alarm1.enable_interrupt();
|
|
|
|
alarm1.enable_interrupt();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut alarm2 = timer.alarm_2().unwrap();
|
|
|
|
|
|
|
|
let _ = alarm2.schedule(MicrosDurationU32::from_ticks(DISPLAY_UPDATE_INT_TICKS));
|
|
|
|
|
|
|
|
alarm2.enable_interrupt();
|
|
|
|
|
|
|
|
|
|
|
|
let (mut pio, sm0, _, _, _) = c.device.PIO0.split(&mut resets);
|
|
|
|
let (mut pio, sm0, _, _, _) = c.device.PIO0.split(&mut resets);
|
|
|
|
let mut led = ws2812_pio::Ws2812::new(
|
|
|
|
let mut led = ws2812_pio::Ws2812::new(
|
|
|
|
pins.gpio16.into_mode(),
|
|
|
|
pins.gpio16.into_mode(),
|
|
|
@ -130,8 +136,6 @@ mod app {
|
|
|
|
unsafe { core::mem::transmute(timer.count_down()) },
|
|
|
|
unsafe { core::mem::transmute(timer.count_down()) },
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
led.write([RGB8::new(255, 255, 0)].iter().copied()).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let scl = pins.gpio15.into_mode();
|
|
|
|
let scl = pins.gpio15.into_mode();
|
|
|
|
let sda = pins.gpio14.into_mode();
|
|
|
|
let sda = pins.gpio14.into_mode();
|
|
|
|
let i2c = i2c::I2C::i2c1(
|
|
|
|
let i2c = i2c::I2C::i2c1(
|
|
|
@ -152,8 +156,8 @@ mod app {
|
|
|
|
Shared {
|
|
|
|
Shared {
|
|
|
|
alarm0,
|
|
|
|
alarm0,
|
|
|
|
alarm1,
|
|
|
|
alarm1,
|
|
|
|
|
|
|
|
alarm2,
|
|
|
|
sensor_value: adc.read(&mut adc_pin).unwrap(),
|
|
|
|
sensor_value: adc.read(&mut adc_pin).unwrap(),
|
|
|
|
led,
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Local {
|
|
|
|
Local {
|
|
|
|
display,
|
|
|
|
display,
|
|
|
@ -161,6 +165,8 @@ mod app {
|
|
|
|
adc_pin,
|
|
|
|
adc_pin,
|
|
|
|
watchdog,
|
|
|
|
watchdog,
|
|
|
|
use_lower_limit: false,
|
|
|
|
use_lower_limit: false,
|
|
|
|
|
|
|
|
led,
|
|
|
|
|
|
|
|
led_color: RGB8::new(255, 255, 255),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
init::Monotonics(),
|
|
|
|
init::Monotonics(),
|
|
|
|
)
|
|
|
|
)
|
|
|
@ -197,7 +203,7 @@ mod app {
|
|
|
|
let text = c.shared.sensor_value.lock(|val| format!("{val}"));
|
|
|
|
let text = c.shared.sensor_value.lock(|val| format!("{val}"));
|
|
|
|
|
|
|
|
|
|
|
|
let display = c.local.display;
|
|
|
|
let display = c.local.display;
|
|
|
|
display.clear();
|
|
|
|
display.clear(BinaryColor::Off).unwrap();
|
|
|
|
Text::with_alignment(
|
|
|
|
Text::with_alignment(
|
|
|
|
&text,
|
|
|
|
&text,
|
|
|
|
display.bounding_box().center(),
|
|
|
|
display.bounding_box().center(),
|
|
|
@ -214,14 +220,24 @@ mod app {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[task(binds = TIMER_IRQ_1, priority = 2, shared = [alarm1, sensor_value, led], local = [adc, adc_pin, watchdog, use_lower_limit])]
|
|
|
|
#[task(binds = TIMER_IRQ_1, priority = 2, shared = [alarm1, sensor_value], local = [adc, adc_pin, watchdog])]
|
|
|
|
fn read_sensor(mut c: read_sensor::Context) {
|
|
|
|
fn read_sensor(mut c: read_sensor::Context) {
|
|
|
|
let mut sensor_value: u16 = c.local.adc.read(c.local.adc_pin).unwrap();
|
|
|
|
let sensor_value: u16 = c.local.adc.read(c.local.adc_pin).unwrap();
|
|
|
|
sensor_value = c.shared.sensor_value.lock(|v| {
|
|
|
|
c.shared.sensor_value.lock(|v| {
|
|
|
|
*v = (*v * (MVG_AVG_COUNT - 1) + sensor_value) / MVG_AVG_COUNT;
|
|
|
|
*v = (*v * (MVG_AVG_COUNT - 1) + sensor_value) / MVG_AVG_COUNT;
|
|
|
|
*v
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
c.local.watchdog.feed();
|
|
|
|
|
|
|
|
c.shared.alarm1.lock(|a| {
|
|
|
|
|
|
|
|
a.clear_interrupt();
|
|
|
|
|
|
|
|
let _ = a.schedule(MicrosDurationU32::from_ticks(DISPLAY_UPDATE_INT_TICKS));
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[task(binds=TIMER_IRQ_2, priority = 1, shared = [alarm2, sensor_value], local = [led, led_color, use_lower_limit])]
|
|
|
|
|
|
|
|
fn update_led(mut c: update_led::Context) {
|
|
|
|
|
|
|
|
let sensor_value = c.shared.sensor_value.lock(|v| *v);
|
|
|
|
|
|
|
|
|
|
|
|
if sensor_value >= AIR_QUALITY_THRESHOLD {
|
|
|
|
if sensor_value >= AIR_QUALITY_THRESHOLD {
|
|
|
|
*c.local.use_lower_limit = true;
|
|
|
|
*c.local.use_lower_limit = true;
|
|
|
|
} else if sensor_value < AIR_QUALITY_THRESHOLD_LOWER && *c.local.use_lower_limit {
|
|
|
|
} else if sensor_value < AIR_QUALITY_THRESHOLD_LOWER && *c.local.use_lower_limit {
|
|
|
@ -237,12 +253,12 @@ mod app {
|
|
|
|
AIR_QUALITY_THRESHOLD.. => RGB8::new(0, 255, 0),
|
|
|
|
AIR_QUALITY_THRESHOLD.. => RGB8::new(0, 255, 0),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
c.shared.led.lock(|l| {
|
|
|
|
if *c.local.led_color != color {
|
|
|
|
l.write([color].iter().cloned()).unwrap();
|
|
|
|
c.local.led.write([color].iter().cloned()).unwrap();
|
|
|
|
});
|
|
|
|
*c.local.led_color = color;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.local.watchdog.feed();
|
|
|
|
c.shared.alarm2.lock(|a| {
|
|
|
|
c.shared.alarm1.lock(|a| {
|
|
|
|
|
|
|
|
a.clear_interrupt();
|
|
|
|
a.clear_interrupt();
|
|
|
|
let _ = a.schedule(MicrosDurationU32::from_ticks(DISPLAY_UPDATE_INT_TICKS));
|
|
|
|
let _ = a.schedule(MicrosDurationU32::from_ticks(DISPLAY_UPDATE_INT_TICKS));
|
|
|
|
});
|
|
|
|
});
|
|
|
|