Skip to content

Instantly share code, notes, and snippets.

@Yatekii
Created July 26, 2020 00:30
Show Gist options
  • Save Yatekii/28e341f58a5e3e73325851e2a9bc4fe8 to your computer and use it in GitHub Desktop.
Save Yatekii/28e341f58a5e3e73325851e2a9bc4fe8 to your computer and use it in GitHub Desktop.
#![no_std]
#![no_main]
extern crate panic_halt;
use cortex_m_rt::entry;
use stm32f4::stm32f407::{self, interrupt};
#[entry]
fn start() -> ! {
// Acquire the device peripherals. They can only be taken once ever.
let device_peripherals = stm32f407::Peripherals::take().unwrap();
// Get a reference to GPIOD and RCC to save typing.
let gpiod = &device_peripherals.GPIOD;
let rcc = &device_peripherals.RCC;
let tim2 = &device_peripherals.TIM2;
// Enable the GPIOD clock and set PD12 to be an output
rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
gpiod.moder.modify(|_, w| w.moder12().output());
// Set up the timer for slow interrupt generation
// NOTE(unsafe): The psc field has not been sufficiently documented
// to allow safe writing of arbitrary integer values, so we have to
// use unsafe here. This could be fixed by improving the SVD file.
rcc.apb1enr.modify(|_, w| w.tim2en().enabled());
tim2.dier.write(|w| w.uie().enabled());
tim2.psc.write(|w| w.psc().bits(1000));
tim2.arr.write(|w| w.arr().bits(2000));
tim2.cr1.write(|w| w.cen().enabled());
// Enable the timer interrupt in the NVIC.
unsafe { cortex_m::peripheral::NVIC::unmask(stm32f407::Interrupt::TIM2) };
// The main thread can now go to sleep.
// WFI (wait for interrupt) puts the core in sleep until an interrupt occurs.
loop {
cortex_m::asm::nop();
}
}
/// Interrupt handler for TIM2
#[interrupt]
fn TIM2() {
// NOTE(unsafe): We have to use unsafe to access the peripheral
// registers in this interrupt handler because we already used `take()`
// in the main code. In this case all our uses are safe, not least because
// the main thread only calls `wfi()` after enabling the interrupt, so
// no race conditions or other unsafe behaviour is possible.
// For ways to avoid using unsafe here, consult the Concurrency chapter:
// https://rust-embedded.github.io/book/concurrency/concurrency.html
// Clear the UIF bit to indicate the interrupt has been serviced
unsafe {
(*stm32f407::TIM2::ptr())
.sr
.modify(|_, w| w.uif().clear_bit())
};
// Read ODR12 to see if the pin is set, and if so, clear it,
// otherwise, set it. We use the atomic BSRR register to
// set/reset it without needing to read-modify-write ODR.
let ptr = stm32f407::GPIOB::ptr();
unsafe {
if (*ptr).odr.read().odr12().is_high() {
(*ptr).bsrr.write(|w| w.br12().set_bit());
} else {
(*ptr).bsrr.write(|w| w.bs12().set_bit());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment