timer-interrupt-rtic.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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 manual 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 rtic::app;
  12. use embedded_hal::digital::v2::OutputPin;
  13. use stm32f1xx_hal::{
  14. gpio::{gpioc::PC13, Output, PushPull, State},
  15. pac,
  16. prelude::*,
  17. timer::{CountDownTimer, Event, Timer},
  18. };
  19. #[app(device = stm32f1xx_hal::pac, peripherals = true)]
  20. const APP: () = {
  21. struct Resources {
  22. led: PC13<Output<PushPull>>,
  23. timer_handler: CountDownTimer<pac::TIM1>,
  24. #[init(false)]
  25. led_state: bool,
  26. }
  27. #[init]
  28. fn init(cx: init::Context) -> init::LateResources {
  29. // Take ownership over the raw flash and rcc devices and convert them into the corresponding
  30. // HAL structs
  31. let mut flash = cx.device.FLASH.constrain();
  32. let mut rcc = cx.device.RCC.constrain();
  33. // Freeze the configuration of all the clocks in the system and store the frozen frequencies
  34. // in `clocks`
  35. let clocks = rcc.cfgr.freeze(&mut flash.acr);
  36. // Acquire the GPIOC peripheral
  37. let mut gpioc = cx.device.GPIOC.split(&mut rcc.apb2);
  38. // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the
  39. // function in order to configure the port. For pins 0-7, crl should be passed instead
  40. let led = gpioc
  41. .pc13
  42. .into_push_pull_output_with_state(&mut gpioc.crh, State::High);
  43. // Configure the syst timer to trigger an update every second and enables interrupt
  44. let mut timer =
  45. Timer::tim1(cx.device.TIM1, &clocks, &mut rcc.apb2).start_count_down(1.hz());
  46. timer.listen(Event::Update);
  47. // Init the static resources to use them later through RTIC
  48. init::LateResources {
  49. led,
  50. timer_handler: timer,
  51. }
  52. }
  53. // Optional.
  54. //
  55. // https://rtic.rs/0.5/book/en/by-example/app.html#idle
  56. // > When no idle function is declared, the runtime sets the SLEEPONEXIT bit and then
  57. // > sends the microcontroller to sleep after running init.
  58. #[idle]
  59. fn idle(_cx: idle::Context) -> ! {
  60. loop {
  61. cortex_m::asm::wfi();
  62. }
  63. }
  64. #[task(binds = TIM1_UP, priority = 1, resources = [led, timer_handler, led_state])]
  65. fn tick(cx: tick::Context) {
  66. // Depending on the application, you could want to delegate some of the work done here to
  67. // the idle task if you want to minimize the latency of interrupts with same priority (if
  68. // you have any). That could be done with some kind of machine state, etc.
  69. // Count used to change the timer update frequency
  70. static mut COUNT: u8 = 0;
  71. if *cx.resources.led_state {
  72. // Uses resources managed by rtic to turn led off (on bluepill)
  73. cx.resources.led.set_high().unwrap();
  74. *cx.resources.led_state = false;
  75. } else {
  76. cx.resources.led.set_low().unwrap();
  77. *cx.resources.led_state = true;
  78. }
  79. *COUNT += 1;
  80. if *COUNT == 4 {
  81. // Changes timer update frequency
  82. cx.resources.timer_handler.start(2.hz());
  83. } else if *COUNT == 12 {
  84. cx.resources.timer_handler.start(1.hz());
  85. *COUNT = 0;
  86. }
  87. // Clears the update flag
  88. cx.resources.timer_handler.clear_update_interrupt_flag();
  89. }
  90. };