Resolve "Setup basic scheduler"
This commit is contained in:
parent
8b55888ad0
commit
3af8031387
26
Cargo.toml
26
Cargo.toml
@ -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
40
openocd.gdb
Normal 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
110
src/lcd_gui.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
232
src/main.rs
232
src/main.rs
@ -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() {
|
||||
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let _ = PCB_LED.borrow(cs).borrow_mut().as_mut().unwrap().toggle();
|
||||
});
|
||||
static mut TICK_DIVIDER: u32 = 0;
|
||||
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let _ = TIMER.borrow(cs).borrow_mut().as_mut().unwrap().clear_update_interrupt_flag();
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[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 encoder
|
||||
let enc = Qei::tim4(dp.TIM4, (gpiob.pb6, gpiob.pb7), &mut afio.mapr, &mut rcc.apb1);
|
||||
// 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);
|
||||
|
||||
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!");
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
BUTTON_PIN.borrow(cs).borrow_mut().replace(but_pin);
|
||||
});
|
||||
|
||||
lcd.set_cursor_pos(0x40);
|
||||
write!(lcd, "{}", enc.count()/4).unwrap();
|
||||
let mut old_count = enc.count();
|
||||
// Set backlight
|
||||
let backlight_pin = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);
|
||||
|
||||
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;
|
||||
}
|
||||
// setup encoder
|
||||
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
|
||||
});
|
||||
|
||||
LCDGui::new(lcd, enc, &BUTTON_FLAG, Some(backlight_pin))
|
||||
};
|
||||
|
||||
let exti = dp.EXTI;
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
G_EXTI.borrow(cs).borrow_mut().replace(exti);
|
||||
});
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user