timer-interrupt-rtfm.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //! Uses the timer interrupt to blink a led with different frequencies.
  2. //!
  3. //! This assumes that a LED is connected to pc13 as is the case on the blue pill board.
  4. //!
  5. //! Note: Without additional hardware, PC13 should not be used to drive an LED, see page 5.1.2 of
  6. //! the reference manaual for an explanation. This is not an issue on the blue pill.
  7. #![no_std]
  8. #![no_main]
  9. // you can put a breakpoint on `rust_begin_unwind` to catch panics
  10. use panic_halt as _;
  11. use cortex_m::asm::wfi;
  12. use rtfm::app;
  13. use stm32f1xx_hal::{
  14. prelude::*,
  15. pac,
  16. timer::{ Timer, CountDownTimer, Event },
  17. gpio::{ gpioc::PC13, State, Output, PushPull },
  18. };
  19. use embedded_hal::digital::v2::OutputPin;
  20. #[app(device = stm32f1xx_hal::pac)]
  21. const APP: () = {
  22. static mut LED: PC13<Output<PushPull>> = ();
  23. static mut TIMER_HANDLER: CountDownTimer<pac::TIM1> = ();
  24. static mut LED_STATE: bool = false;
  25. #[init]
  26. fn init() -> init::LateResources {
  27. // Take ownership over the raw flash and rcc devices and convert them into the corresponding
  28. // HAL structs
  29. let mut flash = device.FLASH.constrain();
  30. let mut rcc = device.RCC.constrain();
  31. // Freeze the configuration of all the clocks in the system and store the frozen frequencies
  32. // in `clocks`
  33. let clocks = rcc.cfgr.freeze(&mut flash.acr);
  34. // Acquire the GPIOC peripheral
  35. let mut gpioc = device.GPIOC.split(&mut rcc.apb2);
  36. // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the
  37. // function in order to configure the port. For pins 0-7, crl should be passed instead
  38. let led = gpioc.pc13.into_push_pull_output_with_state(&mut gpioc.crh, State::High);
  39. // Configure the syst timer to trigger an update every second and enables interrupt
  40. let mut timer = Timer::tim1(device.TIM1, &clocks, &mut rcc.apb2)
  41. .start_count_down(1.hz());
  42. timer.listen(Event::Update);
  43. // Init the static resources to use them later through RTFM
  44. init::LateResources {
  45. LED: led,
  46. TIMER_HANDLER: timer,
  47. }
  48. }
  49. #[idle]
  50. fn idle() -> ! {
  51. loop {
  52. // Waits for interrupt
  53. wfi();
  54. }
  55. }
  56. #[interrupt(priority = 1, resources = [LED, TIMER_HANDLER, LED_STATE])]
  57. fn TIM1_UP() {
  58. // Depending on the application, you could want to delegate some of the work done here to
  59. // the idle task if you want to minimize the latency of interrupts with same priority (if
  60. // you have any). That could be done with some kind of machine state, etc.
  61. // Count used to change the timer update frequency
  62. static mut COUNT: u8 = 0;
  63. if *resources.LED_STATE {
  64. // Uses resourcers managed by rtfm to turn led off (on bluepill)
  65. resources.LED.set_high().unwrap();
  66. *resources.LED_STATE = false;
  67. } else {
  68. resources.LED.set_low().unwrap();
  69. *resources.LED_STATE = true;
  70. }
  71. *COUNT += 1;
  72. if *COUNT == 4 {
  73. // Changes timer update frequency
  74. resources.TIMER_HANDLER.start(2.hz());
  75. } else if *COUNT == 12 {
  76. resources.TIMER_HANDLER.start(1.hz());
  77. *COUNT = 0;
  78. }
  79. // Clears the update flag
  80. resources.TIMER_HANDLER.clear_update_interrupt_flag();
  81. }
  82. };