diff --git a/Cargo.toml b/Cargo.toml index a893e62..457093a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,28 +4,13 @@ version = "0.1.0" authors = ["Levi Pearson "] description = "Base binary crate for STM32F103 Blue Pill boards" categories = ["embedded", "no-std"] -edition = "2018" +edition = "2021" [dependencies] -cortex-m = "0.6.2" -cortex-m-rt = "0.6.12" -#cortex-m-semihosting = "0.3.5" -# alternate panic impls, choose only one! -#panic-halt = "0.2.0" -#panic-semihosting = "0.5.3" # requires cortex-m-semihosting -#panic-itm = "0.4.1" -#panic-abort = "0.3.2" -#panic-ramdump = "0.1.1" -#panic-persist = "0.2.1" -panic-rtt-target = { version = "0.1.0", features = ["cortex-m"] } -embedded-hal = "0.2.3" -nb = "0.1.2" -rtt-target = { version = "0.2.0", features = ["cortex-m"] } -cortex-m-rtic = "0.5.0" - -[dependencies.stm32f1xx-hal] -version = "0.6.1" -features = ["rt", "stm32f103", "medium"] +cortex-m-rtic = "1.0.0" +panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] } +rtt-target = { version = "0.3.1", features = ["cortex-m"] } +stm32f1xx-hal = { version = "0.8.0", features = ["rt", "stm32f103", "medium"] } [[bin]] name = "blue_pill_rtic" diff --git a/src/main.rs b/src/main.rs index fd7e92e..69b72a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,32 +7,43 @@ #![deny(unsafe_code)] #![no_std] -#![cfg_attr(not(doc), no_main)] +#![no_main] -use rtt_target::{rprintln, rtt_init_print}; use panic_rtt_target as _; -use stm32f1xx_hal::{ - prelude::*, - stm32, - timer::{Timer, Event}, -}; -use core::sync::atomic::{self, Ordering}; +// RTIC requires that unused interrupts are declared in "dispatchers" when +// using software tasks; these free interrupts will be used to dispatch the +// software tasks. +// +// For a list, see: +// https://docs.rs/stm32f1xx-hal/0.6.1/stm32f1xx_hal/stm32/enum.Interrupt.html +#[rtic::app(device = stm32f1xx_hal::stm32, peripherals = true, dispatchers = [TAMPER])] +mod app { -use stm32f1xx_hal as hal; + use core::sync::atomic::{self, Ordering}; + use rtt_target::{rprintln, rtt_init_print}; + use stm32f1xx_hal::{ + prelude::*, + stm32, + timer::{Event, Timer}, + }; -#[rtic::app(device = stm32f1xx_hal::stm32, peripherals = true)] -const APP: () = { - // Defining this struct makes shared resources available to tasks; if - // they can't be statically initialized, they will be initialized by - // the values returned from `init` - struct Resources { - // resources -- these are statically initialized via `init` attributes - #[init(0)] - beat: u8, + use stm32f1xx_hal as hal; - // late resources -- these must be initialized in the `init` task and - // returned in `init::LateResources` + // Defining this struct makes shared resources available to tasks; + // they will be initialized by the values returned from `init` and + // will be wrapped in a `Mutex` and must be accessed via a closure + // passed to its `lock` method. + // If you annotate a field with #[lock_free] you can opt-out of the + // mutex but it may only be shared by tasks at the same priority. + #[shared] + struct Shared {} + + // This struct defines local resources (accessed by only one task); + // they will be initialized by the values returned from `init` and + // can be accessed directly. + #[local] + struct Local { led1: hal::gpio::gpioc::PC13>, tmr2: hal::timer::CountDownTimer, tmr3: hal::timer::CountDownTimer, @@ -41,16 +52,14 @@ const APP: () = { // This task does startup config; the peripherals are passed in thanks to // `peripherals = true` in the app definition. They are the `device` and // `core` fields of `init::Context`. - // Any dynamically-configured shared resources in `Resources` must be - // returned as part of `init::LateResources`. #[init] - fn init(cx: init::Context) -> init::LateResources { + fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { rtt_init_print!(); rprintln!("init begin"); // Set everything to 8MHz using the external clock let mut flash = cx.device.FLASH.constrain(); - let mut rcc = cx.device.RCC.constrain(); + let rcc = cx.device.RCC.constrain(); let clocks = rcc .cfgr .use_hse(8.mhz()) @@ -62,26 +71,20 @@ const APP: () = { .freeze(&mut flash.acr); // LED is on pin C13, configure it for output - let mut gpioc = cx.device.GPIOC.split(&mut rcc.apb2); + let mut gpioc = cx.device.GPIOC.split(); let led1 = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); // Use TIM2 for the beat counter task - let mut tmr2 = Timer::tim2(cx.device.TIM2, &clocks, &mut rcc.apb1) - .start_count_down(1.hz()); + let mut tmr2 = Timer::tim2(cx.device.TIM2, &clocks).start_count_down(1.hz()); tmr2.listen(Event::Update); // Use TIM3 for the LED blinker task - let mut tmr3 = Timer::tim3(cx.device.TIM3, &clocks, &mut rcc.apb1) - .start_count_down(2.hz()); + let mut tmr3 = Timer::tim3(cx.device.TIM3, &clocks).start_count_down(2.hz()); tmr3.listen(Event::Update); rprintln!("init end"); - init::LateResources { - led1, - tmr2, - tmr3, - } + (Shared {}, Local { led1, tmr2, tmr3 }, init::Monotonics()) } #[idle] @@ -94,42 +97,32 @@ const APP: () = { // Update the beat counter and periodically display the current count // on the RTT channel - #[task(resources = [beat])] + // Since `beat` is a local, we can have it initialized. + #[task(local = [beat: u32 = 0])] fn beat_update(cx: beat_update::Context) { - if *cx.resources.beat % 10 == 0 { - rprintln!("TIM2 beat = {}", *cx.resources.beat); + if *cx.local.beat % 10 == 0 { + rprintln!("TIM2 beat = {}", *cx.local.beat); } - *cx.resources.beat += 1; + *cx.local.beat += 1; } // Interrupt task for TIM2, the beat counter timer - #[task(binds = TIM2, priority = 2, resources = [tmr2], spawn = [beat_update])] + #[task(binds = TIM2, priority = 2, local = [tmr2])] fn tim2(cx: tim2::Context) { // Delegate the state update to a software task - cx.spawn.beat_update().unwrap(); + beat_update::spawn().unwrap(); // Restart the timer and clear the interrupt flag - cx.resources.tmr2.start(1.hz()); - cx.resources.tmr2.clear_update_interrupt_flag(); + cx.local.tmr2.start(1.hz()); + cx.local.tmr2.clear_update_interrupt_flag(); } // Interrupt task for TIM3, the LED blink timer - #[task(binds = TIM3, priority = 1, resources = [led1, tmr3])] + #[task(binds = TIM3, priority = 1, local = [led1, tmr3])] fn tim3(cx: tim3::Context) { - cx.resources.led1.toggle().unwrap(); - cx.resources.tmr3.start(2.hz()); - cx.resources.tmr3.clear_update_interrupt_flag(); + cx.local.led1.toggle(); + cx.local.tmr3.start(2.hz()); + cx.local.tmr3.clear_update_interrupt_flag(); } - - // RTIC requires that unused interrupts are declared in an extern block when - // using software tasks; these free interrupts will be used to dispatch the - // software tasks. - // - // For a list, see: - // https://docs.rs/stm32f1xx-hal/0.6.1/stm32f1xx_hal/stm32/enum.Interrupt.html - extern "C" { - fn TAMPER(); - } -}; - +}