Improve line graph drawing function & begin input handling
This commit is contained in:
parent
219e43fee8
commit
3255976961
@ -1,11 +1,3 @@
|
||||
[alias]
|
||||
|
||||
build-arm = "build --target=thumbv8m.main-none-eabihf"
|
||||
build-riscv = "build --target=riscv32imac-unknown-none-elf"
|
||||
|
||||
run-arm = "run --target=thumbv8m.main-none-eabihf"
|
||||
run-riscv = "run --target=riscv32imac-unknown-none-elf"
|
||||
|
||||
[build]
|
||||
target = "thumbv8m.main-none-eabihf"
|
||||
|
||||
@ -18,10 +10,8 @@ rustflags = [
|
||||
"-C",
|
||||
"target-cpu=cortex-m33",
|
||||
]
|
||||
|
||||
runner = "picotool load -u -v -x -t elf"
|
||||
runner = "probe-rs run --chip RP235x"
|
||||
|
||||
[target.riscv32imac-unknown-none-elf]
|
||||
rustflags = ["-C", "link-arg=--nmagic", "-C", "link-arg=-Trp235x_riscv.x"]
|
||||
|
||||
runner = "picotool load -u -v -x -t elf"
|
||||
runner = "probe-rs run --chip RP235x"
|
||||
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -703,15 +703,6 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop"
|
||||
version = "0.19.12"
|
||||
@ -723,7 +714,7 @@ dependencies = [
|
||||
"diff",
|
||||
"ena",
|
||||
"is-terminal",
|
||||
"itertools 0.10.5",
|
||||
"itertools",
|
||||
"lalrpop-util",
|
||||
"petgraph",
|
||||
"regex",
|
||||
@ -896,18 +887,20 @@ name = "pico-enviro-sensor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"circular-buffer",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"display-interface-spi",
|
||||
"embassy-embedded-hal",
|
||||
"embassy-executor",
|
||||
"embassy-futures",
|
||||
"embassy-rp",
|
||||
"embassy-sync",
|
||||
"embassy-time",
|
||||
"embedded-graphics",
|
||||
"embedded-graphics-framebuf",
|
||||
"fixed",
|
||||
"heapless",
|
||||
"itertools 0.14.0",
|
||||
"num-traits",
|
||||
"rtt-target",
|
||||
"scd4x",
|
||||
"ssd1351",
|
||||
@ -1144,7 +1137,8 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
||||
[[package]]
|
||||
name = "scd4x"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/twokilohertz/scd4x-rs.git?branch=conversion-fixes#07730523c51d6909530c000de271832125760385"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "550fedc97e7880654aa7dc840f5eb3b2201a01aae566c4584a3601bb0086cd4c"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0",
|
||||
"log",
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -22,12 +22,14 @@ embassy-executor = { version = "0.7.0", features = [
|
||||
"task-arena-size-65536",
|
||||
] }
|
||||
embassy-time = "0.4.0"
|
||||
embassy-sync = "0.6.2"
|
||||
embassy-embedded-hal = "0.3.0"
|
||||
static_cell = "2.1.0"
|
||||
embassy-futures = "0.1.1"
|
||||
embassy-sync = "0.6.2"
|
||||
|
||||
# System
|
||||
cortex-m-rt = "0.7.5"
|
||||
cortex-m = "0.7.7"
|
||||
critical-section = "1.2.0"
|
||||
rtt-target = "0.6.1"
|
||||
|
||||
# embedded-graphics
|
||||
@ -40,10 +42,10 @@ ssd1351 = "0.5.0"
|
||||
display-interface-spi = "0.5.0"
|
||||
|
||||
# Extra
|
||||
static_cell = "2.1.0"
|
||||
heapless = "0.8.0"
|
||||
circular-buffer = { version = "1.0.0", default-features = false }
|
||||
itertools = { version = "0.14.0", default-features = false }
|
||||
num-traits = { version = "0.2.19", default-features = false }
|
||||
fixed = "1.29.0"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = "s"
|
||||
|
@ -1,3 +1,3 @@
|
||||
export PICO_BOARD=pico2_w
|
||||
export PICO_PLATFORM=rp2350-arm-s
|
||||
export PICO_SDK_PATH=~/devel/clones/pico-sdk/
|
||||
export PICO_SDK_PATH=~/devel/clones/pico-sdk
|
||||
|
@ -1,8 +1,11 @@
|
||||
use core::fmt::Write;
|
||||
|
||||
// System
|
||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
|
||||
use embassy_rp::{gpio::Output, spi::Config};
|
||||
use embedded_graphics_framebuf::FrameBuf;
|
||||
use rtt_target::rprintln;
|
||||
use fixed::types::U16F16;
|
||||
use rtt_target::debug_rprintln;
|
||||
|
||||
// Display
|
||||
use display_interface_spi::SPIInterface;
|
||||
@ -16,9 +19,9 @@ use ssd1351::{
|
||||
use embedded_graphics::{
|
||||
draw_target::DrawTarget,
|
||||
mono_font::{ascii::FONT_6X10, MonoTextStyle},
|
||||
pixelcolor::Rgb565,
|
||||
pixelcolor::{Rgb565, Rgb888},
|
||||
prelude::{Point, Primitive, RgbColor, Size, WebColors},
|
||||
primitives::{Line, PrimitiveStyle, PrimitiveStyleBuilder, Rectangle},
|
||||
primitives::{Line, PrimitiveStyle, Rectangle, StyledDrawable},
|
||||
text::{Alignment, Text, TextStyleBuilder},
|
||||
Drawable,
|
||||
};
|
||||
@ -26,15 +29,13 @@ use embedded_graphics::{
|
||||
// Containers
|
||||
use circular_buffer::CircularBuffer;
|
||||
use heapless::String;
|
||||
use itertools::Itertools;
|
||||
|
||||
use core::fmt::Write;
|
||||
use num_traits::{Num, NumCast};
|
||||
|
||||
use crate::{Spi0BusMutex, SENSOR_DATA_SIGNAL};
|
||||
|
||||
const DISPLAY_WIDTH: usize = 128;
|
||||
const DISPLAY_HEIGHT: usize = 128;
|
||||
const DISPLAY_PADDING: usize = 5;
|
||||
type SensorDataBuffer = CircularBuffer<60, U16F16>;
|
||||
|
||||
/// Output to the SSD1351 display
|
||||
#[embassy_executor::task]
|
||||
@ -45,7 +46,7 @@ pub async fn display_output_task(
|
||||
rst: &'static mut Output<'static>,
|
||||
spi_config: Config,
|
||||
) {
|
||||
rprintln!("Display output task started");
|
||||
debug_rprintln!("Display output task started");
|
||||
|
||||
let spi_dev = SpiDeviceWithConfig::new(spi_bus, cs, spi_config);
|
||||
let interface = SPIInterface::new(spi_dev, dc);
|
||||
@ -73,14 +74,14 @@ pub async fn display_output_task(
|
||||
let humidity_text_style = MonoTextStyle::new(&FONT_6X10, Rgb565::CSS_AQUAMARINE);
|
||||
|
||||
// Format string buffers
|
||||
let mut co2_text_buf = String::<16>::new();
|
||||
let mut temp_text_buf = String::<16>::new();
|
||||
let mut humidity_text_buf = String::<16>::new();
|
||||
let mut co2_text_buf = String::<20>::new();
|
||||
let mut temp_text_buf = String::<20>::new();
|
||||
let mut humidity_text_buf = String::<20>::new();
|
||||
|
||||
// Ring buffer for storing past measurement data
|
||||
let mut co2_samples = CircularBuffer::<60, u16>::new();
|
||||
let mut temp_samples = CircularBuffer::<60, f32>::new();
|
||||
let mut humidity_samples = CircularBuffer::<60, f32>::new();
|
||||
let mut co2_samples = SensorDataBuffer::new();
|
||||
let mut temp_samples = SensorDataBuffer::new();
|
||||
let mut humidity_samples = SensorDataBuffer::new();
|
||||
|
||||
loop {
|
||||
// Clear the framebuffer
|
||||
@ -98,28 +99,19 @@ pub async fn display_output_task(
|
||||
write!(&mut humidity_text_buf, "RH: {:.1} %", sensor_data.humidity).unwrap();
|
||||
|
||||
// Record samples
|
||||
co2_samples.push_back(sensor_data.co2);
|
||||
temp_samples.push_back(sensor_data.temperature);
|
||||
humidity_samples.push_back(sensor_data.humidity);
|
||||
co2_samples.push_back(U16F16::from_num(sensor_data.co2));
|
||||
temp_samples.push_back(U16F16::from_num(sensor_data.temperature));
|
||||
humidity_samples.push_back(U16F16::from_num(sensor_data.humidity));
|
||||
co2_samples.make_contiguous();
|
||||
temp_samples.make_contiguous();
|
||||
humidity_samples.make_contiguous();
|
||||
|
||||
let co2_min = *co2_samples.iter().min().unwrap();
|
||||
let co2_max = *co2_samples.iter().max().unwrap();
|
||||
let temp_min = *temp_samples
|
||||
.iter()
|
||||
.reduce(|a: &f32, b: &f32| if a.le(b) { a } else { b })
|
||||
.unwrap();
|
||||
let temp_max = *temp_samples
|
||||
.iter()
|
||||
.reduce(|a: &f32, b: &f32| if a.ge(b) { a } else { b })
|
||||
.unwrap();
|
||||
let humid_min = *humidity_samples
|
||||
.iter()
|
||||
.reduce(|a: &f32, b: &f32| if a.le(b) { a } else { b })
|
||||
.unwrap();
|
||||
let humid_max = *humidity_samples
|
||||
.iter()
|
||||
.reduce(|a: &f32, b: &f32| if a.ge(b) { a } else { b })
|
||||
.unwrap();
|
||||
let temp_min = *temp_samples.iter().min().unwrap();
|
||||
let temp_max = *temp_samples.iter().max().unwrap();
|
||||
let humid_min = *humidity_samples.iter().min().unwrap();
|
||||
let humid_max = *humidity_samples.iter().max().unwrap();
|
||||
|
||||
/*
|
||||
Note about drawing positions:
|
||||
@ -130,44 +122,53 @@ pub async fn display_output_task(
|
||||
|
||||
// Draw line graphs
|
||||
|
||||
if co2_samples.len() >= 2 {
|
||||
draw_line_graph(
|
||||
&co2_samples,
|
||||
co2_max.into(),
|
||||
co2_min.into(),
|
||||
4,
|
||||
Rgb565::CSS_DARK_GREEN,
|
||||
Some(Rgb565::new(3, 5, 3)),
|
||||
&mut framebuf,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
const LINE_GRAPH_WIDTH: u32 = (DISPLAY_WIDTH - (DISPLAY_PADDING * 2)) as u32;
|
||||
const LINE_GRAPH_HEIGHT: u32 = 36;
|
||||
|
||||
if temp_samples.len() >= 2 {
|
||||
draw_line_graph(
|
||||
&temp_samples,
|
||||
temp_max as i32,
|
||||
temp_min as i32,
|
||||
38,
|
||||
Rgb565::CSS_ORANGE,
|
||||
Some(Rgb565::new(3, 5, 3)),
|
||||
&mut framebuf,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
draw_line_graph(
|
||||
Rectangle::new(
|
||||
Point::new(DISPLAY_PADDING as i32, DISPLAY_PADDING as i32),
|
||||
Size::new(LINE_GRAPH_WIDTH, LINE_GRAPH_HEIGHT),
|
||||
),
|
||||
co2_min,
|
||||
co2_max,
|
||||
co2_samples.as_slices().0,
|
||||
Rgb565::CSS_DARK_GREEN,
|
||||
Some(Rgb888::new(24, 24, 24).into()),
|
||||
&mut framebuf,
|
||||
);
|
||||
|
||||
if humidity_samples.len() >= 2 {
|
||||
draw_line_graph(
|
||||
&humidity_samples,
|
||||
humid_max as i32,
|
||||
humid_min as i32,
|
||||
72,
|
||||
Rgb565::CSS_AQUA,
|
||||
Some(Rgb565::new(3, 5, 3)),
|
||||
&mut framebuf,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
draw_line_graph(
|
||||
Rectangle::new(
|
||||
Point::new(
|
||||
DISPLAY_PADDING as i32,
|
||||
(LINE_GRAPH_HEIGHT + (DISPLAY_PADDING as u32 * 2)) as i32,
|
||||
),
|
||||
Size::new(LINE_GRAPH_WIDTH, LINE_GRAPH_HEIGHT),
|
||||
),
|
||||
temp_min,
|
||||
temp_max,
|
||||
temp_samples.as_slices().0,
|
||||
Rgb565::CSS_ORANGE,
|
||||
Some(Rgb888::new(24, 24, 24).into()),
|
||||
&mut framebuf,
|
||||
);
|
||||
|
||||
draw_line_graph(
|
||||
Rectangle::new(
|
||||
Point::new(
|
||||
DISPLAY_PADDING as i32,
|
||||
((LINE_GRAPH_HEIGHT * 2) + (DISPLAY_PADDING as u32 * 3)) as i32,
|
||||
),
|
||||
Size::new(LINE_GRAPH_WIDTH, LINE_GRAPH_HEIGHT),
|
||||
),
|
||||
humid_min,
|
||||
humid_max,
|
||||
humidity_samples.as_slices().0,
|
||||
Rgb565::CSS_AQUA,
|
||||
Some(Rgb888::new(24, 24, 24).into()),
|
||||
&mut framebuf,
|
||||
);
|
||||
|
||||
// Draw the text to the screen
|
||||
|
||||
@ -206,62 +207,61 @@ pub async fn display_output_task(
|
||||
);
|
||||
display.fill_contiguous(&area, framebuf.data).unwrap();
|
||||
}
|
||||
|
||||
fn draw_line_graph<'a, I, V, D, C>(
|
||||
collection: I,
|
||||
graph_max: i32,
|
||||
graph_min: i32,
|
||||
y_start: i32,
|
||||
line_colour: C,
|
||||
back_colour: Option<C>,
|
||||
target: &mut D,
|
||||
) -> Result<(), D::Error>
|
||||
where
|
||||
I: IntoIterator<Item = &'a V>,
|
||||
I::IntoIter: DoubleEndedIterator,
|
||||
V: ?Sized + 'a + Num + NumCast + Clone,
|
||||
C: RgbColor,
|
||||
D: DrawTarget<Color = C>,
|
||||
{
|
||||
let mut x_pos: i32 = (DISPLAY_WIDTH - 5) as i32;
|
||||
|
||||
match back_colour {
|
||||
Some(c) => {
|
||||
let style = PrimitiveStyleBuilder::new().fill_color(c).build();
|
||||
|
||||
Rectangle::new(Point::new(4, y_start), Size::new(120, 30))
|
||||
.into_styled(style)
|
||||
.draw(target)?;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
for (a, b) in collection.into_iter().rev().tuple_windows::<(_, _)>() {
|
||||
let range: i32 = if (graph_max - graph_min) == 0 {
|
||||
1_i32
|
||||
} else {
|
||||
graph_max - graph_min
|
||||
};
|
||||
|
||||
let a_i32: i32 = match NumCast::from(a.clone()) {
|
||||
Some(v) => v,
|
||||
None => 0,
|
||||
};
|
||||
let b_i32: i32 = match NumCast::from(b.clone()) {
|
||||
Some(v) => v,
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let a_y_pos: i32 = y_start + (((graph_max - a_i32) * 30) / range);
|
||||
let b_y_pos: i32 = y_start + (((graph_max - b_i32) * 30) / range);
|
||||
|
||||
Line::new(Point::new(x_pos, a_y_pos), Point::new(x_pos - 2, b_y_pos))
|
||||
.into_styled(PrimitiveStyle::with_stroke(line_colour, 1))
|
||||
.draw(target)?;
|
||||
|
||||
x_pos -= 2;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_line_graph<C, D>(
|
||||
bounds: Rectangle,
|
||||
y_min: U16F16,
|
||||
y_max: U16F16,
|
||||
samples: &[U16F16],
|
||||
fg_colour: C,
|
||||
bg_colour: Option<C>,
|
||||
target: &mut D,
|
||||
) where
|
||||
C: RgbColor,
|
||||
D: DrawTarget<Color = C>,
|
||||
{
|
||||
// Draw background colour first, if supplied
|
||||
|
||||
if let Some(bg_col) = bg_colour {
|
||||
let _ = bounds.draw_styled(&PrimitiveStyle::with_fill(bg_col), target);
|
||||
}
|
||||
|
||||
// Draw the data points
|
||||
|
||||
if samples.len() < 2 {
|
||||
// Drawing a line requires a minimum of two points
|
||||
return;
|
||||
}
|
||||
|
||||
let graph_width = U16F16::from_num(bounds.size.width);
|
||||
let graph_height = U16F16::from_num(bounds.size.height);
|
||||
let y_range = y_max - y_min;
|
||||
let mut x_offset: i32 = bounds.top_left.x;
|
||||
let n_samples: U16F16 = U16F16::from_num(samples.len());
|
||||
let mut n_samples_seen: U16F16 = U16F16::from_num(1);
|
||||
|
||||
for sample in samples.windows(2) {
|
||||
let x_pos_start: i32 = x_offset;
|
||||
let y_pos_start: i32 = bounds.top_left.y
|
||||
+ (graph_height - (((sample[0] - y_min) / y_range) * graph_height)).to_num::<i32>();
|
||||
let x_pos_end: i32 = bounds.top_left.x
|
||||
+ (((n_samples_seen + U16F16::from_num(1)) / n_samples)
|
||||
* (graph_width - U16F16::from_num(1)))
|
||||
.to_num::<i32>();
|
||||
let y_pos_end: i32 = bounds.top_left.y
|
||||
+ (graph_height - (((sample[1] - y_min) / y_range) * graph_height)).to_num::<i32>();
|
||||
|
||||
let _ = Line::new(
|
||||
Point::new(x_pos_start, y_pos_start),
|
||||
Point::new(x_pos_end, y_pos_end),
|
||||
)
|
||||
.into_styled(PrimitiveStyle::with_stroke(fg_colour, 1))
|
||||
.draw(target);
|
||||
|
||||
x_offset = x_pos_end;
|
||||
n_samples_seen += U16F16::from_num(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
60
src/input_task.rs
Normal file
60
src/input_task.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use embassy_futures::select::{select3, Either3};
|
||||
use embassy_rp::gpio::Input;
|
||||
use embassy_time::{with_timeout, Duration, Instant};
|
||||
use rtt_target::debug_rprintln;
|
||||
|
||||
const DEBOUNCE_TIME_MILLIS: u64 = 20;
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn input_handling_task(
|
||||
mut button_enter: Input<'static>,
|
||||
mut button_left: Input<'static>,
|
||||
mut button_right: Input<'static>,
|
||||
) {
|
||||
debug_rprintln!("Input handling task started");
|
||||
|
||||
loop {
|
||||
let enter_pressed = button_enter.wait_for_falling_edge();
|
||||
let left_pressed = button_left.wait_for_falling_edge();
|
||||
let right_pressed = button_right.wait_for_falling_edge();
|
||||
|
||||
match select3(enter_pressed, left_pressed, right_pressed).await {
|
||||
Either3::First(_) => {
|
||||
let pressed_at = Instant::now();
|
||||
if with_timeout(Duration::from_secs(2), button_enter.wait_for_rising_edge())
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
if pressed_at.elapsed().as_millis() < DEBOUNCE_TIME_MILLIS {
|
||||
continue;
|
||||
}
|
||||
debug_rprintln!("Enter button pressed!");
|
||||
}
|
||||
}
|
||||
Either3::Second(_) => {
|
||||
let pressed_at = Instant::now();
|
||||
if with_timeout(Duration::from_secs(2), button_left.wait_for_rising_edge())
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
if pressed_at.elapsed().as_millis() < DEBOUNCE_TIME_MILLIS {
|
||||
continue;
|
||||
}
|
||||
debug_rprintln!("Left button pressed!");
|
||||
}
|
||||
}
|
||||
Either3::Third(_) => {
|
||||
let pressed_at = Instant::now();
|
||||
if with_timeout(Duration::from_secs(2), button_right.wait_for_rising_edge())
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
if pressed_at.elapsed().as_millis() < DEBOUNCE_TIME_MILLIS {
|
||||
continue;
|
||||
}
|
||||
debug_rprintln!("Right button pressed!");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
21
src/main.rs
21
src/main.rs
@ -2,16 +2,17 @@
|
||||
#![no_main]
|
||||
|
||||
mod display_task;
|
||||
mod input_task;
|
||||
mod sensor_task;
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use rtt_target::{debug_rprintln, debug_rtt_init_print};
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::{
|
||||
block::ImageDef,
|
||||
gpio::{Level, Output},
|
||||
gpio::{Input, Level, Output, Pull},
|
||||
i2c,
|
||||
peripherals::{I2C0, SPI0},
|
||||
spi,
|
||||
@ -27,6 +28,7 @@ use embassy_time::Timer;
|
||||
use static_cell::StaticCell;
|
||||
|
||||
use display_task::display_output_task;
|
||||
use input_task::input_handling_task;
|
||||
use sensor_task::sensor_read_task;
|
||||
|
||||
type I2c0BusMutex = Mutex<NoopRawMutex, RefCell<i2c::I2c<'static, I2C0, i2c::Blocking>>>;
|
||||
@ -41,11 +43,11 @@ static SENSOR_DATA_SIGNAL: Signal<CriticalSectionRawMutex, scd4x::types::SensorD
|
||||
|
||||
/// Entrypoint
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
async fn main(spawner: Spawner) -> ! {
|
||||
// Initialise RTT logging
|
||||
|
||||
rtt_init_print!();
|
||||
rprintln!("RTT logging initialised");
|
||||
debug_rtt_init_print!();
|
||||
debug_rprintln!("RTT logging initialised");
|
||||
|
||||
let peripherals = embassy_rp::init(Default::default());
|
||||
|
||||
@ -70,7 +72,7 @@ async fn main(spawner: Spawner) {
|
||||
let rst = SPI0_RST_PIN.init(Output::new(peripherals.PIN_15, Level::Low));
|
||||
|
||||
let mut spi_config = spi::Config::default();
|
||||
spi_config.frequency = 4_000_000u32; // 4 MHz
|
||||
spi_config.frequency = 20_000_000u32; // 20 MHz
|
||||
let spi_bus = spi::Spi::new_blocking_txonly(peripherals.SPI0, sclk, mosi, spi_config.clone());
|
||||
static SPI0_BUS: StaticCell<Spi0BusMutex> = StaticCell::new();
|
||||
let shared_spi0_bus = SPI0_BUS.init(Mutex::new(RefCell::new(spi_bus)));
|
||||
@ -84,6 +86,11 @@ async fn main(spawner: Spawner) {
|
||||
spi_config.clone(),
|
||||
));
|
||||
|
||||
let enter_button = Input::new(peripherals.PIN_8, Pull::Up);
|
||||
let left_button = Input::new(peripherals.PIN_6, Pull::Up);
|
||||
let right_button = Input::new(peripherals.PIN_7, Pull::Up);
|
||||
spawner.must_spawn(input_handling_task(enter_button, left_button, right_button));
|
||||
|
||||
loop {
|
||||
Timer::after_secs(1).await;
|
||||
}
|
||||
@ -92,7 +99,7 @@ async fn main(spawner: Spawner) {
|
||||
/// Panic handler
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
rprintln!("Panicked! {}", info);
|
||||
debug_rprintln!("Panicked! {}", info);
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// System
|
||||
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
|
||||
use embassy_time::Timer;
|
||||
use rtt_target::rprintln;
|
||||
use rtt_target::debug_rprintln;
|
||||
|
||||
// Sensor
|
||||
use scd4x::Scd4x;
|
||||
@ -11,7 +11,7 @@ use crate::{I2c0BusMutex, SENSOR_DATA_SIGNAL};
|
||||
/// Read CO2/temp./humidity data from the sensor
|
||||
#[embassy_executor::task]
|
||||
pub async fn sensor_read_task(i2c_bus: &'static I2c0BusMutex) {
|
||||
rprintln!("Sensor read task started");
|
||||
debug_rprintln!("Sensor read task started");
|
||||
|
||||
Timer::after_millis(30).await; // SCD41 power-up delay
|
||||
let i2c_dev = I2cDevice::new(i2c_bus);
|
||||
@ -21,8 +21,8 @@ pub async fn sensor_read_task(i2c_bus: &'static I2c0BusMutex) {
|
||||
scd41.reinit().unwrap();
|
||||
|
||||
match scd41.serial_number() {
|
||||
Ok(serial) => rprintln!("[SCD41] Serial number: {}", serial),
|
||||
Err(error) => rprintln!(
|
||||
Ok(serial) => debug_rprintln!("[SCD41] Serial number: {}", serial),
|
||||
Err(error) => debug_rprintln!(
|
||||
"[SCD41] Error: did not respond to get_serial_number: {:?}",
|
||||
error
|
||||
),
|
||||
@ -35,8 +35,8 @@ pub async fn sensor_read_task(i2c_bus: &'static I2c0BusMutex) {
|
||||
|
||||
match scd41.measurement() {
|
||||
Ok(data) => {
|
||||
rprintln!(
|
||||
"[SCD41] CO2: {} ppm, temperature: {} C, humidity: {} RH",
|
||||
debug_rprintln!(
|
||||
"[SCD41] CO2: {} ppm, temperature: {} C, humidity: {} % RH",
|
||||
data.co2,
|
||||
data.temperature,
|
||||
data.humidity
|
||||
@ -45,7 +45,7 @@ pub async fn sensor_read_task(i2c_bus: &'static I2c0BusMutex) {
|
||||
SENSOR_DATA_SIGNAL.signal(data);
|
||||
}
|
||||
Err(error) => {
|
||||
rprintln!(
|
||||
debug_rprintln!(
|
||||
"[SCD41] Error: failed to retrieve measurement data: {:?}",
|
||||
error
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user