blinky_rtcalarm_irq.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. #![no_std]
  10. #![no_main]
  11. use panic_halt as _;
  12. use stm32f1xx_hal as hal;
  13. use crate::hal::{
  14. gpio::{gpioc, Output, PushPull},
  15. pac::{interrupt, Interrupt, Peripherals, EXTI},
  16. prelude::*,
  17. rtc::Rtc,
  18. };
  19. use core::cell::RefCell;
  20. use cortex_m::{asm::wfi, interrupt::Mutex};
  21. use cortex_m_rt::entry;
  22. use embedded_hal::digital::v2::OutputPin;
  23. // A type definition for the GPIO pin to be used for our LED
  24. type LEDPIN = gpioc::PC13<Output<PushPull>>;
  25. // Make LED pin globally available
  26. static G_LED: Mutex<RefCell<Option<LEDPIN>>> = Mutex::new(RefCell::new(None));
  27. // Make RTC globally available
  28. static G_RTC: Mutex<RefCell<Option<Rtc>>> = Mutex::new(RefCell::new(None));
  29. // Make EXTI registers globally available
  30. static G_EXTI: Mutex<RefCell<Option<EXTI>>> = Mutex::new(RefCell::new(None));
  31. // Toggle LED every 3 seconds
  32. const TOGGLE_INTERVAL_SECONDS: u32 = 3;
  33. // The f100 does not have an RTC, so this example is disabled
  34. #[cfg(feature = "stm32f101")]
  35. #[entry]
  36. fn main() -> ! {
  37. loop {
  38. continue;
  39. }
  40. }
  41. #[cfg(not(feature = "stm32f101"))]
  42. #[interrupt]
  43. fn RTCALARM() {
  44. static mut LED: Option<LEDPIN> = None;
  45. static mut RTC: Option<Rtc> = None;
  46. static mut EXTI: Option<EXTI> = None;
  47. let led = LED.get_or_insert_with(|| {
  48. cortex_m::interrupt::free(|cs| G_LED.borrow(cs).replace(None).unwrap())
  49. });
  50. let rtc = RTC.get_or_insert_with(|| {
  51. cortex_m::interrupt::free(|cs| G_RTC.borrow(cs).replace(None).unwrap())
  52. });
  53. let exti = EXTI.get_or_insert_with(|| {
  54. cortex_m::interrupt::free(|cs| G_EXTI.borrow(cs).replace(None).unwrap())
  55. });
  56. exti.pr.write(|w| w.pr17().set_bit());
  57. rtc.set_alarm(rtc.current_time() + TOGGLE_INTERVAL_SECONDS);
  58. let _ = led.toggle();
  59. }
  60. #[cfg(not(feature = "stm32f101"))]
  61. #[entry]
  62. fn main() -> ! {
  63. let dp = Peripherals::take().unwrap();
  64. let mut pwr = dp.PWR;
  65. let mut rcc = dp.RCC.constrain();
  66. // Set up the GPIO pin
  67. let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
  68. let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
  69. let _ = led.set_high(); // Turn off
  70. cortex_m::interrupt::free(|cs| *G_LED.borrow(cs).borrow_mut() = Some(led));
  71. // Set up the EXTI (see notes in section 18.4.2 of reference manual)
  72. let exti = dp.EXTI;
  73. exti.ftsr.write(|w| w.tr17().set_bit());
  74. exti.imr.write(|w| w.mr17().set_bit());
  75. cortex_m::interrupt::free(|cs| *G_EXTI.borrow(cs).borrow_mut() = Some(exti));
  76. // Set up the RTC
  77. // Enable writes to the backup domain
  78. let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut rcc.apb1, &mut pwr);
  79. // Start the RTC
  80. let mut rtc = Rtc::rtc(dp.RTC, &mut backup_domain);
  81. rtc.set_time(0);
  82. rtc.set_alarm(TOGGLE_INTERVAL_SECONDS);
  83. rtc.listen_alarm();
  84. cortex_m::interrupt::free(|cs| *G_RTC.borrow(cs).borrow_mut() = Some(rtc));
  85. // Enable RTCALARM IRQ
  86. unsafe { cortex_m::peripheral::NVIC::unmask(Interrupt::RTCALARM) };
  87. loop {
  88. wfi();
  89. }
  90. }