|
| 1 | +//! Blinks an LED |
| 2 | +//! |
| 3 | +//! This assumes that a LED is connected to pc13 as is the case on the blue pill board. |
| 4 | +//! |
| 5 | +//! Please note according to RM0008: |
| 6 | +//! "Due to the fact that the switch only sinks a limited amount of current (3 mA), the use of |
| 7 | +//! GPIOs PC13 to PC15 in output mode is restricted: the speed has to be limited to 2MHz with |
| 8 | +//! a maximum load of 30pF and these IOs must not be used as a current source (e.g. to drive a LED)" |
| 9 | +
|
| 10 | +#![no_std] |
| 11 | +#![no_main] |
| 12 | + |
| 13 | +use panic_halt as _; |
| 14 | + |
| 15 | +use stm32f1xx_hal as hal; |
| 16 | + |
| 17 | +use crate::hal::{ |
| 18 | + gpio::{gpioc, Output, PushPull}, |
| 19 | + pac::{interrupt, Interrupt, Peripherals, EXTI}, |
| 20 | + prelude::*, |
| 21 | + rtc::Rtc, |
| 22 | +}; |
| 23 | + |
| 24 | +use core::cell::RefCell; |
| 25 | +use cortex_m::{asm::wfi, interrupt::Mutex}; |
| 26 | +use cortex_m_rt::entry; |
| 27 | +use embedded_hal::digital::v2::OutputPin; |
| 28 | + |
| 29 | +// A type definition for the GPIO pin to be used for our LED |
| 30 | +type LEDPIN = gpioc::PC13<Output<PushPull>>; |
| 31 | + |
| 32 | +// Make LED pin globally available |
| 33 | +static G_LED: Mutex<RefCell<Option<LEDPIN>>> = Mutex::new(RefCell::new(None)); |
| 34 | +// Make RTC globally available |
| 35 | +static G_RTC: Mutex<RefCell<Option<Rtc>>> = Mutex::new(RefCell::new(None)); |
| 36 | +// Make EXTI registers globally available |
| 37 | +static G_EXTI: Mutex<RefCell<Option<EXTI>>> = Mutex::new(RefCell::new(None)); |
| 38 | + |
| 39 | +// Toggle LED every 3 seconds |
| 40 | +const TOGGLE_INTERVAL_SECONDS: u32 = 3; |
| 41 | + |
| 42 | +// The f100 does not have an RTC, so this example is disabled |
| 43 | +#[cfg(feature = "stm32f101")] |
| 44 | +#[entry] |
| 45 | +fn main() -> ! { |
| 46 | + loop { |
| 47 | + continue; |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +#[cfg(not(feature = "stm32f101"))] |
| 52 | +#[interrupt] |
| 53 | +fn RTCALARM() { |
| 54 | + static mut LED: Option<LEDPIN> = None; |
| 55 | + static mut RTC: Option<Rtc> = None; |
| 56 | + static mut EXTI: Option<EXTI> = None; |
| 57 | + |
| 58 | + let led = LED.get_or_insert_with(|| { |
| 59 | + cortex_m::interrupt::free(|cs| G_LED.borrow(cs).replace(None).unwrap()) |
| 60 | + }); |
| 61 | + let rtc = RTC.get_or_insert_with(|| { |
| 62 | + cortex_m::interrupt::free(|cs| G_RTC.borrow(cs).replace(None).unwrap()) |
| 63 | + }); |
| 64 | + let exti = EXTI.get_or_insert_with(|| { |
| 65 | + cortex_m::interrupt::free(|cs| G_EXTI.borrow(cs).replace(None).unwrap()) |
| 66 | + }); |
| 67 | + |
| 68 | + exti.pr.write(|w| w.pr17().set_bit()); |
| 69 | + rtc.set_alarm(rtc.current_time() + TOGGLE_INTERVAL_SECONDS); |
| 70 | + |
| 71 | + let _ = led.toggle(); |
| 72 | +} |
| 73 | + |
| 74 | +#[cfg(not(feature = "stm32f101"))] |
| 75 | +#[entry] |
| 76 | +fn main() -> ! { |
| 77 | + let dp = Peripherals::take().unwrap(); |
| 78 | + |
| 79 | + let mut pwr = dp.PWR; |
| 80 | + let mut rcc = dp.RCC.constrain(); |
| 81 | + |
| 82 | + // Set up the GPIO pin |
| 83 | + let mut gpioc = dp.GPIOC.split(&mut rcc.apb2); |
| 84 | + let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); |
| 85 | + let _ = led.set_high(); // Turn off |
| 86 | + |
| 87 | + cortex_m::interrupt::free(|cs| *G_LED.borrow(cs).borrow_mut() = Some(led)); |
| 88 | + |
| 89 | + // Set up the EXTI (see notes in section 18.4.2 of reference manual) |
| 90 | + let exti = dp.EXTI; |
| 91 | + exti.ftsr.write(|w| w.tr17().set_bit()); |
| 92 | + exti.imr.write(|w| w.mr17().set_bit()); |
| 93 | + |
| 94 | + cortex_m::interrupt::free(|cs| *G_EXTI.borrow(cs).borrow_mut() = Some(exti)); |
| 95 | + |
| 96 | + // Set up the RTC |
| 97 | + // Enable writes to the backup domain |
| 98 | + let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut rcc.apb1, &mut pwr); |
| 99 | + // Start the RTC |
| 100 | + let mut rtc = Rtc::rtc(dp.RTC, &mut backup_domain); |
| 101 | + rtc.set_time(0); |
| 102 | + rtc.set_alarm(TOGGLE_INTERVAL_SECONDS); |
| 103 | + rtc.listen_alarm(); |
| 104 | + |
| 105 | + cortex_m::interrupt::free(|cs| *G_RTC.borrow(cs).borrow_mut() = Some(rtc)); |
| 106 | + |
| 107 | + // Enable RTCALARM IRQ |
| 108 | + unsafe { cortex_m::peripheral::NVIC::unmask(Interrupt::RTCALARM) }; |
| 109 | + |
| 110 | + loop { |
| 111 | + wfi(); |
| 112 | + } |
| 113 | +} |
0 commit comments