You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
5.3 KiB
Rust

#![no_std]
#![no_main]
use panic_halt as _;
use fugit::RateExtU32;
use cortex_m::prelude::_embedded_hal_watchdog_Watchdog;
use embedded_hal::adc::OneShot;
use hal::i2c;
pub use sparkfun_pro_micro_rp2040::hal;
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
use embedded_graphics::text::Text;
use embedded_graphics::{
mono_font::{ascii::FONT_10X20, MonoTextStyle},
pixelcolor::BinaryColor,
prelude::*,
text::Alignment,
};
use fugit::MicrosDurationU32;
use hal::gpio::bank0::{Gpio14, Gpio15};
use hal::gpio::Pin;
use hal::pac::I2C1;
use hal::timer::{Alarm, Alarm0, Alarm1};
use hal::Adc;
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
const MVG_AVG_COUNT: u16 = 20;
#[rtic::app(device = sparkfun_pro_micro_rp2040::hal::pac, peripherals = true)]
mod app {
const DISPLAY_UPDATE_INT_TICKS: u32 = 500_000;
const SENSOR_READ_INT_TICKS: u32 = 50_000;
use super::*;
type Display = Ssd1306<
I2CInterface<
hal::I2C<
I2C1,
(
Pin<Gpio14, hal::gpio::Function<hal::gpio::I2C>>,
Pin<Gpio15, hal::gpio::Function<hal::gpio::I2C>>,
),
>,
>,
DisplaySize128x64,
ssd1306::mode::BufferedGraphicsMode<DisplaySize128x64>,
>;
#[shared]
struct Shared {
alarm0: Alarm0,
alarm1: Alarm1,
sensor_value: u16,
}
#[local]
struct Local {
display: Display,
adc: Adc,
adc_pin: Pin<hal::gpio::bank0::Gpio29, hal::gpio::FloatingInput>,
watchdog: hal::Watchdog,
}
#[init()]
fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
let mut resets = c.device.RESETS;
let sio = hal::Sio::new(c.device.SIO);
let mut watchdog = hal::Watchdog::new(c.device.WATCHDOG);
let _clocks = hal::clocks::init_clocks_and_plls(
XTAL_FREQ_HZ,
c.device.XOSC,
c.device.CLOCKS,
c.device.PLL_SYS,
c.device.PLL_USB,
&mut resets,
&mut watchdog,
)
.ok()
.unwrap();
let pins = rp2040_hal::gpio::Pins::new(
c.device.IO_BANK0,
c.device.PADS_BANK0,
sio.gpio_bank0,
&mut resets,
);
let mut timer = hal::Timer::new(c.device.TIMER, &mut resets);
let mut alarm0 = timer.alarm_0().unwrap();
let _ = alarm0.schedule(MicrosDurationU32::from_ticks(DISPLAY_UPDATE_INT_TICKS));
alarm0.enable_interrupt();
let mut alarm1 = timer.alarm_1().unwrap();
let _ = alarm1.schedule(MicrosDurationU32::from_ticks(SENSOR_READ_INT_TICKS));
alarm1.enable_interrupt();
let scl = pins.gpio15.into_mode();
let sda = pins.gpio14.into_mode();
let i2c = i2c::I2C::i2c1(
c.device.I2C1,
sda,
scl,
100.kHz(),
&mut resets,
125_000_000.Hz(),
);
let interface = I2CDisplayInterface::new(i2c);
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
.into_buffered_graphics_mode();
display.init().unwrap();
Text::with_alignment(
"Initialized",
display.bounding_box().center(),
MonoTextStyle::new(&FONT_10X20, BinaryColor::On),
Alignment::Center,
)
.draw(&mut display)
.unwrap();
display.flush().unwrap();
let adc = Adc::new(c.device.ADC, &mut resets);
let adc_pin = pins.gpio29.into_floating_input();
(
Shared {
alarm0,
alarm1,
sensor_value: 0,
},
Local {
display,
adc,
adc_pin,
watchdog,
},
init::Monotonics(),
)
}
#[task(binds = TIMER_IRQ_0, priority = 1, shared = [alarm0, sensor_value], local = [display])]
fn update_display(mut c: update_display::Context) {
let mut buf = [0u8; 20];
let text = c.shared.sensor_value.lock(|val| {
use numtoa::NumToA;
val.numtoa_str(10, &mut buf)
});
let display = c.local.display;
display.clear();
Text::with_alignment(
text,
display.bounding_box().center(),
MonoTextStyle::new(&FONT_10X20, BinaryColor::On),
Alignment::Center,
)
.draw(display)
.unwrap();
display.flush().unwrap();
c.shared.alarm0.lock(|a| {
a.clear_interrupt();
let _ = a.schedule(MicrosDurationU32::from_ticks(DISPLAY_UPDATE_INT_TICKS));
});
}
#[task(binds = TIMER_IRQ_1, priority = 2, shared = [alarm1, sensor_value], local = [adc, adc_pin, watchdog])]
fn read_sensor(mut c: read_sensor::Context) {
let sensor_value: u16 = c.local.adc.read(c.local.adc_pin).unwrap();
c.shared
.sensor_value
.lock(|v| *v = (*v * (MVG_AVG_COUNT - 1) + sensor_value) / MVG_AVG_COUNT);
c.local.watchdog.feed();
c.shared.alarm1.lock(|a| {
a.clear_interrupt();
let _ = a.schedule(MicrosDurationU32::from_ticks(DISPLAY_UPDATE_INT_TICKS));
});
}
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
cortex_m::asm::nop();
}
}
}