diff --git a/README.org b/README.org index 540ddfab992559b05f05f55b92dd3f57a592bf1c..7d2c8ae7b8e0c3923b25e27855fe5f88b1a991d5 100644 --- a/README.org +++ b/README.org @@ -44,6 +44,15 @@ the TB6612FNG motor driver. - [[https://wiki.dfrobot.com/Micro_DC_Motor_with_Encoder-SJ01_SKU__FIT0450][Wiki]] +* Led pattern + +The led pattern is in Morse code. + +| Code | Meaning | Pattern | +|------+------------------------------+---------| +| I | Regular reset | .. | +| WW | Reset due to window watchdog | .-- .-- | + * Command set Multibyte values are exchanged in little endian format. diff --git a/controller/src/main.rs b/controller/src/main.rs index 7fb02aef910be94144d12c735d911785731254fc..b3de259234d74c625735585a32d2bddddebffd26 100644 --- a/controller/src/main.rs +++ b/controller/src/main.rs @@ -7,7 +7,8 @@ use embassy_executor::Spawner; use embassy_stm32::{ gpio::{Level, Output, Speed}, interrupt::Priority, - peripherals::PB15, + pac, + peripherals::{PB15, RCC}, rcc::{APBPrescaler, Hse, HseMode, Pll, PllMul, PllPreDiv, PllSource, Sysclk}, time::{khz, mhz}, Config, @@ -19,6 +20,45 @@ mod encoders; mod logic; mod tb6612fng; +#[derive(Clone, Copy, Debug)] +enum ResetCause { + ExternalReset, + WindowWatchdogReset, + IndependentWatchdogReset, + SoftwareReset, + LowPowerManagementReset, + PowerReset, + Unknown, +} + +fn reset_cause(_rcc: &mut RCC) -> ResetCause { + // Read reset cause, and reset it + let csr = pac::RCC.csr().read(); + pac::RCC.csr().modify(|w| w.set_rmvf(true)); + if csr.lpwrrstf() { + ResetCause::LowPowerManagementReset + } else if csr.wwdgrstf() { + ResetCause::WindowWatchdogReset + } else if csr.iwdgrstf() { + ResetCause::IndependentWatchdogReset + } else if csr.sftrstf() { + ResetCause::SoftwareReset + } else if csr.porrstf() { + ResetCause::PowerReset + } else if csr.pinrstf() { + ResetCause::ExternalReset + } else { + ResetCause::Unknown + } +} + +fn blink_pattern(reset_cause: ResetCause) -> &'static str { + match reset_cause { + ResetCause::WindowWatchdogReset => ".-- .--", // WW + _ => "..", // I + } +} + #[embassy_executor::main] async fn main(spawner: Spawner) { let mut config = Config::default(); @@ -36,16 +76,20 @@ async fn main(spawner: Spawner) { }); // APB1 speed (PCLK1) is max 36MHz (SysClk/2), use that config.rcc.apb1_pre = APBPrescaler::DIV2; - let p = embassy_stm32::init(config); + let mut p = embassy_stm32::init(config); + let reset_cause = reset_cause(&mut p.RCC); defmt::info!( - "Firmware {}.{}.{} starting", + "Firmware {}.{}.{} starting – reset cause: {}", logic::PKG_VERSION[0], logic::PKG_VERSION[1], - logic::PKG_VERSION[2] + logic::PKG_VERSION[2], + defmt::Debug2Format(&reset_cause), ); - spawner.spawn(blink(p.PB15)).unwrap(); + spawner + .spawn(blink(p.PB15, blink_pattern(reset_cause))) + .unwrap(); let motors = Tb6612fng::new( p.PA4, @@ -69,12 +113,33 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn blink(pin: PB15) { +async fn blink(pin: PB15, pattern: &'static str) { let mut led = Output::new(pin, Level::High, Speed::Low); loop { - for _ in 0..6 { - led.toggle(); - Timer::after_millis(200).await; + for b in pattern.chars() { + match b { + ' ' => { + Timer::after_millis(200).await; + } + '.' => { + led.toggle(); + Timer::after_millis(150).await; + led.toggle(); + Timer::after_millis(200).await; + } + '-' => { + led.toggle(); + Timer::after_millis(300).await; + led.toggle(); + Timer::after_millis(200).await; + } + _ => { + defmt::error!("unknown pattern letter {}", b); + led.toggle(); + Timer::after_secs(5).await; + led.toggle(); + } + } } Timer::after_secs(1).await; }