Merge branch '4-setup-basic-scheduler' into 'dev'

Resolve "Setup basic scheduler"

See merge request Steins7/fan_monitor!3
This commit is contained in:
Steins7 2021-11-22 15:25:54 +00:00
commit 82a4b95480
4 changed files with 307 additions and 103 deletions

View File

@ -6,34 +6,17 @@ name = "fan_monitor"
version = "0.1.0"
[dependencies]
embedded-hal = "0.2.6"
nb = "0.1.2"
cortex-m = "0.6.0"
cortex-m-rt = "0.6.10"
cortex-m-semihosting = "0.3.3"
panic-halt = "0.2.0"
embedded-hal = "0.2.3"
hd44780-driver = "0.3.0"
nb = "0.1.1"
[dependencies.stm32f1]
version = "0.8.0"
features = ["stm32f103", "rt"]
[dependencies.stm32f1xx-hal]
version = "0.4.0"
features = ["stm32f103", "rt"]
# Uncomment for the panic example.
# panic-itm = "0.4.1"
# Uncomment for the allocator example.
# alloc-cortex-m = "0.3.5"
# Uncomment for the device example.
# Update `memory.x`, set target to `thumbv7em-none-eabihf` in `.cargo/config`,
# and then use `cargo build --examples device` to build it.
# [dependencies.stm32f3]
# features = ["stm32f303", "rt"]
# version = "0.7.1"
version = "0.7.0"
features = ["stm32f103", "rt", "medium"]
# this lets you use `cargo fix`!
[[bin]]
@ -45,3 +28,4 @@ bench = false
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations

40
openocd.gdb Normal file
View File

@ -0,0 +1,40 @@
target extended-remote :3333
# print demangled symbols
set print asm-demangle on
# set backtrace limit to not have infinite backtrace loops
set backtrace limit 32
# detect unhandled exceptions, hard faults and panics
break DefaultHandler
break HardFault
break rust_begin_unwind
# # run the next few lines so the panic message is printed immediately
# # the number needs to be adjusted for your panic handler
# commands $bpnum
# next 4
# end
# *try* to stop at the user entry point (it might be gone due to inlining)
break main
monitor arm semihosting enable
# # send captured ITM to the file itm.fifo
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
# # 8000000 must match the core clock frequency
# monitor tpiu config internal itm.txt uart off 8000000
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
# # 8000000 must match the core clock frequency
# # 2000000 is the frequency of the SWO pin
# monitor tpiu config external uart off 8000000 2000000
# # enable ITM port 0
# monitor itm port 0 on
load
# start the process but immediately halt the processor
stepi

110
src/lcd_gui.rs Normal file
View File

@ -0,0 +1,110 @@
use core::{sync::atomic::{AtomicBool, Ordering}};
use embedded_hal::{
//digital::v1_compat::OldOutputPin,
digital::v2::OutputPin,
Qei,
blocking::delay::{DelayUs, DelayMs},
};
use hd44780_driver::{
HD44780,
display_mode::DisplayMode,
bus::DataBus,
};
pub struct LCDGui<L, Q, B>
where
L: LCDScreen,
Q: Qei<Count = u16>,
B: OutputPin,
{
lcd: L,
qei: Q,
button: &'static AtomicBool,
backlight: Option<B>,
count: u16,
}
impl<L, Q, B> LCDGui<L, Q, B>
where
L: LCDScreen,
Q: Qei<Count = u16>,
B: OutputPin,
{
pub fn new(lcd: L, qei: Q, button: &'static AtomicBool, backlight: Option<B>)
-> LCDGui<L, Q, B> {
use hd44780_driver::{Cursor, CursorBlink, Display};
let count = qei.count();
let mut gui = LCDGui {lcd, qei, button, backlight, count};
if let Some(bl) = &mut gui.backlight { let _ = bl.set_high(); };
gui.lcd.reset();
gui.lcd.clear();
gui.lcd.set_display_mode(
DisplayMode {
display: Display::On,
cursor_visibility: Cursor::Visible,
cursor_blink: CursorBlink::On,
}
);
let _ = gui.lcd.write_str("Hello world!");
gui
}
pub fn run(&mut self) -> ! {
loop {
//TODO deduplicate button detection
if self.button.swap(false, Ordering::AcqRel) {
self.lcd.write_str("paf").unwrap();
}
if self.count != self.qei.count() {
self.count = self.qei.count();
self.lcd.set_cursor_pos(0x40);
self.lcd.write_str(" ").unwrap();
self.lcd.set_cursor_pos(0x40);
write!(self.lcd, "{}", self.qei.count()/2).unwrap();
}
// put device in sleep mode until next interrupt (button or timer)
cortex_m::asm::wfi();
}
}
}
pub trait LCDScreen: core::fmt::Write {
fn reset(&mut self);
fn clear(&mut self);
fn set_display_mode(&mut self, mode: DisplayMode);
fn set_cursor_pos(&mut self, positions: u8);
}
impl<D, DB> LCDScreen for HD44780<D, DB>
where
D: DelayUs<u16> + DelayMs<u8>,
DB: DataBus,
{
fn reset(&mut self) {
self.reset()
}
fn clear(&mut self) {
self.clear()
}
fn set_display_mode(&mut self, mode: DisplayMode) {
self.set_display_mode(mode)
}
fn set_cursor_pos(&mut self, position: u8) {
self.set_cursor_pos(position);
}
}

View File

@ -1,11 +1,15 @@
#![no_std]
#![no_main]
mod lcd_gui;
use lcd_gui::LCDGui;
extern crate panic_halt;
use core::{
cell::RefCell,
fmt::Write,
sync::atomic::{AtomicBool, Ordering},
};
use cortex_m::interrupt::Mutex;
@ -17,63 +21,108 @@ use embedded_hal::digital::{
};
use stm32f1xx_hal::{
delay::Delay,
gpio::{gpioc, gpiob, Output, PushPull},
gpio::*,
pac,
pac::{interrupt, Interrupt},
pac::{interrupt, Interrupt, EXTI},
prelude::*,
timer::{Event, Timer},
qei::Qei,
timer::{Timer, CountDownTimer, Event},
qei::{QeiOptions, SlaveMode},
rtc::Rtc,
};
use hd44780_driver::{Cursor, CursorBlink, Display, DisplayMode, HD44780};
//--------------------------------------------------------------------------------------------------
/* system config */
const GUI_TICK_SEC: f32 = 0.2;
const HEARTBEAT_SEC: f32 = 1.0;
const TEMPS_TICK_SEC: u32 = 5;
//--------------------------------------------------------------------------------------------------
/* interrupt variables */
// tick/heartbeat timer
static PCB_LED: Mutex<RefCell<Option<gpioc::PC13<Output<PushPull>>>>>
= Mutex::new(RefCell::new(None));
static TICK_TIMER: Mutex<RefCell<Option<CountDownTimer<pac::TIM2>>>>
= Mutex::new(RefCell::new(None));
// button interrupt
static BUTTON_PIN: Mutex<RefCell<Option<gpiob::PB8<Input<PullUp>>>>>
= Mutex::new(RefCell::new(None));
static BUTTON_FLAG: AtomicBool = AtomicBool::new(false);
// temps interrupt
static RED_LED: Mutex<RefCell<Option<gpiob::PB11<Output<PushPull>>>>>
= Mutex::new(RefCell::new(None));
static TIMER: Mutex<RefCell<Option<Timer<pac::TIM2>>>> = Mutex::new(RefCell::new(None));
static TIMER2: Mutex<RefCell<Option<Timer<pac::TIM3>>>> = Mutex::new(RefCell::new(None));
static RTC: Mutex<RefCell<Option<Rtc>>> = Mutex::new(RefCell::new(None));
static G_EXTI: Mutex<RefCell<Option<EXTI>>> = Mutex::new(RefCell::new(None));
//--------------------------------------------------------------------------------------------------
/* interrupt service routines */
#[interrupt]
fn TIM2() {
static mut TICK_DIVIDER: u32 = 0;
cortex_m::interrupt::free(|cs| {
let _ = TICK_TIMER.borrow(cs).borrow_mut().as_mut().unwrap().clear_update_interrupt_flag();
});
*TICK_DIVIDER += 1;
if *TICK_DIVIDER >= (HEARTBEAT_SEC / GUI_TICK_SEC) as u32 {
*TICK_DIVIDER = 0;
cortex_m::interrupt::free(|cs| {
let _ = PCB_LED.borrow(cs).borrow_mut().as_mut().unwrap().toggle();
});
cortex_m::interrupt::free(|cs| {
let _ = TIMER.borrow(cs).borrow_mut().as_mut().unwrap().clear_update_interrupt_flag();
});
}
}
#[interrupt]
fn TIM3() {
fn EXTI9_5() {
cortex_m::interrupt::free(|cs| {
let _ = BUTTON_PIN.borrow(cs).borrow_mut().as_mut().unwrap().clear_interrupt_pending_bit();
});
BUTTON_FLAG.store(true, Ordering::Release);
}
#[interrupt]
fn RTCALARM() {
cortex_m::interrupt::free(|cs| {
let _ = G_EXTI.borrow(cs).borrow_mut().as_mut().unwrap().pr.write(|w| w.pr17().set_bit());
});
cortex_m::interrupt::free(|cs| {
let mut rtc = RTC.borrow(cs).borrow_mut();
let time = rtc.as_mut().unwrap().current_time();
rtc.as_mut().unwrap().set_alarm(time + TEMPS_TICK_SEC); //also clears the flag
});
cortex_m::interrupt::free(|cs| {
let _ = RED_LED.borrow(cs).borrow_mut().as_mut().unwrap().toggle();
});
cortex_m::interrupt::free(|cs| {
let _ = TIMER2.borrow(cs).borrow_mut().as_mut().unwrap().clear_update_interrupt_flag();
});
}
//--------------------------------------------------------------------------------------------------
/* main function */
#[entry]
fn main() -> ! {
// Get access to the core peripherals from the cortex-m crate
let cp = cortex_m::Peripherals::take().unwrap();
// Get access to the device specific peripherals from the peripheral access crate
let dp = pac::Peripherals::take().unwrap();
// Take ownership over the raw flash and rcc devices and convert them into the corresponding
// HAL structs
let mut flash = dp.FLASH.constrain();
/* setup */
// basic setup
let mut cp = cortex_m::Peripherals::take().unwrap();
let mut dp = pac::Peripherals::take().unwrap();
// clocks config
let mut rcc = dp.RCC.constrain();
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in
// `clocks`
let clocks = rcc.cfgr.freeze(&mut flash.acr);
let mut flash = dp.FLASH.constrain();
let clocks = rcc.cfgr
.use_hse(8.mhz())
.freeze(&mut flash.acr);
// GPIOs
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
@ -83,45 +132,49 @@ fn main() -> ! {
// setup LED
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
let _ = led.set_high();
cortex_m::interrupt::free(|cs| {
PCB_LED.borrow(cs).borrow_mut().replace(led)
});
// Configure the syst timer to trigger an update every second
let mut timer = Timer::tim2(dp.TIM2, 1.hz(), clocks, &mut rcc.apb1);
// Configure the timer 2 as tick timer
let mut timer = Timer::tim2(dp.TIM2, &clocks, &mut rcc.apb1)
.start_count_down(((1.0/GUI_TICK_SEC) as u32).hz());
timer.listen(Event::Update);
cortex_m::interrupt::free(|cs| {
TIMER.borrow(cs).borrow_mut().replace(timer)
TICK_TIMER.borrow(cs).borrow_mut().replace(timer)
});
// setup LED
let mut led = gpiob.pb11.into_push_pull_output(&mut gpiob.crh);
let _ = led.set_high();
let mut red_led = gpiob.pb11.into_push_pull_output(&mut gpiob.crh);
let _ = red_led.set_high();
cortex_m::interrupt::free(|cs| {
RED_LED.borrow(cs).borrow_mut().replace(led)
RED_LED.borrow(cs).borrow_mut().replace(red_led)
});
// Configure the syst timer to trigger an update every second
let mut timer = Timer::tim3(dp.TIM3, 5.hz(), clocks, &mut rcc.apb1);
timer.listen(Event::Update);
cortex_m::interrupt::free(|cs| {
TIMER2.borrow(cs).borrow_mut().replace(timer)
});
// set EXTI 17 (see note in 18.4.2, in short : needed for rtc ISR to trigger)
dp.EXTI.ftsr.write(|w| w.tr17().set_bit());
dp.EXTI.imr.write(|w| w.mr17().set_bit());
// Enable timer interrupts
unsafe {
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2);
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM3);
}
// setup RTC
let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut rcc.apb1, &mut dp.PWR);
let mut rtc = Rtc::rtc(dp.RTC, &mut backup_domain);
rtc.set_alarm(rtc.current_time() + TEMPS_TICK_SEC);
rtc.listen_alarm();
cortex_m::interrupt::free(|cs| {
RTC.borrow(cs).borrow_mut().replace(rtc)
});
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
// Setup display
let mut lcd = {
let mut gui = {
use stm32f1xx_hal::{gpio::*, delay::Delay};
// Set backlight
let mut backlight_pin = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);
let _ = backlight_pin.set_high();
use hd44780_driver::HD44780;
// Disable JTAG to free pins
let (d3_pin, d5_pin, d7_pin) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4);
@ -140,9 +193,9 @@ fn main() -> ! {
// Force write mode
let mut rw_pin = gpioa.pa9.into_push_pull_output(&mut gpioa.crh);
rw_pin.set_low();
rw_pin.set_low().unwrap();
HD44780::new_8bit(
let lcd = HD44780::new_8bit(
OldOutputPin::new(rs_pin),
OldOutputPin::new(en_pin),
OldOutputPin::new(d0_pin),
@ -154,39 +207,56 @@ fn main() -> ! {
OldOutputPin::new(d6_pin),
OldOutputPin::new(d7_pin),
Delay::new(cp.SYST, clocks)
)};
);
// setup button (interrupt)
let mut but_pin = gpiob.pb8.into_pull_up_input(&mut gpiob.crh);
but_pin.make_interrupt_source(&mut afio);
but_pin.trigger_on_edge(&dp.EXTI, Edge::RISING);
but_pin.enable_interrupt(&dp.EXTI);
cortex_m::interrupt::free(|cs| {
BUTTON_PIN.borrow(cs).borrow_mut().replace(but_pin);
});
// Set backlight
let backlight_pin = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);
// setup encoder
let enc = Qei::tim4(dp.TIM4, (gpiob.pb6, gpiob.pb7), &mut afio.mapr, &mut rcc.apb1);
let enc = Timer::tim4(dp.TIM4, &clocks, &mut rcc.apb1)
.qei((gpiob.pb6, gpiob.pb7), &mut afio.mapr,
QeiOptions {
slave_mode:SlaveMode::EncoderMode2,
auto_reload_value: 200
});
lcd.reset();
lcd.clear();
lcd.set_display_mode(
DisplayMode {
display: Display::On,
cursor_visibility: Cursor::Visible,
cursor_blink: CursorBlink::On,
}
);
let _ = lcd.write_str("Hello world!");
LCDGui::new(lcd, enc, &BUTTON_FLAG, Some(backlight_pin))
};
lcd.set_cursor_pos(0x40);
write!(lcd, "{}", enc.count()/4).unwrap();
let mut old_count = enc.count();
let exti = dp.EXTI;
cortex_m::interrupt::free(|cs| {
G_EXTI.borrow(cs).borrow_mut().replace(exti);
});
loop {
if enc.count() != old_count {
old_count = enc.count();
lcd.set_cursor_pos(0x40);
lcd.write_str(" ");
lcd.set_cursor_pos(0x40);
write!(lcd, "{}", enc.count()/4).unwrap();
}
for i in 0..10000 {
cortex_m::asm::nop;
}
}
// Enable interrupts
unsafe {
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2);
cortex_m::peripheral::NVIC::unmask(Interrupt::EXTI9_5);
cortex_m::peripheral::NVIC::unmask(Interrupt::RTCALARM);
}
// allow the debugging to continue in sleep and stop modes
#[cfg(debug_assertions)]
dp.DBGMCU.cr.write(|w| w.dbg_sleep().set_bit());
#[cfg(debug_assertions)]
dp.DBGMCU.cr.write(|w| w.dbg_stop().set_bit());
// configure stop mode (not working yet, probably due to fake chip)
//dp.PWR.cr.write(|w| w.pdds().stop_mode());
//dp.PWR.cr.write(|w| w.lpds().set_bit());
cp.SCB.set_sleepdeep();
/* run */
gui.run();
}