diff --git a/CHANGELOG.md b/CHANGELOG.md index 43546d9..47e30b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- Another example resembling a stop watch controlled via serial interface + ### Fixed - Incorrect PLLSRC bits when using HSE diff --git a/Cargo.toml b/Cargo.toml index 831e753..b74b332 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,10 @@ opt-level = "s" name = "blinky_timer_irq" required-features = ["stm32f072", "rt"] +[[example]] +name = "serial_stopwatch" +required-features = ["stm32f072", "rt"] + [[example]] name = "dac" required-features = ["stm32f072"] diff --git a/examples/flash_systick_fancier.rs b/examples/flash_systick_fancier.rs index 4413693..6a6d4cf 100644 --- a/examples/flash_systick_fancier.rs +++ b/examples/flash_systick_fancier.rs @@ -11,6 +11,7 @@ use cortex_m::{interrupt::Mutex, peripheral::syst::SystClkSource::Core, Peripher use cortex_m_rt::{entry, exception}; use core::cell::RefCell; +use core::mem::swap; // A type definition for the GPIO pin to be used for our LED type LEDPIN = gpiob::PB3>; @@ -31,7 +32,7 @@ fn main() -> ! { let led = gpioa.pb3.into_push_pull_output(cs); // Transfer GPIO into a shared structure - *GPIO.borrow(cs).borrow_mut() = Some(led); + swap(&mut Some(led), &mut GPIO.borrow(cs).borrow_mut()); let mut syst = cp.SYST; @@ -88,8 +89,8 @@ fn SysTick() { else { // Enter critical section cortex_m::interrupt::free(|cs| { - // Move LED pin here, leaving a None in its place - LED.replace(GPIO.borrow(cs).replace(None).unwrap()); + // Swap globally stored data with SysTick private data + swap(LED, &mut GPIO.borrow(cs).borrow_mut()); }); } } diff --git a/examples/serial_stopwatch.rs b/examples/serial_stopwatch.rs new file mode 100644 index 0000000..ec0ee18 --- /dev/null +++ b/examples/serial_stopwatch.rs @@ -0,0 +1,121 @@ +#![no_main] +#![no_std] + +use panic_halt as _; + +use stm32f0xx_hal as hal; + +use crate::hal::{ + prelude::*, + serial::Serial, + stm32::{interrupt, Interrupt, Peripherals, TIM7}, + timers::{Event, Timer}, +}; +use core::cell::RefCell; +use core::fmt::Write as _; +use core::ops::DerefMut; + +use cortex_m::{interrupt::Mutex, peripheral::Peripherals as c_m_Peripherals}; +use cortex_m_rt::entry; + +// Make timer interrupt registers globally available +static GINT: Mutex>>> = Mutex::new(RefCell::new(None)); + +#[derive(Copy, Clone)] +struct Time { + seconds: u32, + millis: u16, +} + +static TIME: Mutex> = Mutex::new(RefCell::new(Time { + seconds: 0, + millis: 0, +})); + +// Define an interupt handler, i.e. function to call when interrupt occurs. Here if our external +// interrupt trips when the timer timed out +#[interrupt] +fn TIM7() { + cortex_m::interrupt::free(|cs| { + // Move LED pin here, leaving a None in its place + GINT.borrow(cs) + .borrow_mut() + .deref_mut() + .as_mut() + .unwrap() + .wait() + .ok(); + let mut time = TIME.borrow(cs).borrow_mut(); + time.millis += 1; + if time.millis == 1000 { + time.millis = 0; + time.seconds += 1; + } + }); +} + +#[entry] +fn main() -> ! { + if let (Some(p), Some(cp)) = (Peripherals::take(), c_m_Peripherals::take()) { + let mut serial = cortex_m::interrupt::free(move |cs| { + let mut flash = p.FLASH; + let mut rcc = p.RCC.configure().sysclk(48.mhz()).freeze(&mut flash); + + // Use USART2 with PA2 and PA3 as serial port + let gpioa = p.GPIOA.split(&mut rcc); + let tx = gpioa.pa2.into_alternate_af1(cs); + let rx = gpioa.pa3.into_alternate_af1(cs); + + // Set up a timer expiring every millisecond + let mut timer = Timer::tim7(p.TIM7, 1000.hz(), &mut rcc); + + // Generate an interrupt when the timer expires + timer.listen(Event::TimeOut); + + // Move the timer into our global storage + *GINT.borrow(cs).borrow_mut() = Some(timer); + + // Enable TIM7 IRQ, set prio 1 and clear any pending IRQs + let mut nvic = cp.NVIC; + unsafe { + nvic.set_priority(Interrupt::TIM7, 1); + cortex_m::peripheral::NVIC::unmask(Interrupt::TIM7); + } + cortex_m::peripheral::NVIC::unpend(Interrupt::TIM7); + + // Set up our serial port + Serial::usart2(p.USART2, (tx, rx), 115_200.bps(), &mut rcc) + }); + + // Print a welcome message + writeln!( + serial, + "Welcome to the stop watch, hit any key to see the current value and 0 to reset\r", + ) + .ok(); + + loop { + // Wait for reception of a single byte + let received = nb::block!(serial.read()).unwrap(); + + let time = cortex_m::interrupt::free(|cs| { + let mut time = TIME.borrow(cs).borrow_mut(); + + // If we received a 0, reset the time + if received == b'0' { + time.millis = 0; + time.seconds = 0; + } + + *time + }); + + // Print the current time + writeln!(serial, "{}.{:03}s\r", time.seconds, time.millis).ok(); + } + } + + loop { + continue; + } +}