mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-23 20:22:51 +01:00
Merge #436
436: New monotonic r=AfoHT a=korken89 Design document: https://hackmd.io/vWa9GvssR8qBfUYgMZm0CQ Closes #433 Closes #432 Closes #427 Closes #426 Closes #403 Closes #332 Closes #312 Closes #309 Closes #299 Closes #292 Closes #247 Closes #219 Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
This commit is contained in:
commit
89a5c8004e
91 changed files with 908 additions and 898 deletions
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
|
@ -474,7 +474,7 @@ jobs:
|
|||
with:
|
||||
use-cross: false
|
||||
command: test
|
||||
args: --test single --features __v7
|
||||
args: --test tests --features __v7
|
||||
|
||||
# Run test suite for thumbv6m
|
||||
testv6:
|
||||
|
@ -515,7 +515,7 @@ jobs:
|
|||
with:
|
||||
use-cross: false
|
||||
command: test
|
||||
args: --test single
|
||||
args: --test tests
|
||||
|
||||
# Build documentation, check links
|
||||
docs:
|
||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -13,15 +13,11 @@ license = "MIT OR Apache-2.0"
|
|||
name = "cortex-m-rtic"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/rtic-rs/cortex-m-rtic"
|
||||
version = "0.6.0-alpha.0"
|
||||
version = "0.6.0-alpha.1"
|
||||
|
||||
[lib]
|
||||
name = "rtic"
|
||||
|
||||
[[example]]
|
||||
name = "baseline"
|
||||
required-features = ["__v7"]
|
||||
|
||||
[[example]]
|
||||
name = "periodic"
|
||||
required-features = ["__v7"]
|
||||
|
@ -57,16 +53,20 @@ required-features = ["__v7"]
|
|||
[dependencies]
|
||||
cortex-m = "0.7.0"
|
||||
cortex-m-rtic-macros = { path = "macros", version = "0.6.0-alpha.0" }
|
||||
rtic-monotonic = "0.1.0-alpha.0"
|
||||
rtic-core = "0.3.1"
|
||||
heapless = "0.5.0"
|
||||
heapless = "0.6.1"
|
||||
bare-metal = "1.0.0"
|
||||
|
||||
[dependencies.dwt-systick-monotonic]
|
||||
version = "0.1.0-alpha.0"
|
||||
optional = true
|
||||
|
||||
[build-dependencies]
|
||||
version_check = "0.9"
|
||||
|
||||
[dev-dependencies]
|
||||
lm3s6965 = "0.1.3"
|
||||
panic-halt = "0.2.0"
|
||||
cortex-m-semihosting = "0.3.3"
|
||||
|
||||
[dev-dependencies.panic-semihosting]
|
||||
|
@ -78,8 +78,8 @@ trybuild = "1"
|
|||
|
||||
[features]
|
||||
# used for testing this crate; do not use in applications
|
||||
__v7 =[]
|
||||
__min_r1_43 =[]
|
||||
__v7 = ["dwt-systick-monotonic"]
|
||||
__min_r1_43 = []
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
//! examples/baseline.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_semihosting as _;
|
||||
|
||||
// NOTE: does NOT properly work on QEMU
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
use cortex_m_semihosting::{debug, hprintln};
|
||||
use lm3s6965::Interrupt;
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
// omitted: initialization of `CYCCNT`
|
||||
|
||||
hprintln!("init(baseline = {:?})", cx.start).unwrap();
|
||||
|
||||
// `foo` inherits the baseline of `init`: `Instant(0)`
|
||||
foo::spawn().unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn foo(cx: foo::Context) {
|
||||
static mut ONCE: bool = true;
|
||||
|
||||
hprintln!("foo(baseline = {:?})", cx.scheduled).unwrap();
|
||||
|
||||
if *ONCE {
|
||||
*ONCE = false;
|
||||
|
||||
rtic::pend(Interrupt::UART0);
|
||||
} else {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
#[task(binds = UART0)]
|
||||
fn uart0(cx: uart0::Context) {
|
||||
hprintln!("UART0(baseline = {:?})", cx.start).unwrap();
|
||||
|
||||
// `foo` inherits the baseline of `UART0`: its `start` time
|
||||
foo::spawn().unwrap();
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
/// Some big struct
|
||||
pub struct BigStruct {
|
||||
|
@ -31,7 +31,7 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
let big_struct = unsafe {
|
||||
static mut BIG_STRUCT: MaybeUninit<BigStruct> = MaybeUninit::uninit();
|
||||
|
||||
|
@ -40,9 +40,12 @@ mod app {
|
|||
&mut *BIG_STRUCT.as_mut_ptr()
|
||||
};
|
||||
|
||||
init::LateResources {
|
||||
// assign the reference so we can use the resource
|
||||
big_struct,
|
||||
}
|
||||
(
|
||||
init::LateResources {
|
||||
// assign the reference so we can use the resource
|
||||
big_struct,
|
||||
},
|
||||
init::Monotonics(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ mod app {
|
|||
use lm3s6965::Interrupt;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
||||
hprintln!("init").unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -13,10 +13,10 @@ mod app {
|
|||
use lm3s6965::Interrupt;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = UART0)]
|
||||
|
|
|
@ -24,11 +24,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn().unwrap();
|
||||
foo::spawn().unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -21,11 +21,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn().unwrap();
|
||||
foo::spawn().unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -24,11 +24,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
// Direct destructure
|
||||
|
|
|
@ -7,29 +7,37 @@
|
|||
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
use rtic::cyccnt::U32Ext;
|
||||
use dwt_systick_monotonic::{
|
||||
consts::{U0, U8},
|
||||
DwtSystick,
|
||||
};
|
||||
use rtic::time::duration::Seconds;
|
||||
|
||||
#[resources]
|
||||
struct Resources {
|
||||
nothing: (),
|
||||
}
|
||||
#[monotonic(binds = SysTick, default = true)]
|
||||
type MyMono = DwtSystick<U8, U0, U0>; // 8 MHz
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
task1::spawn().ok();
|
||||
|
||||
init::LateResources { nothing: () }
|
||||
let mut dcb = cx.core.DCB;
|
||||
let dwt = cx.core.DWT;
|
||||
let systick = cx.core.SYST;
|
||||
|
||||
let mono = DwtSystick::new(&mut dcb, dwt, systick, 8_000_000);
|
||||
|
||||
(init::LateResources {}, init::Monotonics(mono))
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn task1(_cx: task1::Context) {
|
||||
task2::schedule(_cx.scheduled + 100.cycles()).ok();
|
||||
task2::spawn_after(Seconds(1_u32)).ok();
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn task2(_cx: task2::Context) {
|
||||
task1::schedule(_cx.scheduled + 100.cycles()).ok();
|
||||
task1::spawn_after(Seconds(1_u32)).ok();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@ mod app {
|
|||
use lm3s6965::Interrupt;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
||||
hprintln!("init").unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -22,10 +22,10 @@ mod app {
|
|||
use crate::foo;
|
||||
|
||||
#[init]
|
||||
fn init(_c: init::Context) -> init::LateResources {
|
||||
fn init(_c: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn(1, 2).unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
|
|
|
@ -21,11 +21,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = UART0, resources = [shared])]
|
||||
|
|
|
@ -13,14 +13,14 @@ mod app {
|
|||
use lm3s6965::Interrupt;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
// Pends the UART0 interrupt but its handler won't run until *after*
|
||||
// `init` returns because interrupts are disabled
|
||||
rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend
|
||||
|
||||
hprintln!("init").unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -12,10 +12,10 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
hprintln!("init").unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -12,7 +12,7 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
static mut X: u32 = 0;
|
||||
|
||||
// Cortex-M peripherals
|
||||
|
@ -32,6 +32,6 @@ mod app {
|
|||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,13 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
static mut Q: Queue<u32, U4> = Queue(i::Queue::new());
|
||||
|
||||
let (p, c) = Q.split();
|
||||
|
||||
// Initialization of late resources
|
||||
init::LateResources { p, c }
|
||||
(init::LateResources { p, c }, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle(resources = [c])]
|
||||
|
|
|
@ -19,10 +19,10 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::GPIOA);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
// when omitted priority is assumed to be `1`
|
||||
|
|
|
@ -12,10 +12,10 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn(/* no message */).unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -25,10 +25,10 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::GPIOA);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
// when omitted priority is assumed to be `1`
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#![no_std]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
pub struct NotSync {
|
||||
_0: PhantomData<*const ()>,
|
||||
|
@ -25,10 +25,10 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(resources = [&shared])]
|
||||
|
|
|
@ -18,11 +18,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
|
||||
init::LateResources { key: 0xdeadbeef }
|
||||
(init::LateResources { key: 0xdeadbeef }, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = UART0, resources = [&key])]
|
||||
|
|
|
@ -8,27 +8,33 @@
|
|||
use panic_semihosting as _;
|
||||
|
||||
// NOTE: does NOT work on QEMU!
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
use cortex_m_semihosting::hprintln;
|
||||
use rtic::cyccnt::{Instant, U32Ext};
|
||||
use dwt_systick_monotonic::{
|
||||
consts::{U0, U8},
|
||||
DwtSystick,
|
||||
};
|
||||
use rtic::time::duration::Seconds;
|
||||
|
||||
const PERIOD: u32 = 8_000_000;
|
||||
#[monotonic(binds = SysTick, default = true)]
|
||||
type MyMono = DwtSystick<U8, U0, U0>; // 8 MHz
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
// omitted: initialization of `CYCCNT`
|
||||
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
let mut dcb = cx.core.DCB;
|
||||
let dwt = cx.core.DWT;
|
||||
let systick = cx.core.SYST;
|
||||
|
||||
foo::schedule(cx.start + PERIOD.cycles()).unwrap();
|
||||
let mono = DwtSystick::new(&mut dcb, dwt, systick, 8_000_000);
|
||||
|
||||
init::LateResources {}
|
||||
foo::spawn_after(Seconds(1_u32)).unwrap();
|
||||
|
||||
(init::LateResources {}, init::Monotonics(mono))
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn foo(cx: foo::Context) {
|
||||
let now = Instant::now();
|
||||
hprintln!("foo(scheduled = {:?}, now = {:?})", cx.scheduled, now).unwrap();
|
||||
|
||||
foo::schedule(cx.scheduled + PERIOD.cycles()).unwrap();
|
||||
fn foo(_cx: foo::Context) {
|
||||
// Periodic
|
||||
foo::spawn_after(Seconds(1_u32)).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ mod app {
|
|||
use cortex_m_semihosting::debug;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
assert!(cortex_m::Peripherals::take().is_none());
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ mod app {
|
|||
use super::P;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
static mut MEMORY: [u8; 512] = [0; 512];
|
||||
|
||||
// Increase the capacity of the memory pool by ~4
|
||||
|
@ -33,7 +33,7 @@ mod app {
|
|||
|
||||
rtic::pend(Interrupt::I2C0);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = I2C0, priority = 2)]
|
||||
|
|
|
@ -12,10 +12,10 @@ mod app {
|
|||
use lm3s6965::Interrupt;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::GPIOA);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = GPIOA, priority = 1)]
|
||||
|
|
|
@ -19,10 +19,10 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn().unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
|
|
|
@ -27,11 +27,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
|
|
|
@ -20,11 +20,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
|
|
|
@ -5,45 +5,47 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
// NOTE: does NOT work on QEMU!
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
use cortex_m::peripheral::DWT;
|
||||
use cortex_m_semihosting::hprintln;
|
||||
use rtic::cyccnt::{Instant, U32Ext as _};
|
||||
use dwt_systick_monotonic::{
|
||||
consts::{U0, U8},
|
||||
DwtSystick,
|
||||
};
|
||||
use rtic::time::duration::Seconds;
|
||||
|
||||
#[monotonic(binds = SysTick, default = true)]
|
||||
type MyMono = DwtSystick<U8, U0, U0>; // 8 MHz
|
||||
|
||||
#[init()]
|
||||
fn init(mut cx: init::Context) -> init::LateResources {
|
||||
// Initialize (enable) the monotonic timer (CYCCNT)
|
||||
cx.core.DCB.enable_trace();
|
||||
// required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7)
|
||||
DWT::unlock();
|
||||
cx.core.DWT.enable_cycle_counter();
|
||||
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
let mut dcb = cx.core.DCB;
|
||||
let dwt = cx.core.DWT;
|
||||
let systick = cx.core.SYST;
|
||||
|
||||
// semantically, the monotonic timer is frozen at time "zero" during `init`
|
||||
// NOTE do *not* call `Instant::now` in this context; it will return a nonsense value
|
||||
let now = cx.start; // the start time of the system
|
||||
let mono = DwtSystick::new(&mut dcb, dwt, systick, 8_000_000);
|
||||
|
||||
hprintln!("init @ {:?}", now).unwrap();
|
||||
hprintln!("init").unwrap();
|
||||
|
||||
// Schedule `foo` to run 8e6 cycles (clock cycles) in the future
|
||||
foo::schedule(now + 8_000_000.cycles()).unwrap();
|
||||
// Schedule `foo` to run 1 second in the future
|
||||
foo::spawn_after(Seconds(1_u32)).unwrap();
|
||||
|
||||
// Schedule `bar` to run 4e6 cycles in the future
|
||||
bar::schedule(now + 4_000_000.cycles()).unwrap();
|
||||
// Schedule `bar` to run 2 seconds in the future
|
||||
bar::spawn_after(Seconds(2_u32)).unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics(mono))
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn foo(_: foo::Context) {
|
||||
hprintln!("foo @ {:?}", Instant::now()).unwrap();
|
||||
hprintln!("foo").unwrap();
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn bar(_: bar::Context) {
|
||||
hprintln!("bar @ {:?}", Instant::now()).unwrap();
|
||||
hprintln!("bar").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(_c: init::Context) -> init::LateResources {
|
||||
fn init(_c: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn(1, 2).unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task()]
|
||||
|
|
|
@ -12,10 +12,10 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(_c: init::Context) -> init::LateResources {
|
||||
fn init(_c: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn(1, 2).unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -26,13 +26,13 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
static mut Q: Queue<u32, U4> = Queue(i::Queue::new());
|
||||
|
||||
let (p, c) = Q.split();
|
||||
|
||||
// Initialization of late resources
|
||||
init::LateResources { p, c }
|
||||
(init::LateResources { p, c }, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle(resources = [c])]
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {}
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
// Cortex-M exception
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
|
@ -18,13 +18,16 @@ mod app {
|
|||
dummy: (), // dummy such that we have at least one late resource
|
||||
}
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {
|
||||
// The feature needs to be applied everywhere x is defined or used
|
||||
#[cfg(feature = "feature_x")]
|
||||
x: 0,
|
||||
dummy: (), // dummy such that we have at least one late resource
|
||||
}
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
(
|
||||
init::LateResources {
|
||||
// The feature needs to be applied everywhere x is defined or used
|
||||
#[cfg(feature = "feature_x")]
|
||||
x: 0,
|
||||
dummy: (), // dummy such that we have at least one late resource
|
||||
},
|
||||
init::Monotonics(),
|
||||
)
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0, QEI0])]
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
|
@ -15,11 +15,11 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
#[cfg(never)]
|
||||
static mut BAR: u32 = 0;
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -10,10 +10,10 @@ mod app {
|
|||
use cortex_m_semihosting::debug;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(lm3s6965::Interrupt::UART0);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = UART0)]
|
||||
|
|
|
@ -10,8 +10,8 @@ mod app {
|
|||
use cortex_m_semihosting::debug;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {}
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -10,9 +10,9 @@ mod app {
|
|||
use cortex_m_semihosting::debug;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
pub struct NotSend {
|
||||
_0: PhantomData<*const ()>,
|
||||
|
@ -24,10 +24,13 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {
|
||||
x: NotSend { _0: PhantomData },
|
||||
}
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
(
|
||||
init::LateResources {
|
||||
x: NotSend { _0: PhantomData },
|
||||
},
|
||||
init::Monotonics(),
|
||||
)
|
||||
}
|
||||
|
||||
#[idle(resources = [x, y])]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
|
@ -32,8 +32,8 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {}
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle(resources = [o2, &o4, s1, &s3])]
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
let _c: rtic::Peripherals = c.core;
|
||||
fn init(c: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
let _c: cortex_m::Peripherals = c.core;
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -5,52 +5,47 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
use rtic::cyccnt::{Instant, U32Ext as _};
|
||||
use dwt_systick_monotonic::{
|
||||
consts::{U0, U8},
|
||||
DwtSystick,
|
||||
};
|
||||
use rtic::time::duration::Seconds;
|
||||
|
||||
#[monotonic(binds = SysTick, default = true)]
|
||||
type MyMono = DwtSystick<U8, U0, U0>; // 8 MHz
|
||||
|
||||
#[init]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
let _: Result<(), ()> = foo::schedule(c.start + 10.cycles());
|
||||
let _: Result<(), u32> = bar::schedule(c.start + 20.cycles(), 0);
|
||||
let _: Result<(), (u32, u32)> = baz::schedule(c.start + 30.cycles(), 0, 1);
|
||||
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
let mut dcb = cx.core.DCB;
|
||||
let dwt = cx.core.DWT;
|
||||
let systick = cx.core.SYST;
|
||||
|
||||
init::LateResources {}
|
||||
let mono = DwtSystick::new(&mut dcb, dwt, systick, 8_000_000);
|
||||
|
||||
let _: Result<(), ()> = foo::spawn_after(Seconds(1_u32));
|
||||
let _: Result<(), u32> = bar::spawn_after(Seconds(2_u32), 0);
|
||||
let _: Result<(), (u32, u32)> = baz::spawn_after(Seconds(3_u32), 0, 1);
|
||||
|
||||
(init::LateResources {}, init::Monotonics(mono))
|
||||
}
|
||||
|
||||
#[idle]
|
||||
fn idle(_: idle::Context) -> ! {
|
||||
let _: Result<(), ()> = foo::schedule(Instant::now() + 40.cycles());
|
||||
let _: Result<(), u32> = bar::schedule(Instant::now() + 50.cycles(), 0);
|
||||
let _: Result<(), (u32, u32)> = baz::schedule(Instant::now() + 60.cycles(), 0, 1);
|
||||
let _: Result<(), ()> = foo::spawn_at(MyMono::now() + Seconds(3_u32));
|
||||
let _: Result<(), u32> = bar::spawn_at(MyMono::now() + Seconds(4_u32), 0);
|
||||
let _: Result<(), (u32, u32)> = baz::spawn_at(MyMono::now() + Seconds(5_u32), 0, 1);
|
||||
|
||||
loop {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[task(binds = SVCall)]
|
||||
fn svcall(c: svcall::Context) {
|
||||
let _: Result<(), ()> = foo::schedule(c.start + 70.cycles());
|
||||
let _: Result<(), u32> = bar::schedule(c.start + 80.cycles(), 0);
|
||||
let _: Result<(), (u32, u32)> = baz::schedule(c.start + 90.cycles(), 0, 1);
|
||||
}
|
||||
|
||||
#[task(binds = UART0)]
|
||||
fn uart0(c: uart0::Context) {
|
||||
let _: Result<(), ()> = foo::schedule(c.start + 100.cycles());
|
||||
let _: Result<(), u32> = bar::schedule(c.start + 110.cycles(), 0);
|
||||
let _: Result<(), (u32, u32)> = baz::schedule(c.start + 120.cycles(), 0, 1);
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn foo(c: foo::Context) {
|
||||
let _: Result<(), ()> = foo::schedule(c.scheduled + 130.cycles());
|
||||
let _: Result<(), u32> = bar::schedule(c.scheduled + 140.cycles(), 0);
|
||||
let _: Result<(), (u32, u32)> = baz::schedule(c.scheduled + 150.cycles(), 0, 1);
|
||||
}
|
||||
fn foo(_: foo::Context) {}
|
||||
|
||||
#[task]
|
||||
fn bar(_: bar::Context, _x: u32) {}
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_halt as _;
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
let _: Result<(), ()> = foo::spawn();
|
||||
let _: Result<(), u32> = bar::spawn(0);
|
||||
let _: Result<(), (u32, u32)> = baz::spawn(0, 1);
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
|
|
@ -10,10 +10,10 @@ mod app {
|
|||
use cortex_m_semihosting::debug;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
taskmain::spawn().ok();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -18,8 +18,8 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources { l: 42 }
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
(init::LateResources { l: 42 }, init::Monotonics())
|
||||
}
|
||||
|
||||
// l is task_local
|
||||
|
|
|
@ -38,10 +38,10 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
init::LateResources { e2: 2, l2: 2 }
|
||||
(init::LateResources { e2: 2, l2: 2 }, init::Monotonics())
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
||||
|
|
|
@ -12,10 +12,10 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
foo::spawn().unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -12,10 +12,10 @@ mod app {
|
|||
use cortex_m_semihosting::{debug, hprintln};
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
main::spawn().unwrap();
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -7,10 +7,16 @@
|
|||
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
|
||||
#[rtic::app(device = lm3s6965, peripherals = true, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtic::cyccnt;
|
||||
use dwt_systick_monotonic::{
|
||||
consts::{U0, U8},
|
||||
DwtSystick,
|
||||
};
|
||||
|
||||
#[monotonic(binds = SysTick, default = true)]
|
||||
type MyMono = DwtSystick<U8, U0, U0>; // 8 MHz
|
||||
|
||||
#[resources]
|
||||
struct Resources {
|
||||
|
@ -19,14 +25,19 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
let _: cyccnt::Instant = cx.start;
|
||||
let _: rtic::Peripherals = cx.core;
|
||||
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
let _: cortex_m::Peripherals = cx.core;
|
||||
let _: lm3s6965::Peripherals = cx.device;
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
init::LateResources {}
|
||||
let mut dcb = cx.core.DCB;
|
||||
let dwt = cx.core.DWT;
|
||||
let systick = cx.core.SYST;
|
||||
|
||||
let mono = DwtSystick::new(&mut dcb, dwt, systick, 8_000_000);
|
||||
|
||||
(init::LateResources {}, init::Monotonics(mono))
|
||||
}
|
||||
|
||||
#[idle]
|
||||
|
@ -38,13 +49,11 @@ mod app {
|
|||
|
||||
#[task(binds = UART0, resources = [shared])]
|
||||
fn uart0(cx: uart0::Context) {
|
||||
let _: cyccnt::Instant = cx.start;
|
||||
let _: resources::shared = cx.resources.shared;
|
||||
}
|
||||
|
||||
#[task(priority = 2, resources = [shared])]
|
||||
fn foo(cx: foo::Context) {
|
||||
let _: cyccnt::Instant = cx.scheduled;
|
||||
let _: resources::shared = cx.resources.shared;
|
||||
let _: foo::Resources = cx.resources;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
|
|||
name = "cortex-m-rtic-macros"
|
||||
readme = "../README.md"
|
||||
repository = "https://github.com/rtic-rs/cortex-m-rtic"
|
||||
version = "0.6.0-alpha.0"
|
||||
version = "0.6.0-alpha.1"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
@ -22,5 +22,5 @@ proc-macro2 = "1"
|
|||
proc-macro-error = "1"
|
||||
quote = "1"
|
||||
syn = "1"
|
||||
rtic-syntax = { git = "https://github.com/rtic-rs/rtic-syntax", branch = "master", version = "0.5.0-alpha.0" }
|
||||
rtic-syntax = "0.5.0-alpha.1"
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ use syn::{parse, Path};
|
|||
|
||||
pub struct Extra {
|
||||
pub device: Path,
|
||||
pub monotonic: Option<Path>,
|
||||
pub peripherals: bool,
|
||||
}
|
||||
|
||||
|
@ -62,18 +61,6 @@ pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<Extra> {
|
|||
for (name, task) in &app.hardware_tasks {
|
||||
let name_s = task.args.binds.to_string();
|
||||
match &*name_s {
|
||||
"SysTick" => {
|
||||
// If the timer queue is used, then SysTick is unavailable
|
||||
if app.args.monotonic.is_some() {
|
||||
return Err(parse::Error::new(
|
||||
name.span(),
|
||||
"this exception can't be used because it's being used by the runtime",
|
||||
));
|
||||
} else {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
|
||||
"NonMaskableInt" | "HardFault" => {
|
||||
return Err(parse::Error::new(
|
||||
name.span(),
|
||||
|
@ -88,7 +75,6 @@ pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<Extra> {
|
|||
if let Some(device) = app.args.device.clone() {
|
||||
Ok(Extra {
|
||||
device,
|
||||
monotonic: app.args.monotonic.clone(),
|
||||
peripherals: app.args.peripherals,
|
||||
})
|
||||
} else {
|
||||
|
|
|
@ -27,13 +27,13 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
let mut user = vec![];
|
||||
|
||||
// Generate the `main` function
|
||||
let assertion_stmts = assertions::codegen(analysis);
|
||||
let assertion_stmts = assertions::codegen(app, analysis);
|
||||
|
||||
let pre_init_stmts = pre_init::codegen(&app, analysis, extra);
|
||||
let pre_init_stmts = pre_init::codegen(app, analysis, extra);
|
||||
|
||||
let (mod_app_init, root_init, user_init, call_init) = init::codegen(app, analysis, extra);
|
||||
|
||||
let post_init_stmts = post_init::codegen(&app, analysis);
|
||||
let post_init_stmts = post_init::codegen(app, analysis);
|
||||
|
||||
let (mod_app_idle, root_idle, user_idle, call_idle) = idle::codegen(app, analysis, extra);
|
||||
|
||||
|
@ -57,12 +57,11 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
|
||||
let main = util::suffixed("main");
|
||||
mains.push(quote!(
|
||||
#[doc(hidden)]
|
||||
mod rtic_ext {
|
||||
use super::*;
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn #main() -> ! {
|
||||
let _TODO: () = ();
|
||||
|
||||
#(#assertion_stmts)*
|
||||
|
||||
#(#pre_init_stmts)*
|
||||
|
@ -90,27 +89,69 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
let user_code = &app.user_code;
|
||||
let name = &app.name;
|
||||
let device = &extra.device;
|
||||
let app_name = &app.name;
|
||||
let app_path = quote! {crate::#app_name};
|
||||
|
||||
// Get the list of all tasks
|
||||
// Currently unused, might be useful
|
||||
let task_list = analysis.tasks.clone();
|
||||
let monotonic_parts: Vec<_> = app
|
||||
.monotonics
|
||||
.iter()
|
||||
.map(|(_, monotonic)| {
|
||||
let name = &monotonic.ident;
|
||||
let name_str = &name.to_string();
|
||||
let ty = &monotonic.ty;
|
||||
let ident = util::monotonic_ident(&name_str);
|
||||
let ident = util::mark_internal_ident(&ident);
|
||||
let panic_str = &format!(
|
||||
"Use of monotonic '{}' before it was passed to the runtime",
|
||||
name_str
|
||||
);
|
||||
let doc = &format!(
|
||||
"This module holds the static implementation for `{}::now()`",
|
||||
name_str
|
||||
);
|
||||
let user_imports = &app.user_imports;
|
||||
|
||||
let mut tasks = vec![];
|
||||
quote! {
|
||||
pub use rtic::Monotonic as _;
|
||||
|
||||
if !task_list.is_empty() {
|
||||
tasks.push(quote!(
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum Tasks {
|
||||
#(#task_list),*
|
||||
#[doc = #doc]
|
||||
#[allow(non_snake_case)]
|
||||
pub mod #name {
|
||||
#(
|
||||
#[allow(unused_imports)]
|
||||
#user_imports
|
||||
)*
|
||||
|
||||
/// Read the current time from this monotonic
|
||||
pub fn now() -> rtic::time::Instant<#ty> {
|
||||
rtic::export::interrupt::free(|_| {
|
||||
use rtic::Monotonic as _;
|
||||
use rtic::time::Clock as _;
|
||||
if let Some(m) = unsafe{ #app_path::#ident.as_ref() } {
|
||||
if let Ok(v) = m.try_now() {
|
||||
v
|
||||
} else {
|
||||
unreachable!("Your monotonic is not infallible!")
|
||||
}
|
||||
} else {
|
||||
panic!(#panic_str);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let rt_err = util::rt_err_ident();
|
||||
|
||||
quote!(
|
||||
/// Implementation details
|
||||
/// The RTIC application module
|
||||
pub mod #name {
|
||||
/// Always include the device crate which contains the vector table
|
||||
use #device as you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml;
|
||||
use #device as #rt_err;
|
||||
|
||||
#(#monotonic_parts)*
|
||||
|
||||
#(#user_imports)*
|
||||
|
||||
|
@ -132,9 +173,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
|
||||
#(#root_software_tasks)*
|
||||
|
||||
/// Unused
|
||||
#(#tasks)*
|
||||
|
||||
/// app module
|
||||
#(#mod_app)*
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@ use proc_macro2::TokenStream as TokenStream2;
|
|||
use quote::quote;
|
||||
|
||||
use crate::analyze::Analysis;
|
||||
use rtic_syntax::ast::App;
|
||||
|
||||
/// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits
|
||||
pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
|
||||
pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
||||
let mut stmts = vec![];
|
||||
|
||||
for ty in &analysis.send_types {
|
||||
|
@ -15,5 +16,10 @@ pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
|
|||
stmts.push(quote!(rtic::export::assert_sync::<#ty>();));
|
||||
}
|
||||
|
||||
for (_, monotonic) in &app.monotonics {
|
||||
let ty = &monotonic.ty;
|
||||
stmts.push(quote!(rtic::export::assert_monotonic::<#ty>();));
|
||||
}
|
||||
|
||||
stmts
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rtic_syntax::ast::App;
|
|||
use crate::{analyze::Analysis, check::Extra, codegen::util};
|
||||
|
||||
/// Generates task dispatchers
|
||||
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
|
||||
pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
|
||||
let mut items = vec![];
|
||||
|
||||
let interrupts = &analysis.interrupts;
|
||||
|
@ -26,15 +26,16 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let doc = format!(
|
||||
"Software tasks to be dispatched at priority level {}",
|
||||
level,
|
||||
);
|
||||
// let doc = format!(
|
||||
// "Software tasks to be dispatched at priority level {}",
|
||||
// level,
|
||||
// );
|
||||
let t = util::spawn_t_ident(level);
|
||||
items.push(quote!(
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[doc = #doc]
|
||||
// #[doc = #doc]
|
||||
#[doc(hidden)]
|
||||
pub enum #t {
|
||||
#(#variants,)*
|
||||
}
|
||||
|
@ -42,6 +43,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
|
||||
let n = util::capacity_typenum(channel.capacity, true);
|
||||
let rq = util::rq_ident(level);
|
||||
let rq = util::mark_internal_ident(&rq);
|
||||
let (rq_ty, rq_expr) = {
|
||||
(
|
||||
quote!(rtic::export::SCRQ<#t, #n>),
|
||||
|
@ -51,12 +53,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
)
|
||||
};
|
||||
|
||||
let doc = format!(
|
||||
"Queue of tasks ready to be dispatched at priority level {}",
|
||||
level
|
||||
);
|
||||
// let doc = format!(
|
||||
// "Queue of tasks ready to be dispatched at priority level {}",
|
||||
// level
|
||||
// );
|
||||
items.push(quote!(
|
||||
#[doc = #doc]
|
||||
#[doc(hidden)]
|
||||
static mut #rq: #rq_ty = #rq_expr;
|
||||
));
|
||||
|
||||
|
@ -67,23 +69,11 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
let task = &app.software_tasks[name];
|
||||
let cfgs = &task.cfgs;
|
||||
let fq = util::fq_ident(name);
|
||||
let fq = util::mark_internal_ident(&fq);
|
||||
let inputs = util::inputs_ident(name);
|
||||
let inputs = util::mark_internal_ident(&inputs);
|
||||
let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs);
|
||||
|
||||
let (let_instant, instant) = if extra.monotonic.is_some() {
|
||||
let instants = util::instants_ident(name);
|
||||
|
||||
(
|
||||
quote!(
|
||||
let instant =
|
||||
#instants.get_unchecked(usize::from(index)).as_ptr().read();
|
||||
),
|
||||
quote!(, instant),
|
||||
)
|
||||
} else {
|
||||
(quote!(), quote!())
|
||||
};
|
||||
|
||||
let locals_new = if task.locals.is_empty() {
|
||||
quote!()
|
||||
} else {
|
||||
|
@ -97,12 +87,11 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
#t::#name => {
|
||||
let #tupled =
|
||||
#inputs.get_unchecked(usize::from(index)).as_ptr().read();
|
||||
#let_instant
|
||||
#fq.split().0.enqueue_unchecked(index);
|
||||
let priority = &rtic::export::Priority::new(PRIORITY);
|
||||
#app_path::#name(
|
||||
#locals_new
|
||||
#name::Context::new(priority #instant)
|
||||
#name::Context::new(priority)
|
||||
#(,#pats)*
|
||||
)
|
||||
}
|
||||
|
|
|
@ -29,15 +29,6 @@ pub fn codegen(
|
|||
let mut user_tasks = vec![];
|
||||
|
||||
for (name, task) in &app.hardware_tasks {
|
||||
let (let_instant, instant) = if let Some(ref m) = extra.monotonic {
|
||||
(
|
||||
Some(quote!(let instant = <#m as rtic::Monotonic>::now();)),
|
||||
Some(quote!(, instant)),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let locals_new = if task.locals.is_empty() {
|
||||
quote!()
|
||||
} else {
|
||||
|
@ -55,12 +46,10 @@ pub fn codegen(
|
|||
unsafe fn #symbol() {
|
||||
const PRIORITY: u8 = #priority;
|
||||
|
||||
#let_instant
|
||||
|
||||
rtic::export::run(PRIORITY, || {
|
||||
#app_path::#name(
|
||||
#locals_new
|
||||
#name::Context::new(&rtic::export::Priority::new(PRIORITY) #instant)
|
||||
#name::Context::new(&rtic::export::Priority::new(PRIORITY))
|
||||
)
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rtic_syntax::{ast::App, Context};
|
|||
use crate::{
|
||||
analyze::Analysis,
|
||||
check::Extra,
|
||||
codegen::{locals, module, resources_struct, util},
|
||||
codegen::{locals, module, resources_struct},
|
||||
};
|
||||
|
||||
type CodegenResult = (
|
||||
|
@ -32,32 +32,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
|
|||
|
||||
let mut root_init = vec![];
|
||||
|
||||
let late_fields = analysis
|
||||
.late_resources
|
||||
.iter()
|
||||
.flat_map(|resources| {
|
||||
resources.iter().map(|name| {
|
||||
let ty = &app.late_resources[name].ty;
|
||||
let cfgs = &app.late_resources[name].cfgs;
|
||||
|
||||
quote!(
|
||||
#(#cfgs)*
|
||||
pub #name: #ty
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let late_resources = util::late_resources_ident(&name);
|
||||
|
||||
root_init.push(quote!(
|
||||
/// Resources initialized at runtime
|
||||
#[allow(non_snake_case)]
|
||||
pub struct #late_resources {
|
||||
#(#late_fields),*
|
||||
}
|
||||
));
|
||||
|
||||
let mut locals_pat = None;
|
||||
let mut locals_new = None;
|
||||
if !init.locals.is_empty() {
|
||||
|
@ -72,10 +46,13 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
|
|||
let attrs = &init.attrs;
|
||||
let stmts = &init.stmts;
|
||||
let locals_pat = locals_pat.iter();
|
||||
|
||||
let user_init_return = quote! {#name::LateResources, #name::Monotonics};
|
||||
|
||||
let user_init = Some(quote!(
|
||||
#(#attrs)*
|
||||
#[allow(non_snake_case)]
|
||||
fn #name(#(#locals_pat,)* #context: #name::Context) -> #name::LateResources {
|
||||
fn #name(#(#locals_pat,)* #context: #name::Context) -> (#user_init_return) {
|
||||
#(#stmts)*
|
||||
}
|
||||
));
|
||||
|
@ -92,7 +69,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
|
|||
let app_path = quote! {crate::#app_name};
|
||||
let locals_new = locals_new.iter();
|
||||
let call_init = Some(
|
||||
quote!(let late = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));),
|
||||
quote!(let (late, mut monotonics) = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));),
|
||||
);
|
||||
|
||||
root_init.push(module::codegen(
|
||||
|
|
|
@ -49,6 +49,7 @@ pub fn codegen(
|
|||
));
|
||||
items.push(quote!(
|
||||
#(#cfgs)*
|
||||
#[doc(hidden)]
|
||||
static mut #name: #ty = #expr
|
||||
));
|
||||
values.push(quote!(
|
||||
|
|
|
@ -18,29 +18,16 @@ pub fn codegen(
|
|||
let mut task_cfgs = vec![];
|
||||
|
||||
let name = ctxt.ident(app);
|
||||
let app_name = &app.name;
|
||||
let app_path = quote! {crate::#app_name};
|
||||
|
||||
let mut needs_instant = false;
|
||||
let mut lt = None;
|
||||
match ctxt {
|
||||
Context::Init => {
|
||||
if let Some(m) = &extra.monotonic {
|
||||
fields.push(quote!(
|
||||
/// System start time = `Instant(0 /* cycles */)`
|
||||
pub start: <#m as rtic::Monotonic>::Instant
|
||||
));
|
||||
|
||||
values.push(quote!(start: <#m as rtic::Monotonic>::zero()));
|
||||
|
||||
fields.push(quote!(
|
||||
/// Core (Cortex-M) peripherals minus the SysTick
|
||||
pub core: rtic::Peripherals
|
||||
));
|
||||
} else {
|
||||
fields.push(quote!(
|
||||
/// Core (Cortex-M) peripherals
|
||||
pub core: rtic::export::Peripherals
|
||||
));
|
||||
}
|
||||
fields.push(quote!(
|
||||
/// Core (Cortex-M) peripherals
|
||||
pub core: rtic::export::Peripherals
|
||||
));
|
||||
|
||||
if extra.peripherals {
|
||||
let device = &extra.device;
|
||||
|
@ -66,31 +53,9 @@ pub fn codegen(
|
|||
|
||||
Context::Idle => {}
|
||||
|
||||
Context::HardwareTask(..) => {
|
||||
if let Some(m) = &extra.monotonic {
|
||||
fields.push(quote!(
|
||||
/// Time at which this handler started executing
|
||||
pub start: <#m as rtic::Monotonic>::Instant
|
||||
));
|
||||
Context::HardwareTask(_) => {}
|
||||
|
||||
values.push(quote!(start: instant));
|
||||
|
||||
needs_instant = true;
|
||||
}
|
||||
}
|
||||
|
||||
Context::SoftwareTask(..) => {
|
||||
if let Some(m) = &extra.monotonic {
|
||||
fields.push(quote!(
|
||||
/// The time at which this task was scheduled to run
|
||||
pub scheduled: <#m as rtic::Monotonic>::Instant
|
||||
));
|
||||
|
||||
values.push(quote!(scheduled: instant));
|
||||
|
||||
needs_instant = true;
|
||||
}
|
||||
}
|
||||
Context::SoftwareTask(_) => {}
|
||||
}
|
||||
|
||||
if ctxt.has_locals(app) {
|
||||
|
@ -103,6 +68,7 @@ pub fn codegen(
|
|||
|
||||
if ctxt.has_resources(app) {
|
||||
let ident = util::resources_ident(ctxt, app);
|
||||
let ident = util::mark_internal_ident(&ident);
|
||||
let lt = if resources_tick {
|
||||
lt = Some(quote!('a));
|
||||
Some(quote!('a))
|
||||
|
@ -129,12 +95,45 @@ pub fn codegen(
|
|||
}
|
||||
|
||||
if let Context::Init = ctxt {
|
||||
let init = &app.inits.first().unwrap();
|
||||
let late_resources = util::late_resources_ident(&init.name);
|
||||
let late_fields = analysis
|
||||
.late_resources
|
||||
.iter()
|
||||
.flat_map(|resources| {
|
||||
resources.iter().map(|name| {
|
||||
let ty = &app.late_resources[name].ty;
|
||||
let cfgs = &app.late_resources[name].cfgs;
|
||||
|
||||
quote!(
|
||||
#(#cfgs)*
|
||||
pub #name: #ty
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
items.push(quote!(
|
||||
#[doc(inline)]
|
||||
pub use super::#late_resources as LateResources;
|
||||
/// Resources initialized at runtime
|
||||
#[allow(non_snake_case)]
|
||||
pub struct LateResources {
|
||||
#(#late_fields),*
|
||||
}
|
||||
));
|
||||
|
||||
let monotonic_types: Vec<_> = app
|
||||
.monotonics
|
||||
.iter()
|
||||
.map(|(_, monotonic)| {
|
||||
let mono = &monotonic.ty;
|
||||
quote! {#mono}
|
||||
})
|
||||
.collect();
|
||||
|
||||
items.push(quote!(
|
||||
/// Monotonics used by the system
|
||||
#[allow(non_snake_case)]
|
||||
pub struct Monotonics(
|
||||
#(pub #monotonic_types),*
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -146,11 +145,7 @@ pub fn codegen(
|
|||
};
|
||||
|
||||
let core = if ctxt.is_init() {
|
||||
if extra.monotonic.is_some() {
|
||||
Some(quote!(core: rtic::Peripherals,))
|
||||
} else {
|
||||
Some(quote!(core: rtic::export::Peripherals,))
|
||||
}
|
||||
Some(quote!(core: rtic::export::Peripherals,))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -161,14 +156,6 @@ pub fn codegen(
|
|||
Some(quote!(priority: &#lt rtic::export::Priority))
|
||||
};
|
||||
|
||||
let instant = if needs_instant {
|
||||
let m = extra.monotonic.clone().expect("RTIC-ICE: UNREACHABLE");
|
||||
|
||||
Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
items.push(quote!(
|
||||
/// Execution context
|
||||
pub struct Context<#lt> {
|
||||
|
@ -177,7 +164,7 @@ pub fn codegen(
|
|||
|
||||
impl<#lt> Context<#lt> {
|
||||
#[inline(always)]
|
||||
pub unsafe fn new(#core #priority #instant) -> Self {
|
||||
pub unsafe fn new(#core #priority) -> Self {
|
||||
Context {
|
||||
#(#values,)*
|
||||
}
|
||||
|
@ -195,15 +182,15 @@ pub fn codegen(
|
|||
let cfgs = &spawnee.cfgs;
|
||||
// Store a copy of the task cfgs
|
||||
task_cfgs = cfgs.clone();
|
||||
let (args, tupled, _untupled, ty) = util::regroup_inputs(&spawnee.inputs);
|
||||
let (args, tupled, untupled, ty) = util::regroup_inputs(&spawnee.inputs);
|
||||
let args = &args;
|
||||
let tupled = &tupled;
|
||||
let fq = util::fq_ident(name);
|
||||
let fq = util::mark_internal_ident(&fq);
|
||||
let rq = util::rq_ident(priority);
|
||||
let rq = util::mark_internal_ident(&rq);
|
||||
let inputs = util::inputs_ident(name);
|
||||
|
||||
let app_name = &app.name;
|
||||
let app_path = quote! {crate::#app_name};
|
||||
let inputs = util::mark_internal_ident(&inputs);
|
||||
|
||||
let device = &extra.device;
|
||||
let enum_ = util::interrupt_ident();
|
||||
|
@ -216,11 +203,8 @@ pub fn codegen(
|
|||
// Spawn caller
|
||||
items.push(quote!(
|
||||
#(#cfgs)*
|
||||
/// Spawns the task directly
|
||||
pub fn spawn(#(#args,)*) -> Result<(), #ty> {
|
||||
// #let_instant // do we need it?
|
||||
use rtic::Mutex as _;
|
||||
use rtic::mutex_prelude::*;
|
||||
|
||||
let input = #tupled;
|
||||
|
||||
unsafe {
|
||||
|
@ -245,45 +229,114 @@ pub fn codegen(
|
|||
}));
|
||||
|
||||
// Schedule caller
|
||||
if let Some(m) = &extra.monotonic {
|
||||
let instants = util::instants_ident(name);
|
||||
for (_, monotonic) in &app.monotonics {
|
||||
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
|
||||
let instants = util::mark_internal_ident(&instants);
|
||||
let monotonic_name = monotonic.ident.to_string();
|
||||
|
||||
let tq = util::tq_ident();
|
||||
let tq = util::tq_ident(&monotonic.ident.to_string());
|
||||
let tq = util::mark_internal_ident(&tq);
|
||||
let t = util::schedule_t_ident();
|
||||
let m = &monotonic.ident;
|
||||
let mono_type = &monotonic.ty;
|
||||
let m_ident = util::monotonic_ident(&monotonic_name);
|
||||
let m_ident = util::mark_internal_ident(&m_ident);
|
||||
let m_isr = &monotonic.args.binds;
|
||||
let enum_ = util::interrupt_ident();
|
||||
|
||||
if monotonic.args.default {
|
||||
items.push(quote!(pub use #m::spawn_after;));
|
||||
items.push(quote!(pub use #m::spawn_at;));
|
||||
}
|
||||
|
||||
let (enable_interrupt, pend) = if &*m_isr.to_string() == "SysTick" {
|
||||
(
|
||||
quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(())
|
||||
.enable_interrupt()),
|
||||
quote!(cortex_m::peripheral::SCB::set_pendst()),
|
||||
)
|
||||
} else {
|
||||
let rt_err = util::rt_err_ident();
|
||||
(
|
||||
quote!(rtic::export::NVIC::unmask(#app_path::#rt_err::#enum_::#m_isr)),
|
||||
quote!(rtic::pend(#app_path::#rt_err::#enum_::#m_isr)),
|
||||
)
|
||||
};
|
||||
|
||||
let user_imports = &app.user_imports;
|
||||
|
||||
items.push(quote!(
|
||||
#(#cfgs)*
|
||||
pub fn schedule(
|
||||
instant: <#m as rtic::Monotonic>::Instant
|
||||
#(,#args)*
|
||||
) -> Result<(), #ty> {
|
||||
unsafe {
|
||||
use rtic::Mutex as _;
|
||||
use rtic::mutex_prelude::*;
|
||||
/// Holds methods related to this monotonic
|
||||
pub mod #m {
|
||||
#(
|
||||
#[allow(unused_imports)]
|
||||
#user_imports
|
||||
)*
|
||||
|
||||
let input = #tupled;
|
||||
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
||||
#app_path::#inputs
|
||||
.get_unchecked_mut(usize::from(index))
|
||||
.as_mut_ptr()
|
||||
.write(input);
|
||||
#(#cfgs)*
|
||||
/// Spawns the task after a set duration relative to the current time
|
||||
///
|
||||
/// This will use the time `Instant::new(0)` as baseline if called in `#[init]`,
|
||||
/// so if you use a non-resetable timer use `spawn_at` when in `#[init]`
|
||||
pub fn spawn_after<D>(
|
||||
duration: D
|
||||
#(,#args)*
|
||||
) -> Result<(), #ty>
|
||||
where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
|
||||
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
|
||||
{
|
||||
|
||||
#app_path::#instants
|
||||
.get_unchecked_mut(usize::from(index))
|
||||
.as_mut_ptr()
|
||||
.write(instant);
|
||||
|
||||
let nr = rtic::export::NotReady {
|
||||
instant,
|
||||
index,
|
||||
task: #app_path::#t::#name,
|
||||
};
|
||||
|
||||
rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr));
|
||||
|
||||
Ok(())
|
||||
let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.is_none() }) {
|
||||
rtic::time::Instant::new(0)
|
||||
} else {
|
||||
Err(input)
|
||||
#app_path::#m::now()
|
||||
};
|
||||
|
||||
spawn_at(instant + duration #(,#untupled)*)
|
||||
}
|
||||
|
||||
#(#cfgs)*
|
||||
/// Spawns the task at a fixed time instant
|
||||
pub fn spawn_at(
|
||||
instant: rtic::time::Instant<#app_path::#mono_type>
|
||||
#(,#args)*
|
||||
) -> Result<(), #ty> {
|
||||
unsafe {
|
||||
let input = #tupled;
|
||||
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
||||
#app_path::#inputs
|
||||
.get_unchecked_mut(usize::from(index))
|
||||
.as_mut_ptr()
|
||||
.write(input);
|
||||
|
||||
#app_path::#instants
|
||||
.get_unchecked_mut(usize::from(index))
|
||||
.as_mut_ptr()
|
||||
.write(instant);
|
||||
|
||||
let nr = rtic::export::NotReady {
|
||||
instant,
|
||||
index,
|
||||
task: #app_path::#t::#name,
|
||||
};
|
||||
|
||||
rtic::export::interrupt::free(|_|
|
||||
if let Some(mono) = #app_path::#m_ident.as_mut() {
|
||||
#app_path::#tq.enqueue_unchecked(
|
||||
nr,
|
||||
|| #enable_interrupt,
|
||||
|| #pend,
|
||||
mono)
|
||||
} else {
|
||||
// We can only use the timer queue if `init` has returned, and it
|
||||
// writes the `Some(monotonic)` we are accessing here.
|
||||
core::hint::unreachable_unchecked()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::quote;
|
||||
use rtic_syntax::ast::App;
|
||||
use syn::Index;
|
||||
|
||||
use crate::{analyze::Analysis, codegen::util};
|
||||
|
||||
|
@ -12,7 +13,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
|||
if !analysis.late_resources.is_empty() {
|
||||
// BTreeSet wrapped in a vector
|
||||
for name in analysis.late_resources.first().unwrap() {
|
||||
let mangled_name = util::mangle_ident(&name);
|
||||
let mangled_name = util::mark_internal_ident(&name);
|
||||
// If it's live
|
||||
let cfgs = app.late_resources[name].cfgs.clone();
|
||||
if analysis.locations.get(name).is_some() {
|
||||
|
@ -25,6 +26,19 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
|||
}
|
||||
}
|
||||
|
||||
for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
|
||||
let idx = Index {
|
||||
index: i as u32,
|
||||
span: Span::call_site(),
|
||||
};
|
||||
stmts.push(quote!(monotonics.#idx.reset();));
|
||||
|
||||
// Store the monotonic
|
||||
let name = util::monotonic_ident(&monotonic.to_string());
|
||||
let name = util::mark_internal_ident(&name);
|
||||
stmts.push(quote!(#name = Some(monotonics.#idx);));
|
||||
}
|
||||
|
||||
// Enable the interrupts -- this completes the `init`-ialization phase
|
||||
stmts.push(quote!(rtic::export::interrupt::enable();));
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ use crate::{analyze::Analysis, check::Extra, codegen::util};
|
|||
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
|
||||
let mut stmts = vec![];
|
||||
|
||||
let rt_err = util::rt_err_ident();
|
||||
|
||||
// Disable interrupts -- `init` must run with interrupts disabled
|
||||
stmts.push(quote!(rtic::export::interrupt::disable();));
|
||||
|
||||
|
@ -15,6 +17,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
for (name, task) in &app.software_tasks {
|
||||
let cap = task.args.capacity;
|
||||
let fq_ident = util::fq_ident(name);
|
||||
let fq_ident = util::mark_internal_ident(&fq_ident);
|
||||
|
||||
stmts.push(quote!(
|
||||
(0..#cap).for_each(|i| #fq_ident.enqueue_unchecked(i));
|
||||
|
@ -47,14 +50,14 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
let interrupt = util::interrupt_ident();
|
||||
stmts.push(quote!(
|
||||
core.NVIC.set_priority(
|
||||
you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#interrupt::#name,
|
||||
#rt_err::#interrupt::#name,
|
||||
rtic::export::logical2hw(#priority, #nvic_prio_bits),
|
||||
);
|
||||
));
|
||||
|
||||
// NOTE unmask the interrupt *after* setting its priority: changing the priority of a pended
|
||||
// interrupt is implementation defined
|
||||
stmts.push(quote!(rtic::export::NVIC::unmask(you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#interrupt::#name);));
|
||||
stmts.push(quote!(rtic::export::NVIC::unmask(#rt_err::#interrupt::#name);));
|
||||
}
|
||||
|
||||
// Set exception priorities
|
||||
|
@ -74,23 +77,48 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
);));
|
||||
}
|
||||
|
||||
// Initialize the SysTick if there exist a TimerQueue
|
||||
if extra.monotonic.is_some() {
|
||||
let priority = analysis.channels.keys().max().unwrap();
|
||||
// Initialize monotonic's interrupts
|
||||
for (_, monotonic) in app.monotonics.iter()
|
||||
//.map(|(ident, monotonic)| (ident, &monotonic.args.priority, &monotonic.args.binds))
|
||||
{
|
||||
let priority = &monotonic.args.priority;
|
||||
let binds = &monotonic.args.binds;
|
||||
|
||||
// Compile time assert that this priority is supported by the device
|
||||
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
|
||||
|
||||
stmts.push(quote!(core.SCB.set_priority(
|
||||
rtic::export::SystemHandler::SysTick,
|
||||
rtic::export::logical2hw(#priority, #nvic_prio_bits),
|
||||
);));
|
||||
let app_name = &app.name;
|
||||
let app_path = quote! {crate::#app_name};
|
||||
let mono_type = &monotonic.ty;
|
||||
|
||||
stmts.push(quote!(
|
||||
core.SYST.set_clock_source(rtic::export::SystClkSource::Core);
|
||||
core.SYST.enable_counter();
|
||||
core.DCB.enable_trace();
|
||||
));
|
||||
if &*binds.to_string() == "SysTick" {
|
||||
stmts.push(quote!(
|
||||
core.SCB.set_priority(
|
||||
rtic::export::SystemHandler::SysTick,
|
||||
rtic::export::logical2hw(#priority, #nvic_prio_bits),
|
||||
);
|
||||
|
||||
// Always enable monotonic interrupts if they should never be off
|
||||
if !<#mono_type as rtic::Monotonic>::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
|
||||
core::mem::transmute::<_, cortex_m::peripheral::SYST>(())
|
||||
.enable_interrupt();
|
||||
}
|
||||
));
|
||||
} else {
|
||||
// NOTE this also checks that the interrupt exists in the `Interrupt` enumeration
|
||||
let interrupt = util::interrupt_ident();
|
||||
stmts.push(quote!(
|
||||
core.NVIC.set_priority(
|
||||
#rt_err::#interrupt::#binds,
|
||||
rtic::export::logical2hw(#priority, #nvic_prio_bits),
|
||||
);
|
||||
|
||||
// Always enable monotonic interrupts if they should never be off
|
||||
if !<#mono_type as rtic::Monotonic>::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
|
||||
rtic::export::NVIC::unmask(#app_path::#rt_err::#interrupt::#binds);
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no user `#[idle]` then optimize returning from interrupt handlers
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn codegen(
|
|||
for (name, res, expr, _) in app.resources(analysis) {
|
||||
let cfgs = &res.cfgs;
|
||||
let ty = &res.ty;
|
||||
let mangled_name = util::mangle_ident(&name);
|
||||
let mangled_name = util::mark_internal_ident(&name);
|
||||
|
||||
{
|
||||
let section = if expr.is_none() {
|
||||
|
@ -42,6 +42,7 @@ pub fn codegen(
|
|||
let attrs = &res.attrs;
|
||||
mod_app.push(quote!(
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[doc(hidden)]
|
||||
#(#attrs)*
|
||||
#(#cfgs)*
|
||||
#section
|
||||
|
|
|
@ -31,7 +31,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
|
|||
None
|
||||
};
|
||||
let ty = &res.ty;
|
||||
let mangled_name = util::mangle_ident(&name);
|
||||
let mangled_name = util::mark_internal_ident(&name);
|
||||
|
||||
// let ownership = &analysis.ownerships[name];
|
||||
let r_prop = &res.properties;
|
||||
|
@ -112,6 +112,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
|
|||
|
||||
let doc = format!("Resources `{}` has access to", ctxt.ident(app));
|
||||
let ident = util::resources_ident(ctxt, app);
|
||||
let ident = util::mark_internal_ident(&ident);
|
||||
let item = quote!(
|
||||
#[allow(non_snake_case)]
|
||||
#[doc = #doc]
|
||||
|
|
|
@ -37,6 +37,7 @@ pub fn codegen(
|
|||
|
||||
// Create free queues and inputs / instants buffers
|
||||
let fq = util::fq_ident(name);
|
||||
let fq = util::mark_internal_ident(&fq);
|
||||
|
||||
let (fq_ty, fq_expr, mk_uninit): (_, _, Box<dyn Fn() -> Option<_>>) = {
|
||||
(
|
||||
|
@ -48,8 +49,9 @@ pub fn codegen(
|
|||
)
|
||||
};
|
||||
mod_app.push(quote!(
|
||||
/// Queue version of a free-list that keeps track of empty slots in
|
||||
/// the following buffers
|
||||
// /// Queue version of a free-list that keeps track of empty slots in
|
||||
// /// the following buffers
|
||||
#[doc(hidden)]
|
||||
static mut #fq: #fq_ty = #fq_expr;
|
||||
));
|
||||
|
||||
|
@ -57,24 +59,29 @@ pub fn codegen(
|
|||
.map(|_| quote!(core::mem::MaybeUninit::uninit()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(m) = &extra.monotonic {
|
||||
let instants = util::instants_ident(name);
|
||||
for (_, monotonic) in &app.monotonics {
|
||||
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
|
||||
let instants = util::mark_internal_ident(&instants);
|
||||
let mono_type = &monotonic.ty;
|
||||
|
||||
let uninit = mk_uninit();
|
||||
mod_app.push(quote!(
|
||||
#uninit
|
||||
/// Buffer that holds the instants associated to the inputs of a task
|
||||
// /// Buffer that holds the instants associated to the inputs of a task
|
||||
#[doc(hidden)]
|
||||
static mut #instants:
|
||||
[core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] =
|
||||
[core::mem::MaybeUninit<rtic::time::Instant<#mono_type>>; #cap_lit] =
|
||||
[#(#elems,)*];
|
||||
));
|
||||
}
|
||||
|
||||
let uninit = mk_uninit();
|
||||
let inputs_ident = util::inputs_ident(name);
|
||||
let inputs_ident = util::mark_internal_ident(&inputs_ident);
|
||||
mod_app.push(quote!(
|
||||
#uninit
|
||||
/// Buffer that holds the inputs of a task
|
||||
// /// Buffer that holds the inputs of a task
|
||||
#[doc(hidden)]
|
||||
static mut #inputs_ident: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
|
||||
[#(#elems,)*];
|
||||
));
|
||||
|
|
|
@ -5,10 +5,10 @@ use rtic_syntax::ast::App;
|
|||
use crate::{analyze::Analysis, check::Extra, codegen::util};
|
||||
|
||||
/// Generates timer queues and timer queue handlers
|
||||
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
|
||||
pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
|
||||
let mut items = vec![];
|
||||
|
||||
if let Some(m) = &extra.monotonic {
|
||||
if !app.monotonics.is_empty() {
|
||||
let t = util::schedule_t_ident();
|
||||
|
||||
// Enumeration of `schedule`-able tasks
|
||||
|
@ -26,9 +26,10 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let doc = "Tasks that can be scheduled".to_string();
|
||||
// let doc = "Tasks that can be scheduled".to_string();
|
||||
items.push(quote!(
|
||||
#[doc = #doc]
|
||||
// #[doc = #doc]
|
||||
#[doc(hidden)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Copy)]
|
||||
enum #t {
|
||||
|
@ -36,32 +37,54 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let tq = util::tq_ident();
|
||||
for (_, monotonic) in &app.monotonics {
|
||||
let monotonic_name = monotonic.ident.to_string();
|
||||
let tq = util::tq_ident(&monotonic_name);
|
||||
let tq = util::mark_internal_ident(&tq);
|
||||
let t = util::schedule_t_ident();
|
||||
let mono_type = &monotonic.ty;
|
||||
let m_ident = util::monotonic_ident(&monotonic_name);
|
||||
let m_ident = util::mark_internal_ident(&m_ident);
|
||||
let app_name = &app.name;
|
||||
let app_path = quote! {crate::#app_name};
|
||||
|
||||
// Static variable and resource proxy
|
||||
// Static variables and resource proxy
|
||||
{
|
||||
let doc = "Timer queue".to_string();
|
||||
// let doc = &format!("Timer queue for {}", monotonic_name);
|
||||
let cap = app
|
||||
.software_tasks
|
||||
.iter()
|
||||
.map(|(_name, task)| task.args.capacity)
|
||||
.sum();
|
||||
let n = util::capacity_typenum(cap, false);
|
||||
let tq_ty = quote!(rtic::export::TimerQueue<#m, #t, #n>);
|
||||
let tq_ty = quote!(rtic::export::TimerQueue<#mono_type, #t, #n>);
|
||||
|
||||
items.push(quote!(
|
||||
#[doc = #doc]
|
||||
#[doc(hidden)]
|
||||
static mut #tq: #tq_ty = rtic::export::TimerQueue(
|
||||
rtic::export::BinaryHeap(
|
||||
rtic::export::iBinaryHeap::new()
|
||||
)
|
||||
);
|
||||
));
|
||||
|
||||
let mono = util::monotonic_ident(&monotonic_name);
|
||||
let mono = util::mark_internal_ident(&mono);
|
||||
// let doc = &format!("Storage for {}", monotonic_name);
|
||||
|
||||
items.push(quote!(
|
||||
#[doc(hidden)]
|
||||
static mut #mono: Option<#mono_type> = None;
|
||||
));
|
||||
}
|
||||
|
||||
// Timer queue handler
|
||||
{
|
||||
let enum_ = util::interrupt_ident();
|
||||
let rt_err = util::rt_err_ident();
|
||||
|
||||
let arms = app
|
||||
.software_tasks
|
||||
.iter()
|
||||
|
@ -69,13 +92,15 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
let cfgs = &task.cfgs;
|
||||
let priority = task.args.priority;
|
||||
let rq = util::rq_ident(priority);
|
||||
let rq = util::mark_internal_ident(&rq);
|
||||
let rqt = util::spawn_t_ident(priority);
|
||||
let enum_ = util::interrupt_ident();
|
||||
|
||||
// The interrupt that runs the task dispatcher
|
||||
let interrupt = &analysis.interrupts.get(&priority).expect("RTIC-ICE: interrupt not found").0;
|
||||
|
||||
let pend = {
|
||||
quote!(
|
||||
rtic::pend(you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#enum_::#interrupt);
|
||||
rtic::pend(#rt_err::#enum_::#interrupt);
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -90,21 +115,39 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let sys_tick = util::suffixed("SysTick");
|
||||
let bound_interrupt = &monotonic.args.binds;
|
||||
let disable_isr = if &*bound_interrupt.to_string() == "SysTick" {
|
||||
quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(()).disable_interrupt())
|
||||
} else {
|
||||
quote!(rtic::export::NVIC::mask(#rt_err::#enum_::#bound_interrupt))
|
||||
};
|
||||
|
||||
items.push(quote!(
|
||||
#[no_mangle]
|
||||
unsafe fn #sys_tick() {
|
||||
use rtic::Mutex as _;
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn #bound_interrupt() {
|
||||
|
||||
while let Some((task, index)) = rtic::export::interrupt::free(|_| #tq.dequeue())
|
||||
while let Some((task, index)) = rtic::export::interrupt::free(|_|
|
||||
if let Some(mono) = #app_path::#m_ident.as_mut() {
|
||||
#tq.dequeue(|| #disable_isr, mono)
|
||||
} else {
|
||||
// We can only use the timer queue if `init` has returned, and it
|
||||
// writes the `Some(monotonic)` we are accessing here.
|
||||
core::hint::unreachable_unchecked()
|
||||
})
|
||||
{
|
||||
match task {
|
||||
#(#arms)*
|
||||
}
|
||||
}
|
||||
|
||||
rtic::export::interrupt::free(|_| if let Some(mono) = #app_path::#m_ident.as_mut() {
|
||||
mono.on_interrupt();
|
||||
});
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
items
|
||||
}
|
||||
|
|
|
@ -77,8 +77,11 @@ pub fn inputs_ident(task: &Ident) -> Ident {
|
|||
}
|
||||
|
||||
/// Generates an identifier for the `INSTANTS` buffer (`schedule` API)
|
||||
pub fn instants_ident(task: &Ident) -> Ident {
|
||||
Ident::new(&format!("{}_INSTANTS", task), Span::call_site())
|
||||
pub fn monotonic_instants_ident(task: &Ident, monotonic: &Ident) -> Ident {
|
||||
Ident::new(
|
||||
&format!("{}_{}_INSTANTS", task, monotonic),
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn interrupt_ident() -> Ident {
|
||||
|
@ -103,16 +106,8 @@ pub fn is_exception(name: &Ident) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
/// Generates a pre-reexport identifier for the "late resources" struct
|
||||
pub fn late_resources_ident(init: &Ident) -> Ident {
|
||||
Ident::new(
|
||||
&format!("{}LateResources", init.to_string()),
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Mangle an ident
|
||||
pub fn mangle_ident(ident: &Ident) -> Ident {
|
||||
/// Mark an ident as internal
|
||||
pub fn mark_internal_ident(ident: &Ident) -> Ident {
|
||||
Ident::new(
|
||||
&format!("__rtic_internal_{}", ident.to_string()),
|
||||
Span::call_site(),
|
||||
|
@ -222,7 +217,7 @@ pub fn rq_ident(priority: u8) -> Ident {
|
|||
|
||||
/// Generates an identifier for the `enum` of `schedule`-able tasks
|
||||
pub fn schedule_t_ident() -> Ident {
|
||||
Ident::new(&"SCHED_T".to_string(), Span::call_site())
|
||||
Ident::new(&"SCHED_T", Span::call_site())
|
||||
}
|
||||
|
||||
/// Generates an identifier for the `enum` of `spawn`-able tasks
|
||||
|
@ -233,14 +228,26 @@ pub fn spawn_t_ident(priority: u8) -> Ident {
|
|||
Ident::new(&format!("P{}_T", priority), Span::call_site())
|
||||
}
|
||||
|
||||
/// Suffixed identifier
|
||||
pub fn suffixed(name: &str) -> Ident {
|
||||
let span = Span::call_site();
|
||||
Ident::new(name, span)
|
||||
}
|
||||
|
||||
/// Generates an identifier for a timer queue
|
||||
///
|
||||
/// At most there is one timer queue
|
||||
pub fn tq_ident() -> Ident {
|
||||
Ident::new(&"TQ".to_string(), Span::call_site())
|
||||
pub fn tq_ident(name: &str) -> Ident {
|
||||
Ident::new(&format!("TQ_{}", name), Span::call_site())
|
||||
}
|
||||
|
||||
/// Generates an identifier for monotonic timer storage
|
||||
pub fn monotonic_ident(name: &str) -> Ident {
|
||||
Ident::new(&format!("MONOTONIC_STORAGE_{}", name), Span::call_site())
|
||||
}
|
||||
|
||||
/// The name to get better RT flag errors
|
||||
pub fn rt_err_ident() -> Ident {
|
||||
Ident::new(
|
||||
&"you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml",
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![deny(warnings)]
|
||||
// #![deny(warnings)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
|
@ -20,7 +20,7 @@ mod tests;
|
|||
#[proc_macro_attribute]
|
||||
pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut settings = Settings::default();
|
||||
settings.optimize_priorities = true;
|
||||
settings.optimize_priorities = false;
|
||||
settings.parse_binds = true;
|
||||
settings.parse_extern_interrupt = true;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ pub use cortex_m::{
|
|||
use heapless::spsc::SingleCore;
|
||||
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
|
||||
pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap};
|
||||
pub use rtic_monotonic as monotonic;
|
||||
|
||||
pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>;
|
||||
pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;
|
||||
|
@ -112,6 +113,13 @@ where
|
|||
{
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn assert_monotonic<T>()
|
||||
where
|
||||
T: monotonic::Monotonic,
|
||||
{
|
||||
}
|
||||
|
||||
/// Lock the resource proxy by setting the BASEPRI
|
||||
/// and running the closure with interrupt::free
|
||||
///
|
||||
|
|
111
src/lib.rs
111
src/lib.rs
|
@ -35,123 +35,16 @@
|
|||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
use core::ops::Sub;
|
||||
|
||||
use cortex_m::{
|
||||
interrupt::InterruptNumber,
|
||||
peripheral::{CBP, CPUID, DCB, DWT, FPB, FPU, ITM, MPU, NVIC, SCB, TPIU},
|
||||
};
|
||||
use cortex_m::{interrupt::InterruptNumber, peripheral::NVIC};
|
||||
pub use cortex_m_rtic_macros::app;
|
||||
pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex};
|
||||
pub use rtic_monotonic::{self, embedded_time as time, Monotonic};
|
||||
|
||||
#[cfg(armv7m)]
|
||||
pub mod cyccnt;
|
||||
#[doc(hidden)]
|
||||
pub mod export;
|
||||
#[doc(hidden)]
|
||||
mod tq;
|
||||
|
||||
/// `cortex_m::Peripherals` minus `SYST`
|
||||
#[allow(non_snake_case)]
|
||||
pub struct Peripherals {
|
||||
/// Cache and branch predictor maintenance operations (not present on Cortex-M0 variants)
|
||||
pub CBP: CBP,
|
||||
|
||||
/// CPUID
|
||||
pub CPUID: CPUID,
|
||||
|
||||
/// Debug Control Block
|
||||
pub DCB: DCB,
|
||||
|
||||
/// Data Watchpoint and Trace unit
|
||||
pub DWT: DWT,
|
||||
|
||||
/// Flash Patch and Breakpoint unit (not present on Cortex-M0 variants)
|
||||
pub FPB: FPB,
|
||||
|
||||
/// Floating Point Unit (only present on `thumbv7em-none-eabihf`)
|
||||
pub FPU: FPU,
|
||||
|
||||
/// Instrumentation Trace Macrocell (not present on Cortex-M0 variants)
|
||||
pub ITM: ITM,
|
||||
|
||||
/// Memory Protection Unit
|
||||
pub MPU: MPU,
|
||||
|
||||
/// Nested Vector Interrupt Controller
|
||||
pub NVIC: NVIC,
|
||||
|
||||
/// System Control Block
|
||||
pub SCB: SCB,
|
||||
|
||||
// SysTick: System Timer
|
||||
// pub SYST: SYST,
|
||||
/// Trace Port Interface Unit (not present on Cortex-M0 variants)
|
||||
pub TPIU: TPIU,
|
||||
}
|
||||
|
||||
impl From<cortex_m::Peripherals> for Peripherals {
|
||||
fn from(p: cortex_m::Peripherals) -> Self {
|
||||
Self {
|
||||
CBP: p.CBP,
|
||||
CPUID: p.CPUID,
|
||||
DCB: p.DCB,
|
||||
DWT: p.DWT,
|
||||
FPB: p.FPB,
|
||||
FPU: p.FPU,
|
||||
ITM: p.ITM,
|
||||
MPU: p.MPU,
|
||||
NVIC: p.NVIC,
|
||||
SCB: p.SCB,
|
||||
TPIU: p.TPIU,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A fraction
|
||||
pub struct Fraction {
|
||||
/// The numerator
|
||||
pub numerator: u32,
|
||||
|
||||
/// The denominator
|
||||
pub denominator: u32,
|
||||
}
|
||||
|
||||
/// A monotonic clock / counter
|
||||
pub trait Monotonic {
|
||||
/// A measurement of this clock, use `CYCCNT` as a reference implementation for `Instant`.
|
||||
/// Note that the Instant must be a signed value such as `i32`.
|
||||
type Instant: Copy + Ord + Sub;
|
||||
|
||||
/// The ratio between the system timer (SysTick) frequency and this clock frequency, i.e.
|
||||
/// `Monotonic clock * Fraction = System clock`
|
||||
///
|
||||
/// The ratio must be expressed in *reduced* `Fraction` form to prevent overflows. That is
|
||||
/// `2 / 3` instead of `4 / 6`
|
||||
fn ratio() -> Fraction;
|
||||
|
||||
/// Returns the current time
|
||||
///
|
||||
/// # Correctness
|
||||
///
|
||||
/// This function is *allowed* to return nonsensical values if called before `reset` is invoked
|
||||
/// by the runtime. Therefore application authors should *not* call this function during the
|
||||
/// `#[init]` phase.
|
||||
fn now() -> Self::Instant;
|
||||
|
||||
/// Resets the counter to *zero*
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function will be called *exactly once* by the RTIC runtime after `#[init]` returns and
|
||||
/// before tasks can start; this is also the case in multi-core applications. User code must
|
||||
/// *never* call this function.
|
||||
unsafe fn reset();
|
||||
|
||||
/// A `Self::Instant` that represents a count of *zero*
|
||||
fn zero() -> Self::Instant;
|
||||
}
|
||||
|
||||
/// Sets the given `interrupt` as pending
|
||||
///
|
||||
/// This is a convenience function around
|
||||
|
|
169
src/tq.rs
169
src/tq.rs
|
@ -1,28 +1,21 @@
|
|||
use core::{
|
||||
cmp::{self, Ordering},
|
||||
convert::TryInto,
|
||||
mem,
|
||||
ops::Sub,
|
||||
use crate::{
|
||||
time::{Clock, Instant},
|
||||
Monotonic,
|
||||
};
|
||||
|
||||
use cortex_m::peripheral::{SCB, SYST};
|
||||
use core::cmp::Ordering;
|
||||
use heapless::{binary_heap::Min, ArrayLength, BinaryHeap};
|
||||
|
||||
use crate::Monotonic;
|
||||
|
||||
pub struct TimerQueue<M, T, N>(pub BinaryHeap<NotReady<M, T>, N, Min>)
|
||||
pub struct TimerQueue<Mono, Task, N>(pub BinaryHeap<NotReady<Mono, Task>, N, Min>)
|
||||
where
|
||||
M: Monotonic,
|
||||
<M::Instant as Sub>::Output: TryInto<u32>,
|
||||
N: ArrayLength<NotReady<M, T>>,
|
||||
T: Copy;
|
||||
Mono: Monotonic,
|
||||
N: ArrayLength<NotReady<Mono, Task>>,
|
||||
Task: Copy;
|
||||
|
||||
impl<M, T, N> TimerQueue<M, T, N>
|
||||
impl<Mono, Task, N> TimerQueue<Mono, Task, N>
|
||||
where
|
||||
M: Monotonic,
|
||||
<M::Instant as Sub>::Output: TryInto<u32>,
|
||||
N: ArrayLength<NotReady<M, T>>,
|
||||
T: Copy,
|
||||
Mono: Monotonic,
|
||||
N: ArrayLength<NotReady<Mono, Task>>,
|
||||
Task: Copy,
|
||||
{
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -31,7 +24,16 @@ where
|
|||
///
|
||||
/// Enqueue a task without checking if it is full
|
||||
#[inline]
|
||||
pub unsafe fn enqueue_unchecked(&mut self, nr: NotReady<M, T>) {
|
||||
pub unsafe fn enqueue_unchecked<F1, F2>(
|
||||
&mut self,
|
||||
nr: NotReady<Mono, Task>,
|
||||
enable_interrupt: F1,
|
||||
pend_handler: F2,
|
||||
mono: &mut Mono,
|
||||
) where
|
||||
F1: FnOnce(),
|
||||
F2: FnOnce(),
|
||||
{
|
||||
let mut is_empty = true;
|
||||
// Check if the top contains a non-empty element and if that element is
|
||||
// greater than nr
|
||||
|
@ -44,111 +46,118 @@ where
|
|||
})
|
||||
.unwrap_or(true);
|
||||
if if_heap_max_greater_than_nr {
|
||||
if is_empty {
|
||||
mem::transmute::<_, SYST>(()).enable_interrupt();
|
||||
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE && is_empty {
|
||||
// mem::transmute::<_, SYST>(()).enable_interrupt();A
|
||||
mono.enable_timer();
|
||||
enable_interrupt();
|
||||
}
|
||||
|
||||
// Set SysTick pending
|
||||
SCB::set_pendst();
|
||||
// SCB::set_pendst();
|
||||
pend_handler();
|
||||
}
|
||||
|
||||
self.0.push_unchecked(nr);
|
||||
}
|
||||
|
||||
/// Check if the timer queue is empty.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unwrapper<T, E>(val: Result<T, E>) -> T {
|
||||
if let Ok(v) = val {
|
||||
v
|
||||
} else {
|
||||
unreachable!("Your monotonic is not infallible")
|
||||
}
|
||||
}
|
||||
|
||||
/// Dequeue a task from the TimerQueue
|
||||
#[inline]
|
||||
pub fn dequeue(&mut self) -> Option<(T, u8)> {
|
||||
unsafe {
|
||||
if let Some(instant) = self.0.peek().map(|p| p.instant) {
|
||||
let now = M::now();
|
||||
pub fn dequeue<F>(&mut self, disable_interrupt: F, mono: &mut Mono) -> Option<(Task, u8)>
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
mono.clear_compare_flag();
|
||||
|
||||
if instant < now {
|
||||
// task became ready
|
||||
let nr = self.0.pop_unchecked();
|
||||
if let Some(instant) = self.0.peek().map(|p| p.instant) {
|
||||
if instant <= Self::unwrapper(Clock::try_now(mono)) {
|
||||
// task became ready
|
||||
let nr = unsafe { self.0.pop_unchecked() };
|
||||
|
||||
Some((nr.task, nr.index))
|
||||
} else {
|
||||
// Set compare
|
||||
mono.set_compare(&instant);
|
||||
|
||||
// Double check that the instant we set is really in the future, else
|
||||
// dequeue. If the monotonic is fast enough it can happen that from the
|
||||
// read of now to the set of the compare, the time can overflow. This is to
|
||||
// guard against this.
|
||||
if instant <= Self::unwrapper(Clock::try_now(mono)) {
|
||||
let nr = unsafe { self.0.pop_unchecked() };
|
||||
|
||||
Some((nr.task, nr.index))
|
||||
} else {
|
||||
// set a new timeout
|
||||
const MAX: u32 = 0x00ffffff;
|
||||
|
||||
let ratio = M::ratio();
|
||||
let dur = match (instant - now).try_into().ok().and_then(|x| {
|
||||
x.checked_mul(ratio.numerator)
|
||||
.map(|x| x / ratio.denominator)
|
||||
}) {
|
||||
None => MAX,
|
||||
|
||||
// ARM Architecture Reference Manual says:
|
||||
// "Setting SYST_RVR to zero has the effect of
|
||||
// disabling the SysTick counter independently
|
||||
// of the counter enable bit."
|
||||
Some(0) => 1,
|
||||
|
||||
Some(x) => cmp::min(MAX, x),
|
||||
};
|
||||
mem::transmute::<_, SYST>(()).set_reload(dur);
|
||||
|
||||
// Start counting down from the new reload
|
||||
mem::transmute::<_, SYST>(()).clear_current();
|
||||
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// The queue is empty
|
||||
mem::transmute::<_, SYST>(()).disable_interrupt();
|
||||
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// The queue is empty, disable the interrupt.
|
||||
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
|
||||
disable_interrupt();
|
||||
mono.disable_timer();
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NotReady<M, T>
|
||||
pub struct NotReady<Mono, Task>
|
||||
where
|
||||
T: Copy,
|
||||
M: Monotonic,
|
||||
<M::Instant as Sub>::Output: TryInto<u32>,
|
||||
Task: Copy,
|
||||
Mono: Monotonic,
|
||||
{
|
||||
pub index: u8,
|
||||
pub instant: M::Instant,
|
||||
pub task: T,
|
||||
pub instant: Instant<Mono>,
|
||||
pub task: Task,
|
||||
}
|
||||
|
||||
impl<M, T> Eq for NotReady<M, T>
|
||||
impl<Mono, Task> Eq for NotReady<Mono, Task>
|
||||
where
|
||||
T: Copy,
|
||||
M: Monotonic,
|
||||
<M::Instant as Sub>::Output: TryInto<u32>,
|
||||
Task: Copy,
|
||||
Mono: Monotonic,
|
||||
{
|
||||
}
|
||||
|
||||
impl<M, T> Ord for NotReady<M, T>
|
||||
impl<Mono, Task> Ord for NotReady<Mono, Task>
|
||||
where
|
||||
T: Copy,
|
||||
M: Monotonic,
|
||||
<M::Instant as Sub>::Output: TryInto<u32>,
|
||||
Task: Copy,
|
||||
Mono: Monotonic,
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.instant.cmp(&other.instant)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, T> PartialEq for NotReady<M, T>
|
||||
impl<Mono, Task> PartialEq for NotReady<Mono, Task>
|
||||
where
|
||||
T: Copy,
|
||||
M: Monotonic,
|
||||
<M::Instant as Sub>::Output: TryInto<u32>,
|
||||
Task: Copy,
|
||||
Mono: Monotonic,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.instant == other.instant
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, T> PartialOrd for NotReady<M, T>
|
||||
impl<Mono, Task> PartialOrd for NotReady<Mono, Task>
|
||||
where
|
||||
T: Copy,
|
||||
M: Monotonic,
|
||||
<M::Instant as Sub>::Output: TryInto<u32>,
|
||||
Task: Copy,
|
||||
Mono: Monotonic,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(&other))
|
||||
|
|
|
@ -3,5 +3,5 @@ use trybuild::TestCases;
|
|||
#[test]
|
||||
fn ui() {
|
||||
let t = TestCases::new();
|
||||
t.compile_fail("ui/single/*.rs");
|
||||
t.compile_fail("ui/*.rs");
|
||||
}
|
|
@ -26,15 +26,18 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
init::LateResources {
|
||||
#[cfg(feature = "feature_l2")]
|
||||
l2: 2,
|
||||
#[cfg(not(feature = "feature_l2"))]
|
||||
l2: 5,
|
||||
}
|
||||
(
|
||||
init::LateResources {
|
||||
#[cfg(feature = "feature_l2")]
|
||||
l2: 2,
|
||||
#[cfg(not(feature = "feature_l2"))]
|
||||
l2: 5,
|
||||
},
|
||||
init::Monotonics(),
|
||||
)
|
||||
}
|
||||
|
||||
// l1 ok (task_local)
|
|
@ -5,15 +5,15 @@ error: task local resource "l2" is used by multiple tasks
|
|||
| ^^
|
||||
|
||||
error: task local resource "l2" is used by task "uart0" with priority 1
|
||||
--> $DIR/local-cfg-task-local-err.rs:51:39
|
||||
--> $DIR/local-cfg-task-local-err.rs:54:39
|
||||
|
|
||||
51 | #[cfg(feature = "feature_l2")]l2,
|
||||
54 | #[cfg(feature = "feature_l2")]l2,
|
||||
| ^^
|
||||
|
||||
error: task local resource "l2" is used by task "uart1" with priority 1
|
||||
--> $DIR/local-cfg-task-local-err.rs:60:44
|
||||
--> $DIR/local-cfg-task-local-err.rs:63:44
|
||||
|
|
||||
60 | #[cfg(not(feature = "feature_l2"))]l2
|
||||
63 | #[cfg(not(feature = "feature_l2"))]l2
|
||||
| ^^
|
||||
|
||||
warning: unused import: `cortex_m_semihosting::debug`
|
|
@ -39,10 +39,10 @@ mod app {
|
|||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
init::LateResources { e2: 2, l2: 2 }
|
||||
(init::LateResources { e2: 2, l2: 2 }, init::Monotonics())
|
||||
}
|
||||
|
||||
// `shared` cannot be accessed from this context
|
|
@ -1,16 +1,17 @@
|
|||
#![no_main]
|
||||
use panic_halt as _;
|
||||
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
#[cfg(never)]
|
||||
static mut FOO: u32 = 0;
|
||||
|
||||
FOO;
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle]
|
29
ui/locals-cfg.stderr
Normal file
29
ui/locals-cfg.stderr
Normal file
|
@ -0,0 +1,29 @@
|
|||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:12:9
|
||||
|
|
||||
12 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:22:9
|
||||
|
|
||||
22 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:32:9
|
||||
|
|
||||
32 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:40:9
|
||||
|
|
||||
40 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:48:9
|
||||
|
|
||||
48 | FOO;
|
||||
| ^^^ not found in this scope
|
|
@ -1,5 +1,6 @@
|
|||
#![no_main]
|
||||
use panic_halt as _;
|
||||
|
||||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
|
@ -43,14 +44,14 @@ mod app {
|
|||
}
|
||||
|
||||
#[init(resources = [o1, o4, o5, o6, s3])]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
fn init(c: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
c.resources.o1;
|
||||
c.resources.o4;
|
||||
c.resources.o5;
|
||||
c.resources.o6;
|
||||
c.resources.s3;
|
||||
|
||||
init::LateResources {}
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[idle(resources = [o2, &o4, s1, &s3])]
|
119
ui/resources-cfg.stderr
Normal file
119
ui/resources-cfg.stderr
Normal file
|
@ -0,0 +1,119 @@
|
|||
error[E0609]: no field `o1` on type `__rtic_internal_initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:48:21
|
||||
|
|
||||
48 | c.resources.o1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o4` on type `__rtic_internal_initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:49:21
|
||||
|
|
||||
49 | c.resources.o4;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o5` on type `__rtic_internal_initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:50:21
|
||||
|
|
||||
50 | c.resources.o5;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o6` on type `__rtic_internal_initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:51:21
|
||||
|
|
||||
51 | c.resources.o6;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `__rtic_internal_initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:52:21
|
||||
|
|
||||
52 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o2` on type `__rtic_internal_idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:59:21
|
||||
|
|
||||
59 | c.resources.o2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o4` on type `__rtic_internal_idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:60:21
|
||||
|
|
||||
60 | c.resources.o4;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s1` on type `__rtic_internal_idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:61:21
|
||||
|
|
||||
61 | c.resources.s1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `__rtic_internal_idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:62:21
|
||||
|
|
||||
62 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o3` on type `__rtic_internal_uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:69:21
|
||||
|
|
||||
69 | c.resources.o3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s1` on type `__rtic_internal_uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:70:21
|
||||
|
|
||||
70 | c.resources.s1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s2` on type `__rtic_internal_uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:71:21
|
||||
|
|
||||
71 | c.resources.s2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `__rtic_internal_uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:72:21
|
||||
|
|
||||
72 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s2` on type `__rtic_internal_uart1Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:77:21
|
||||
|
|
||||
77 | c.resources.s2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o5` on type `__rtic_internal_uart1Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:78:21
|
||||
|
|
||||
78 | c.resources.o5;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
|
@ -1,7 +0,0 @@
|
|||
#![no_main]
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
mod app {
|
||||
#[task(binds = SysTick)]
|
||||
fn sys_tick(_: sys_tick::Context) {}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
error: this exception can't be used because it's being used by the runtime
|
||||
--> $DIR/exception-systick-used.rs:6:8
|
||||
|
|
||||
6 | fn sys_tick(_: sys_tick::Context) {}
|
||||
| ^^^^^^^^
|
|
@ -1,35 +0,0 @@
|
|||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:11:9
|
||||
|
|
||||
11 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:21:9
|
||||
|
|
||||
21 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:31:9
|
||||
|
|
||||
31 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:39:9
|
||||
|
|
||||
39 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:47:9
|
||||
|
|
||||
47 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.
|
||||
|
|
||||
= note: the lang item is first defined in crate `std` (which `$CRATE` depends on)
|
||||
= note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-e12de7683a34c500.rlib
|
||||
= note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-f6dc7d4a3dd7a21d.rmeta
|
|
@ -1,125 +0,0 @@
|
|||
error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.
|
||||
|
|
||||
= note: the lang item is first defined in crate `std` (which `$CRATE` depends on)
|
||||
= note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-e12de7683a34c500.rlib
|
||||
= note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-f6dc7d4a3dd7a21d.rmeta
|
||||
|
||||
error[E0609]: no field `o1` on type `initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:47:21
|
||||
|
|
||||
47 | c.resources.o1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o4` on type `initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:48:21
|
||||
|
|
||||
48 | c.resources.o4;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o5` on type `initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:49:21
|
||||
|
|
||||
49 | c.resources.o5;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o6` on type `initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:50:21
|
||||
|
|
||||
50 | c.resources.o6;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `initResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:51:21
|
||||
|
|
||||
51 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o2` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:58:21
|
||||
|
|
||||
58 | c.resources.o2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o4` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:59:21
|
||||
|
|
||||
59 | c.resources.o4;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s1` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:60:21
|
||||
|
|
||||
60 | c.resources.s1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:61:21
|
||||
|
|
||||
61 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o3` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:68:21
|
||||
|
|
||||
68 | c.resources.o3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s1` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:69:21
|
||||
|
|
||||
69 | c.resources.s1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s2` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:70:21
|
||||
|
|
||||
70 | c.resources.s2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:71:21
|
||||
|
|
||||
71 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s2` on type `uart1Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:76:21
|
||||
|
|
||||
76 | c.resources.s2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o5` on type `uart1Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:77:21
|
||||
|
|
||||
77 | c.resources.o5;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
|
@ -3,8 +3,8 @@
|
|||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {}
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = GPIOA, priority = 1)]
|
Loading…
Reference in a new issue