diff --git a/.gitignore b/.gitignore index 8a888b6..2eb09f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /kicad/*-backups/ +/kicad/*.lck \ No newline at end of file diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index cd4d280..d2478f5 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -25,6 +25,9 @@ experimental = ["esp-idf-svc/experimental"] [dependencies] log = "0.4" esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-driver", "embassy-sync"] } +anyhow = "1.0.97" +embedded-graphics = "0.8.1" +ssd1306 = "0.9.0" [build-dependencies] embuild = "0.33" diff --git a/firmware/sdkconfig.defaults b/firmware/sdkconfig.defaults index c364dc9..8c3db28 100644 --- a/firmware/sdkconfig.defaults +++ b/firmware/sdkconfig.defaults @@ -9,4 +9,4 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000 #CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n #CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n -CONFIG_ESP_CONSOLE_UART=CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG \ No newline at end of file +CONFIG_ESP_CONSOLE_USB_CDC=y \ No newline at end of file diff --git a/firmware/src/main.rs b/firmware/src/main.rs index bc35c2d..f0ba90f 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -1,6 +1,24 @@ -use esp_idf_svc::hal::{delay::FreeRtos, gpio::{PinDriver}, prelude::Peripherals}; +use std::{num::NonZeroU32, thread, time::Duration}; +use anyhow::Result; +use embedded_graphics::{ + mono_font::{ascii::FONT_6X10, MonoTextStyleBuilder}, + pixelcolor::BinaryColor, + prelude::Point, + text::{Baseline, Text}, + Drawable +}; +use esp_idf_svc::hal::{ + i2c::{I2cConfig, I2cDriver}, + adc::{attenuation::DB_11, oneshot::{config::AdcChannelConfig, AdcChannelDriver, AdcDriver}}, + delay::FreeRtos, + gpio::{InterruptType, PinDriver, Pull}, + prelude::Peripherals, + units::*, + task::notification::Notification +}; +use ssd1306::{mode::DisplayConfig, prelude::DisplayRotation, size::DisplaySize128x32, I2CDisplayInterface, Ssd1306}; -fn main() { +fn main() -> Result<()> { // It is necessary to call this function once. Otherwise some patches to the runtime // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 esp_idf_svc::sys::link_patches(); @@ -9,12 +27,78 @@ fn main() { esp_idf_svc::log::EspLogger::initialize_default(); let peripherals = Peripherals::take().unwrap(); + let adc = AdcDriver::new(peripherals.adc1)?; + + let i2c_sda_pin = peripherals.pins.gpio8; + let i2c_scl_pin = peripherals.pins.gpio9; + let mut led_pin = PinDriver::output(peripherals.pins.gpio15).unwrap(); let mut led2_pin = PinDriver::output(peripherals.pins.gpio3).unwrap(); + let mut heater_drv_pin = PinDriver::output(peripherals.pins.gpio13).unwrap(); + let mut pump_drv_pin = PinDriver::output(peripherals.pins.gpio12).unwrap(); + + let mut button1 = PinDriver::input(peripherals.pins.gpio2)?; + let mut button2 = PinDriver::input(peripherals.pins.gpio4)?; + let mut button3 = PinDriver::input(peripherals.pins.gpio6)?; + + let config = AdcChannelConfig { + attenuation: DB_11, + ..Default::default() + }; + let mut therm_pin = AdcChannelDriver::new(&adc, peripherals.pins.gpio10, &config)?; + + let config = I2cConfig::new().baudrate(400.kHz().into()); + let i2c = I2cDriver::new(peripherals.i2c0, i2c_sda_pin, i2c_scl_pin, &config)?; + + let interface = I2CDisplayInterface::new(i2c); + let mut display = Ssd1306::new(interface, DisplaySize128x32, DisplayRotation::Rotate0) + .into_buffered_graphics_mode(); + display.init().unwrap(); + + let text_style = MonoTextStyleBuilder::new() + .font(&FONT_6X10) + .text_color(BinaryColor::On) + .build(); + + button1.set_pull(Pull::Down)?; + button1.set_interrupt_type(InterruptType::PosEdge)?; + + button2.set_pull(Pull::Down)?; + button2.set_interrupt_type(InterruptType::PosEdge)?; + + button3.set_pull(Pull::Down)?; + button3.set_interrupt_type(InterruptType::PosEdge)?; + + let notification = Notification::new(); + let notifier = notification.notifier(); + + unsafe { + button1.subscribe(move || { + notifier.notify_and_yield(NonZeroU32::new(1).unwrap()); + })?; + } + + button1.enable_interrupt()?; + log::info!("Hello, world!"); loop { + let not = notification.wait(esp_idf_svc::hal::delay::NON_BLOCK); + match not { + Some(n) => { + println!("Button 1 pressed!"); + button1.enable_interrupt()?; + + if heater_drv_pin.is_set_high() { + heater_drv_pin.set_low()?; + } else { + heater_drv_pin.set_high()?; + } + }, + None => (), + } + led_pin.set_low().unwrap(); led2_pin.set_low().unwrap(); FreeRtos::delay_ms(1000); @@ -23,5 +107,36 @@ fn main() { led2_pin.set_high().unwrap(); FreeRtos::delay_ms(1000); println!("blink"); + + const R1: f32 = 100000_f32; + const R0: f32 = 100000_f32; + const V1: f32 = 5_f32; + const T0: f32 = 298.15_f32; + const B: f32 = 4285_f32; + + let mut samples_sum = 0_f32; + for i in 0..64 { + let v = adc.read(&mut therm_pin)? as f32 / 1000_f32; + let r = R1 / (V1 / v - 1_f32); + let temp = T0 * B / (T0 * (r / R0).ln() + B) - 273.15_f32; + samples_sum += temp; + FreeRtos::delay_ms(10); + } + let temp = samples_sum / 64_f32; + + println!("Temperature value: {}", temp); + + display.clear_buffer(); + + Text::with_baseline(format!("Temperature: {}", temp).as_str(), Point::zero(), text_style, Baseline::Top) + .draw(&mut display) + .unwrap(); + Text::with_baseline(format!("Relay: {}", heater_drv_pin.is_set_high()).as_str(), Point::new(0, 16), text_style, Baseline::Top) + .draw(&mut display) + .unwrap(); + + display.flush().unwrap(); + + thread::sleep(Duration::from_millis(10)); } }