Resolve "Setup basic scheduler"

This commit is contained in:
Steins7 2021-11-22 15:25:54 +00:00
parent 8b55888ad0
commit 3af8031387
4 changed files with 307 additions and 103 deletions

View File

@ -6,34 +6,17 @@ name = "fan_monitor"
version = "0.1.0" version = "0.1.0"
[dependencies] [dependencies]
embedded-hal = "0.2.6"
nb = "0.1.2"
cortex-m = "0.6.0" cortex-m = "0.6.0"
cortex-m-rt = "0.6.10" cortex-m-rt = "0.6.10"
cortex-m-semihosting = "0.3.3" cortex-m-semihosting = "0.3.3"
panic-halt = "0.2.0" panic-halt = "0.2.0"
embedded-hal = "0.2.3"
hd44780-driver = "0.3.0" hd44780-driver = "0.3.0"
nb = "0.1.1"
[dependencies.stm32f1]
version = "0.8.0"
features = ["stm32f103", "rt"]
[dependencies.stm32f1xx-hal] [dependencies.stm32f1xx-hal]
version = "0.4.0" version = "0.7.0"
features = ["stm32f103", "rt"] features = ["stm32f103", "rt", "medium"]
# 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"
# this lets you use `cargo fix`! # this lets you use `cargo fix`!
[[bin]] [[bin]]
@ -45,3 +28,4 @@ bench = false
codegen-units = 1 # better optimizations codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations 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_std]
#![no_main] #![no_main]
mod lcd_gui;
use lcd_gui::LCDGui;
extern crate panic_halt; extern crate panic_halt;
use core::{ use core::{
cell::RefCell, cell::RefCell,
fmt::Write, sync::atomic::{AtomicBool, Ordering},
}; };
use cortex_m::interrupt::Mutex; use cortex_m::interrupt::Mutex;
@ -17,63 +21,108 @@ use embedded_hal::digital::{
}; };
use stm32f1xx_hal::{ use stm32f1xx_hal::{
delay::Delay, gpio::*,
gpio::{gpioc, gpiob, Output, PushPull},
pac, pac,
pac::{interrupt, Interrupt}, pac::{interrupt, Interrupt, EXTI},
prelude::*, prelude::*,
timer::{Event, Timer}, timer::{Timer, CountDownTimer, Event},
qei::Qei, 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>>>>> static PCB_LED: Mutex<RefCell<Option<gpioc::PC13<Output<PushPull>>>>>
= Mutex::new(RefCell::new(None)); = 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>>>>> static RED_LED: Mutex<RefCell<Option<gpiob::PB11<Output<PushPull>>>>>
= Mutex::new(RefCell::new(None)); = Mutex::new(RefCell::new(None));
static TIMER: Mutex<RefCell<Option<Timer<pac::TIM2>>>> = Mutex::new(RefCell::new(None)); static RTC: Mutex<RefCell<Option<Rtc>>> = Mutex::new(RefCell::new(None));
static TIMER2: Mutex<RefCell<Option<Timer<pac::TIM3>>>> = Mutex::new(RefCell::new(None)); static G_EXTI: Mutex<RefCell<Option<EXTI>>> = Mutex::new(RefCell::new(None));
//--------------------------------------------------------------------------------------------------
/* interrupt service routines */
#[interrupt] #[interrupt]
fn TIM2() { fn TIM2() {
cortex_m::interrupt::free(|cs| { static mut TICK_DIVIDER: u32 = 0;
let _ = PCB_LED.borrow(cs).borrow_mut().as_mut().unwrap().toggle();
});
cortex_m::interrupt::free(|cs| { 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] #[interrupt]
fn TIM3() { fn EXTI9_5() {
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
let _ = RED_LED.borrow(cs).borrow_mut().as_mut().unwrap().toggle(); 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| { cortex_m::interrupt::free(|cs| {
let _ = TIMER2.borrow(cs).borrow_mut().as_mut().unwrap().clear_update_interrupt_flag(); 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();
}); });
} }
//--------------------------------------------------------------------------------------------------
/* main function */
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Get access to the core peripherals from the cortex-m crate
let cp = cortex_m::Peripherals::take().unwrap(); /* setup */
// Get access to the device specific peripherals from the peripheral access crate
let dp = pac::Peripherals::take().unwrap(); // basic setup
let mut cp = cortex_m::Peripherals::take().unwrap();
let mut dp = pac::Peripherals::take().unwrap();
// Take ownership over the raw flash and rcc devices and convert them into the corresponding // clocks config
// HAL structs
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain(); let mut rcc = dp.RCC.constrain();
let mut flash = dp.FLASH.constrain();
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in let clocks = rcc.cfgr
// `clocks` .use_hse(8.mhz())
let clocks = rcc.cfgr.freeze(&mut flash.acr); .freeze(&mut flash.acr);
// GPIOs // GPIOs
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
@ -83,45 +132,49 @@ fn main() -> ! {
// setup LED // setup LED
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
let _ = led.set_high(); let _ = led.set_high();
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
PCB_LED.borrow(cs).borrow_mut().replace(led) PCB_LED.borrow(cs).borrow_mut().replace(led)
}); });
// Configure the syst timer to trigger an update every second // Configure the timer 2 as tick timer
let mut timer = Timer::tim2(dp.TIM2, 1.hz(), clocks, &mut rcc.apb1); 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); timer.listen(Event::Update);
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
TIMER.borrow(cs).borrow_mut().replace(timer) TICK_TIMER.borrow(cs).borrow_mut().replace(timer)
}); });
// setup LED // setup LED
let mut led = gpiob.pb11.into_push_pull_output(&mut gpiob.crh); let mut red_led = gpiob.pb11.into_push_pull_output(&mut gpiob.crh);
let _ = led.set_high(); let _ = red_led.set_high();
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
RED_LED.borrow(cs).borrow_mut().replace(led) RED_LED.borrow(cs).borrow_mut().replace(red_led)
});
// 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());
// 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)
}); });
// 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)
});
// Enable timer interrupts
unsafe {
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2);
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM3);
}
let mut afio = dp.AFIO.constrain(&mut rcc.apb2); let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
// Setup display // 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); use hd44780_driver::HD44780;
let _ = backlight_pin.set_high();
// Disable JTAG to free pins // Disable JTAG to free pins
let (d3_pin, d5_pin, d7_pin) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4); 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 // Force write mode
let mut rw_pin = gpioa.pa9.into_push_pull_output(&mut gpioa.crh); 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(rs_pin),
OldOutputPin::new(en_pin), OldOutputPin::new(en_pin),
OldOutputPin::new(d0_pin), OldOutputPin::new(d0_pin),
@ -154,39 +207,56 @@ fn main() -> ! {
OldOutputPin::new(d6_pin), OldOutputPin::new(d6_pin),
OldOutputPin::new(d7_pin), OldOutputPin::new(d7_pin),
Delay::new(cp.SYST, clocks) Delay::new(cp.SYST, clocks)
)}; );
// setup encoder // setup button (interrupt)
let enc = Qei::tim4(dp.TIM4, (gpiob.pb6, gpiob.pb7), &mut afio.mapr, &mut rcc.apb1); 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(); cortex_m::interrupt::free(|cs| {
lcd.clear(); BUTTON_PIN.borrow(cs).borrow_mut().replace(but_pin);
lcd.set_display_mode( });
DisplayMode {
display: Display::On,
cursor_visibility: Cursor::Visible,
cursor_blink: CursorBlink::On,
}
);
let _ = lcd.write_str("Hello world!");
lcd.set_cursor_pos(0x40); // Set backlight
write!(lcd, "{}", enc.count()/4).unwrap(); let backlight_pin = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);
let mut old_count = enc.count();
loop { // setup encoder
if enc.count() != old_count { let enc = Timer::tim4(dp.TIM4, &clocks, &mut rcc.apb1)
old_count = enc.count(); .qei((gpiob.pb6, gpiob.pb7), &mut afio.mapr,
lcd.set_cursor_pos(0x40); QeiOptions {
lcd.write_str(" "); slave_mode:SlaveMode::EncoderMode2,
lcd.set_cursor_pos(0x40); auto_reload_value: 200
write!(lcd, "{}", enc.count()/4).unwrap(); });
}
for i in 0..10000 { LCDGui::new(lcd, enc, &BUTTON_FLAG, Some(backlight_pin))
cortex_m::asm::nop; };
}
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();
} }