#![doc = include_str!("../README.md")]
#![no_std]
use crate::input::{Buttons, ExtInterrupts};
use core::cell::RefCell;
use dial::Dial;
use stm32h7xx_hal::{
delay::Delay,
pac::Peripherals as Stm32Peripherals,
prelude::*,
rcc::{CoreClocks, ResetEnable},
};
#[cfg(all(feature = "alloc", feature = "panic"))]
extern crate alloc;
pub mod dial;
mod hal_sys;
pub mod input;
mod pac;
#[cfg(feature = "display")]
pub mod display;
#[cfg(feature = "alloc")]
mod e_alloc;
#[cfg(feature = "panic")]
pub mod panic;
static mut DELAY: Option<RefCell<Delay>> = None;
pub struct Alarmo {
pub clocks: CoreClocks,
pub delay: &'static RefCell<Delay>,
pub dial: Dial,
pub ext_interrupts: ExtInterrupts,
pub buttons: Buttons,
#[cfg(feature = "display")]
pub display: display::AlarmoDisplay,
#[cfg(feature = "usb")]
pub usb1: stm32h7xx_hal::usb_hs::USB1,
}
pub struct AlarmoOptions {
#[cfg(feature = "alloc")]
pub heap_size: usize,
}
impl Alarmo {
pub unsafe fn init() -> Alarmo {
Self::init_with_options(AlarmoOptions::default())
}
pub unsafe fn init_with_options(options: AlarmoOptions) -> Alarmo {
let mut cortex = cortex_m::Peripherals::take().unwrap();
cortex.SCB.enable_icache();
cortex.SCB.enable_dcache(&mut cortex.CPUID);
cortex_m::interrupt::enable();
let peripherals = Stm32Peripherals::take().unwrap();
let pwr = peripherals.PWR.constrain();
let pwr_cfg = pwr.freeze();
let rcc = peripherals.RCC.constrain();
let mut ccdr = rcc.freeze(pwr_cfg, &peripherals.SYSCFG);
if cfg!(feature = "usb") {
let _ = ccdr.clocks.hsi48_ck().expect("HSI48 must run");
ccdr.peripheral
.kernel_usb_clk_mux(stm32h7xx_hal::rcc::rec::UsbClkSel::Hsi48);
}
#[cfg(feature = "alloc")]
e_alloc::init_heap(options.heap_size);
let gpioa = peripherals.GPIOA.split(ccdr.peripheral.GPIOA);
let gpiob = peripherals.GPIOB.split(ccdr.peripheral.GPIOB);
let gpioc = peripherals.GPIOC.split(ccdr.peripheral.GPIOC);
let gpiog = peripherals.GPIOG.split_without_reset(ccdr.peripheral.GPIOG);
#[cfg(feature = "usb")]
let usb1 = pac::usb::split_usb(
gpioa.pa11,
gpioa.pa12,
peripherals.OTG1_HS_GLOBAL,
peripherals.OTG1_HS_DEVICE,
peripherals.OTG1_HS_PWRCLK,
ccdr.peripheral.USB1OTG,
&ccdr.clocks,
);
let (dial_timers, disp_timer) = pac::timers::split_timers(
&ccdr.clocks,
peripherals.TIM1,
peripherals.TIM3,
gpioa.pa8,
gpioa.pa10,
gpiob.pb1,
gpioc.pc8,
ccdr.peripheral.TIM1,
ccdr.peripheral.TIM3,
);
let exti = ExtInterrupts {
syscfg: peripherals.SYSCFG,
exti: peripherals.EXTI,
nvic: cortex.NVIC,
};
let buttons = Buttons::split(gpiog.pg5, gpiog.pg6, gpioc.pc5);
let disp_pin = unsafe { pac::sram::init(peripherals.FMC, gpioc.pc7) };
ccdr.peripheral
.FMC
.kernel_clk_mux(stm32h7xx_hal::pac::rcc::d1ccipr::FMCSEL_A::Per)
.enable();
DELAY = Some(RefCell::new(Delay::new(cortex.SYST, ccdr.clocks)));
Alarmo {
delay: DELAY.as_ref().unwrap(),
clocks: ccdr.clocks,
dial: Dial {
timers: dial_timers,
},
ext_interrupts: exti,
buttons,
#[cfg(feature = "display")]
display: display::AlarmoDisplay::new(
disp_timer,
disp_pin,
gpiog.pg4,
DELAY.as_ref().unwrap(),
),
#[cfg(feature = "usb")]
usb1,
}
}
}
impl Default for AlarmoOptions {
fn default() -> Self {
AlarmoOptions {
#[cfg(feature = "alloc")]
heap_size: 0x1000000, }
}
}