mirror of
https://github.com/rtic-rs/rtic.git
synced 2025-12-16 21:05:35 +01:00
parent
653338e799
commit
c631049efc
154 changed files with 7538 additions and 3276 deletions
61
examples/baseline.rs
Normal file
61
examples/baseline.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//! examples/baseline.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE: does NOT properly work on QEMU
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(spawn = [foo])]
|
||||
fn init() {
|
||||
println!("init(baseline = {:?})", start);
|
||||
|
||||
// `foo` inherits the baseline of `init`: `Instant(0)`
|
||||
spawn.foo().unwrap();
|
||||
}
|
||||
|
||||
#[task(schedule = [foo])]
|
||||
fn foo() {
|
||||
static mut ONCE: bool = true;
|
||||
|
||||
println!("foo(baseline = {:?})", scheduled);
|
||||
|
||||
if *ONCE {
|
||||
*ONCE = false;
|
||||
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
} else {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt(spawn = [foo])]
|
||||
fn UART0() {
|
||||
println!("UART0(baseline = {:?})", start);
|
||||
|
||||
// `foo` inherits the baseline of `UART0`: its `start` time
|
||||
spawn.foo().unwrap();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
57
examples/capacity.rs
Normal file
57
examples/capacity.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//! examples/capacity.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(spawn = [foo])]
|
||||
fn init() {
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
}
|
||||
|
||||
#[interrupt(spawn = [foo, bar])]
|
||||
fn UART0() {
|
||||
spawn.foo(0).unwrap();
|
||||
spawn.foo(1).unwrap();
|
||||
spawn.foo(2).unwrap();
|
||||
spawn.foo(3).unwrap();
|
||||
|
||||
spawn.bar().unwrap();
|
||||
}
|
||||
|
||||
#[task(capacity = 4)]
|
||||
fn foo(x: u32) {
|
||||
println!("foo({})", x);
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn bar() {
|
||||
println!("bar");
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Interrupt handlers used to dispatch software tasks
|
||||
extern "C" {
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::{app, Threshold};
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
static CO_OWNED: Foo = Foo;
|
||||
static ON: Foo = Foo;
|
||||
static OWNED: Foo = Foo;
|
||||
static SHARED: Foo = Foo;
|
||||
},
|
||||
|
||||
idle: {
|
||||
resources: [OWNED, SHARED],
|
||||
},
|
||||
|
||||
tasks: {
|
||||
SYS_TICK: {
|
||||
path: sys_tick,
|
||||
resources: [CO_OWNED, ON, SHARED],
|
||||
},
|
||||
|
||||
TIM2: {
|
||||
enabled: false,
|
||||
path: tim2,
|
||||
priority: 1,
|
||||
resources: [CO_OWNED],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fn init(_p: ::init::Peripherals, _r: ::init::Resources) {}
|
||||
|
||||
fn idle(_t: &mut Threshold, _r: ::idle::Resources) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn sys_tick(_t: &mut Threshold, _r: SYS_TICK::Resources) {}
|
||||
|
||||
fn tim2(_t: &mut Threshold, _r: TIM2::Resources) {}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
//! A showcase of the `app!` macro syntax
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::{app, Threshold};
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
static CO_OWNED: u32 = 0;
|
||||
static ON: bool = false;
|
||||
static OWNED: bool = false;
|
||||
static SHARED: bool = false;
|
||||
},
|
||||
|
||||
init: {
|
||||
// This is the path to the `init` function
|
||||
//
|
||||
// `init` doesn't necessarily has to be in the root of the crate
|
||||
path: main::init,
|
||||
},
|
||||
|
||||
idle: {
|
||||
// This is a path to the `idle` function
|
||||
//
|
||||
// `idle` doesn't necessarily has to be in the root of the crate
|
||||
path: main::idle,
|
||||
resources: [OWNED, SHARED],
|
||||
},
|
||||
|
||||
tasks: {
|
||||
SYS_TICK: {
|
||||
path: sys_tick,
|
||||
// If omitted priority is assumed to be 1
|
||||
// priority: 1,
|
||||
resources: [CO_OWNED, ON, SHARED],
|
||||
},
|
||||
|
||||
TIM2: {
|
||||
// Tasks are enabled, between `init` and `idle`, by default but they
|
||||
// can start disabled if `false` is specified here
|
||||
enabled: false,
|
||||
path: tim2,
|
||||
priority: 1,
|
||||
resources: [CO_OWNED],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mod main {
|
||||
use rtfm::{self, Resource, Threshold};
|
||||
|
||||
pub fn init(_p: ::init::Peripherals, _r: ::init::Resources) {}
|
||||
|
||||
pub fn idle(t: &mut Threshold, mut r: ::idle::Resources) -> ! {
|
||||
loop {
|
||||
*r.OWNED = !*r.OWNED;
|
||||
|
||||
if *r.OWNED {
|
||||
if r.SHARED.claim(t, |shared, _| *shared) {
|
||||
rtfm::wfi();
|
||||
}
|
||||
} else {
|
||||
r.SHARED.claim_mut(t, |shared, _| *shared = !*shared);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
|
||||
*r.ON = !*r.ON;
|
||||
|
||||
*r.CO_OWNED += 1;
|
||||
}
|
||||
|
||||
fn tim2(_t: &mut Threshold, mut r: TIM2::Resources) {
|
||||
*r.CO_OWNED += 1;
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
//! Working with resources in a generic fashion
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::{app, Resource, Threshold};
|
||||
use stm32f103xx::{GPIOA, SPI1};
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
static GPIOA: GPIOA;
|
||||
static SPI1: SPI1;
|
||||
},
|
||||
|
||||
tasks: {
|
||||
EXTI0: {
|
||||
path: exti0,
|
||||
priority: 1,
|
||||
resources: [GPIOA, SPI1],
|
||||
},
|
||||
|
||||
EXTI1: {
|
||||
path: exti1,
|
||||
priority: 2,
|
||||
resources: [GPIOA, SPI1],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fn init(p: init::Peripherals) -> init::LateResources {
|
||||
init::LateResources {
|
||||
GPIOA: p.device.GPIOA,
|
||||
SPI1: p.device.SPI1,
|
||||
}
|
||||
}
|
||||
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
// A generic function that uses some resources
|
||||
fn work<G, S>(t: &mut Threshold, gpioa: &G, spi1: &S)
|
||||
where
|
||||
G: Resource<Data = GPIOA>,
|
||||
S: Resource<Data = SPI1>,
|
||||
{
|
||||
gpioa.claim(t, |_gpioa, t| {
|
||||
// drive NSS low
|
||||
|
||||
spi1.claim(t, |_spi1, _| {
|
||||
// transfer data
|
||||
});
|
||||
|
||||
// drive NSS high
|
||||
});
|
||||
}
|
||||
|
||||
// This task needs critical sections to access the resources
|
||||
fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
|
||||
work(t, &r.GPIOA, &r.SPI1);
|
||||
}
|
||||
|
||||
// This task has direct access to the resources
|
||||
fn exti1(t: &mut Threshold, r: EXTI1::Resources) {
|
||||
work(t, &r.GPIOA, &r.SPI1);
|
||||
}
|
||||
43
examples/idle.rs
Normal file
43
examples/idle.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//! examples/idle.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init]
|
||||
fn init() {
|
||||
println!("init");
|
||||
}
|
||||
|
||||
#[idle]
|
||||
fn idle() -> ! {
|
||||
static mut X: u32 = 0;
|
||||
|
||||
// Safe access to local `static mut` variable
|
||||
let _x: &'static mut u32 = X;
|
||||
|
||||
println!("idle");
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
loop {}
|
||||
}
|
||||
};
|
||||
44
examples/init.rs
Normal file
44
examples/init.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
//! examples/init.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::app;
|
||||
|
||||
// NOTE: This convenience macro will appear in all the other examples and
|
||||
// will always look the same
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init]
|
||||
fn init() {
|
||||
static mut X: u32 = 0;
|
||||
|
||||
// Cortex-M peripherals
|
||||
let _core: rtfm::Peripherals = core;
|
||||
|
||||
// Device specific peripherals
|
||||
let _device: lm3s6965::Peripherals = device;
|
||||
|
||||
// Safe access to local `static mut` variable
|
||||
let _x: &'static mut u32 = X;
|
||||
|
||||
println!("init");
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
};
|
||||
61
examples/interrupt.rs
Normal file
61
examples/interrupt.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//! examples/interrupt.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init]
|
||||
fn init() {
|
||||
// Pends the UART0 interrupt but its handler won't run until *after*
|
||||
// `init` returns because interrupts are disabled
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
|
||||
println!("init");
|
||||
}
|
||||
|
||||
#[idle]
|
||||
fn idle() -> ! {
|
||||
// interrupts are enabled again; the `UART0` handler runs at this point
|
||||
|
||||
println!("idle");
|
||||
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn UART0() {
|
||||
static mut TIMES: u32 = 0;
|
||||
|
||||
// Safe access to local `static mut` variable
|
||||
*TIMES += 1;
|
||||
|
||||
println!(
|
||||
"UART0 called {} time{}",
|
||||
*TIMES,
|
||||
if *TIMES > 1 { "s" } else { "" }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
//! Demonstrates initialization of resources in `init`.
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::{app, Threshold};
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
// Usually, resources are initialized with a constant initializer:
|
||||
static ON: bool = false;
|
||||
|
||||
// However, there are cases where this is not possible or not desired.
|
||||
// For example, there may not be a sensible value to use, or the type may
|
||||
// not be constructible in a constant (like `Vec`).
|
||||
//
|
||||
// While it is possible to use an `Option` in some cases, that requires
|
||||
// you to properly initialize it and `.unwrap()` it at every use. It
|
||||
// also consumes more memory.
|
||||
//
|
||||
// To solve this, it is possible to defer initialization of resources to
|
||||
// `init` by omitting the initializer. Doing that will require `init` to
|
||||
// return the values of all "late" resources.
|
||||
static IP_ADDRESS: u32;
|
||||
|
||||
// PORT is used by 2 tasks, making it a shared resource. This just tests
|
||||
// another internal code path and is not important for the example.
|
||||
static PORT: u16;
|
||||
},
|
||||
|
||||
idle: {
|
||||
// Test that late resources can be used in idle
|
||||
resources: [IP_ADDRESS],
|
||||
},
|
||||
|
||||
tasks: {
|
||||
SYS_TICK: {
|
||||
priority: 1,
|
||||
path: sys_tick,
|
||||
resources: [IP_ADDRESS, PORT, ON],
|
||||
},
|
||||
|
||||
EXTI0: {
|
||||
priority: 2,
|
||||
path: exti0,
|
||||
resources: [PORT],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The signature of `init` is now required to have a specific return type.
|
||||
fn init(_p: init::Peripherals, _r: init::Resources) -> init::LateResources {
|
||||
// `init::Resources` does not contain `IP_ADDRESS`, since it is not yet
|
||||
// initialized.
|
||||
//_r.IP_ADDRESS; // doesn't compile
|
||||
|
||||
// ...obtain value for IP_ADDRESS from EEPROM/DHCP...
|
||||
let ip_address = 0x7f000001;
|
||||
|
||||
init::LateResources {
|
||||
// This struct will contain fields for all resources with omitted
|
||||
// initializers.
|
||||
IP_ADDRESS: ip_address,
|
||||
PORT: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
|
||||
// Other tasks can access late resources like any other, since they are
|
||||
// guaranteed to be initialized when tasks are run.
|
||||
|
||||
r.IP_ADDRESS;
|
||||
}
|
||||
|
||||
fn exti0(_t: &mut Threshold, _r: EXTI0::Resources) {}
|
||||
|
||||
fn idle(_t: &mut Threshold, _r: idle::Resources) -> ! {
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
65
examples/late.rs
Normal file
65
examples/late.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
//! examples/late.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use heapless::{
|
||||
consts::*,
|
||||
spsc::{Consumer, Producer, Queue},
|
||||
};
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
// Late resources
|
||||
static mut P: Producer<'static, u32, U4> = ();
|
||||
static mut C: Consumer<'static, u32, U4> = ();
|
||||
|
||||
#[init]
|
||||
fn init() {
|
||||
// NOTE: we use `Option` here to work around the lack of
|
||||
// a stable `const` constructor
|
||||
static mut Q: Option<Queue<u32, U4>> = None;
|
||||
|
||||
*Q = Some(Queue::new());
|
||||
let (p, c) = Q.as_mut().unwrap().split();
|
||||
|
||||
// Initialization of late resources
|
||||
P = p;
|
||||
C = c;
|
||||
}
|
||||
|
||||
#[idle(resources = [C])]
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
if let Some(byte) = resources.C.dequeue() {
|
||||
println!("received message: {}", byte);
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
} else {
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt(resources = [P])]
|
||||
fn UART0() {
|
||||
resources.P.enqueue(42).unwrap();
|
||||
}
|
||||
};
|
||||
71
examples/lock.rs
Normal file
71
examples/lock.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
//! examples/lock.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
static mut SHARED: u32 = 0;
|
||||
|
||||
#[init]
|
||||
fn init() {
|
||||
rtfm::pend(Interrupt::GPIOA);
|
||||
}
|
||||
|
||||
// when omitted priority is assumed to be `1`
|
||||
#[interrupt(resources = [SHARED])]
|
||||
fn GPIOA() {
|
||||
println!("A");
|
||||
|
||||
// the lower priority task requires a critical section to access the data
|
||||
resources.SHARED.lock(|shared| {
|
||||
// data can only be modified within this critical section (closure)
|
||||
*shared += 1;
|
||||
|
||||
// GPIOB will *not* run right now due to the critical section
|
||||
rtfm::pend(Interrupt::GPIOB);
|
||||
|
||||
println!("B - SHARED = {}", *shared);
|
||||
|
||||
// GPIOC does not contend for `SHARED` so it's allowed to run now
|
||||
rtfm::pend(Interrupt::GPIOC);
|
||||
});
|
||||
|
||||
// critical section is over: GPIOB can now start
|
||||
|
||||
println!("E");
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#[interrupt(priority = 2, resources = [SHARED])]
|
||||
fn GPIOB() {
|
||||
// the higher priority task does *not* need a critical section
|
||||
*resources.SHARED += 1;
|
||||
|
||||
println!("D - SHARED = {}", *resources.SHARED);
|
||||
}
|
||||
|
||||
#[interrupt(priority = 3)]
|
||||
fn GPIOC() {
|
||||
println!("C");
|
||||
}
|
||||
};
|
||||
61
examples/message.rs
Normal file
61
examples/message.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//! examples/message.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(spawn = [foo])]
|
||||
fn init() {
|
||||
spawn.foo(/* no message */).unwrap();
|
||||
}
|
||||
|
||||
#[task(spawn = [bar])]
|
||||
fn foo() {
|
||||
static mut COUNT: u32 = 0;
|
||||
|
||||
println!("foo");
|
||||
|
||||
spawn.bar(*COUNT).unwrap();
|
||||
*COUNT += 1;
|
||||
}
|
||||
|
||||
#[task(spawn = [baz])]
|
||||
fn bar(x: u32) {
|
||||
println!("bar({})", x);
|
||||
|
||||
spawn.baz(x + 1, x + 2).unwrap();
|
||||
}
|
||||
|
||||
#[task(spawn = [foo])]
|
||||
fn baz(x: u32, y: u32) {
|
||||
println!("baz({}, {})", x, y);
|
||||
|
||||
if x + y > 4 {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
spawn.foo().unwrap();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
//! Nesting claims and how the preemption threshold works
|
||||
//!
|
||||
//! If you run this program you'll hit the breakpoints as indicated by the
|
||||
//! letters in the comments: A, then B, then C, etc.
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::{app, Resource, Threshold};
|
||||
use stm32f103xx::Interrupt;
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
static LOW: u64 = 0;
|
||||
static HIGH: u64 = 0;
|
||||
},
|
||||
|
||||
tasks: {
|
||||
EXTI0: {
|
||||
path: exti0,
|
||||
priority: 1,
|
||||
resources: [LOW, HIGH],
|
||||
},
|
||||
|
||||
EXTI1: {
|
||||
path: exti1,
|
||||
priority: 2,
|
||||
resources: [LOW],
|
||||
},
|
||||
|
||||
EXTI2: {
|
||||
path: exti2,
|
||||
priority: 3,
|
||||
resources: [HIGH],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fn init(_p: init::Peripherals, _r: init::Resources) {}
|
||||
|
||||
fn idle() -> ! {
|
||||
// A
|
||||
rtfm::bkpt();
|
||||
|
||||
// Sets task `exti0` as pending
|
||||
//
|
||||
// Because `exti0` has higher priority than `idle` it will be executed
|
||||
// immediately
|
||||
rtfm::set_pending(Interrupt::EXTI0); // ~> exti0
|
||||
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn exti0(
|
||||
t: &mut Threshold,
|
||||
EXTI0::Resources {
|
||||
LOW: mut low,
|
||||
HIGH: mut high,
|
||||
}: EXTI0::Resources,
|
||||
) {
|
||||
// Because this task has a priority of 1 the preemption threshold `t` also
|
||||
// starts at 1
|
||||
|
||||
// B
|
||||
rtfm::bkpt();
|
||||
|
||||
// Because `exti1` has higher priority than `exti0` it can preempt it
|
||||
rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
|
||||
|
||||
// A claim creates a critical section
|
||||
low.claim_mut(t, |_low, t| {
|
||||
// This claim increases the preemption threshold to 2
|
||||
//
|
||||
// 2 is just high enough to not race with task `exti1` for access to the
|
||||
// `LOW` resource
|
||||
|
||||
// D
|
||||
rtfm::bkpt();
|
||||
|
||||
// Now `exti1` can't preempt this task because its priority is equal to
|
||||
// the current preemption threshold
|
||||
rtfm::set_pending(Interrupt::EXTI1);
|
||||
|
||||
// But `exti2` can, because its priority is higher than the current
|
||||
// preemption threshold
|
||||
rtfm::set_pending(Interrupt::EXTI2); // ~> exti2
|
||||
|
||||
// F
|
||||
rtfm::bkpt();
|
||||
|
||||
// Claims can be nested
|
||||
high.claim_mut(t, |_high, _| {
|
||||
// This claim increases the preemption threshold to 3
|
||||
|
||||
// Now `exti2` can't preempt this task
|
||||
rtfm::set_pending(Interrupt::EXTI2);
|
||||
|
||||
// G
|
||||
rtfm::bkpt();
|
||||
});
|
||||
|
||||
// Upon leaving the critical section the preemption threshold drops back
|
||||
// to 2 and `exti2` immediately preempts this task
|
||||
// ~> exti2
|
||||
});
|
||||
|
||||
// Once again the preemption threshold drops but this time to 1. Now the
|
||||
// pending `exti1` task can preempt this task
|
||||
// ~> exti1
|
||||
}
|
||||
|
||||
fn exti1(_t: &mut Threshold, _r: EXTI1::Resources) {
|
||||
// C, I
|
||||
rtfm::bkpt();
|
||||
}
|
||||
|
||||
fn exti2(_t: &mut Threshold, _r: EXTI2::Resources) {
|
||||
// E, H
|
||||
rtfm::bkpt();
|
||||
}
|
||||
58
examples/not-send.rs
Normal file
58
examples/not-send.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
//! `examples/not-send.rs`
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_halt;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::app;
|
||||
|
||||
pub struct NotSend {
|
||||
_0: PhantomData<*const ()>,
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
static mut SHARED: Option<NotSend> = None;
|
||||
|
||||
#[init(spawn = [baz, quux])]
|
||||
fn init() {
|
||||
spawn.baz().unwrap();
|
||||
spawn.quux().unwrap();
|
||||
}
|
||||
|
||||
#[task(spawn = [bar])]
|
||||
fn foo() {
|
||||
// scenario 1: message passed to task that runs at the same priority
|
||||
spawn.bar(NotSend { _0: PhantomData }).ok();
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn bar(_x: NotSend) {
|
||||
// scenario 1
|
||||
}
|
||||
|
||||
#[task(priority = 2, resources = [SHARED])]
|
||||
fn baz() {
|
||||
// scenario 2: resource shared between tasks that run at the same priority
|
||||
*resources.SHARED = Some(NotSend { _0: PhantomData });
|
||||
}
|
||||
|
||||
#[task(priority = 2, resources = [SHARED])]
|
||||
fn quux() {
|
||||
// scenario 2
|
||||
let _not_send = resources.SHARED.take().unwrap();
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
41
examples/not-sync.rs
Normal file
41
examples/not-sync.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
//! `examples/not-sync.rs`
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_halt;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::app;
|
||||
|
||||
pub struct NotSync {
|
||||
_0: PhantomData<*const ()>,
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
static SHARED: NotSync = NotSync { _0: PhantomData };
|
||||
|
||||
#[init]
|
||||
fn init() {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#[task(resources = [SHARED])]
|
||||
fn foo() {
|
||||
let _: &NotSync = resources.SHARED;
|
||||
}
|
||||
|
||||
#[task(resources = [SHARED])]
|
||||
fn bar() {
|
||||
let _: &NotSync = resources.SHARED;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
//! An application with one task
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use cortex_m::peripheral::syst::SystClkSource;
|
||||
use rtfm::{app, Threshold};
|
||||
use stm32f103xx::GPIOC;
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
// Here data resources are declared
|
||||
//
|
||||
// Data resources are static variables that are safe to share across tasks
|
||||
resources: {
|
||||
// Declaration of resources looks exactly like declaration of static
|
||||
// variables
|
||||
static ON: bool = false;
|
||||
},
|
||||
|
||||
// Here tasks are declared
|
||||
//
|
||||
// Each task corresponds to an interrupt or an exception. Every time the
|
||||
// interrupt or exception becomes *pending* the corresponding task handler
|
||||
// will be executed.
|
||||
tasks: {
|
||||
// Here we declare that we'll use the SYS_TICK exception as a task
|
||||
SYS_TICK: {
|
||||
// Path to the task handler
|
||||
path: sys_tick,
|
||||
|
||||
// These are the resources this task has access to.
|
||||
//
|
||||
// The resources listed here must also appear in `app.resources`
|
||||
resources: [ON],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn init(mut p: init::Peripherals, r: init::Resources) {
|
||||
// `init` can modify all the `resources` declared in `app!`
|
||||
r.ON;
|
||||
|
||||
// power on GPIOC
|
||||
p.device.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
|
||||
|
||||
// configure PC13 as output
|
||||
p.device.GPIOC.bsrr.write(|w| w.bs13().set());
|
||||
p.device
|
||||
.GPIOC
|
||||
.crh
|
||||
.modify(|_, w| w.mode13().output().cnf13().push());
|
||||
|
||||
// configure the system timer to generate one interrupt every second
|
||||
p.core.SYST.set_clock_source(SystClkSource::Core);
|
||||
p.core.SYST.set_reload(8_000_000); // 1s
|
||||
p.core.SYST.enable_interrupt();
|
||||
p.core.SYST.enable_counter();
|
||||
}
|
||||
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
// This is the task handler of the SYS_TICK exception
|
||||
//
|
||||
// `_t` is the preemption threshold token. We won't use it in this program.
|
||||
//
|
||||
// `r` is the set of resources this task has access to. `SYS_TICK::Resources`
|
||||
// has one field per resource declared in `app!`.
|
||||
#[allow(unsafe_code)]
|
||||
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
|
||||
// toggle state
|
||||
*r.ON = !*r.ON;
|
||||
|
||||
if *r.ON {
|
||||
// set the pin PC13 high
|
||||
// NOTE(unsafe) atomic write to a stateless register
|
||||
unsafe {
|
||||
(*GPIOC::ptr()).bsrr.write(|w| w.bs13().set());
|
||||
}
|
||||
} else {
|
||||
// set the pin PC13 low
|
||||
// NOTE(unsafe) atomic write to a stateless register
|
||||
unsafe {
|
||||
(*GPIOC::ptr()).bsrr.write(|w| w.br13().reset());
|
||||
}
|
||||
}
|
||||
}
|
||||
43
examples/periodic.rs
Normal file
43
examples/periodic.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//! examples/periodic.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use rtfm::{app, Instant};
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const PERIOD: u32 = 8_000_000;
|
||||
|
||||
// NOTE: does NOT work on QEMU!
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(schedule = [foo])]
|
||||
fn init() {
|
||||
schedule.foo(Instant::now() + PERIOD.cycles()).unwrap();
|
||||
}
|
||||
|
||||
#[task(schedule = [foo])]
|
||||
fn foo() {
|
||||
let now = Instant::now();
|
||||
println!("foo(scheduled = {:?}, now = {:?})", scheduled, now);
|
||||
|
||||
schedule.foo(scheduled + PERIOD.cycles()).unwrap();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
//! Two tasks running at *different* priorities with access to the same resource
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::{app, Resource, Threshold};
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
static COUNTER: u64 = 0;
|
||||
},
|
||||
|
||||
tasks: {
|
||||
// The `SYS_TICK` task has higher priority than `TIM2`
|
||||
SYS_TICK: {
|
||||
path: sys_tick,
|
||||
priority: 2,
|
||||
resources: [COUNTER],
|
||||
},
|
||||
|
||||
TIM2: {
|
||||
path: tim2,
|
||||
priority: 1,
|
||||
resources: [COUNTER],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fn init(_p: init::Peripherals, _r: init::Resources) {
|
||||
// ..
|
||||
}
|
||||
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
|
||||
// ..
|
||||
|
||||
// This task can't be preempted by `tim2` so it has direct access to the
|
||||
// resource data
|
||||
*r.COUNTER += 1;
|
||||
|
||||
// ..
|
||||
}
|
||||
|
||||
fn tim2(t: &mut Threshold, mut r: TIM2::Resources) {
|
||||
// ..
|
||||
|
||||
// As this task runs at lower priority it needs a critical section to
|
||||
// prevent `sys_tick` from preempting it while it modifies this resource
|
||||
// data. The critical section is required to prevent data races which can
|
||||
// lead to undefined behavior.
|
||||
r.COUNTER.claim_mut(t, |counter, _t| {
|
||||
// `claim_mut` creates a critical section
|
||||
*counter += 1;
|
||||
});
|
||||
|
||||
// ..
|
||||
}
|
||||
53
examples/ramfunc.rs
Normal file
53
examples/ramfunc.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
//! examples/ramfunc.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(spawn = [bar])]
|
||||
fn init() {
|
||||
spawn.bar().unwrap();
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[task]
|
||||
fn foo() {
|
||||
println!("foo");
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// run this task from RAM
|
||||
#[inline(never)]
|
||||
#[link_section = ".data.bar"]
|
||||
#[task(priority = 2, spawn = [foo])]
|
||||
fn bar() {
|
||||
spawn.foo().unwrap();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
|
||||
// run the task dispatcher from RAM
|
||||
#[link_section = ".data.UART1"]
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
60
examples/resource.rs
Normal file
60
examples/resource.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
//! examples/resource.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
// A resource
|
||||
static mut SHARED: u32 = 0;
|
||||
|
||||
#[init]
|
||||
fn init() {
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtfm::pend(Interrupt::UART1);
|
||||
}
|
||||
|
||||
#[idle]
|
||||
fn idle() -> ! {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
// error: `SHARED` can't be accessed from this context
|
||||
// SHARED += 1;
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
// `SHARED` can be access from this context
|
||||
#[interrupt(resources = [SHARED])]
|
||||
fn UART0() {
|
||||
*resources.SHARED += 1;
|
||||
|
||||
println!("UART0: SHARED = {}", resources.SHARED);
|
||||
}
|
||||
|
||||
// `SHARED` can be access from this context
|
||||
#[interrupt(resources = [SHARED])]
|
||||
fn UART1() {
|
||||
*resources.SHARED += 1;
|
||||
|
||||
println!("UART1: SHARED = {}", resources.SHARED);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
//! Safe creation of `&'static mut` references
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::app;
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
static BUFFER: [u8; 16] = [0; 16];
|
||||
},
|
||||
|
||||
init: {
|
||||
resources: [BUFFER],
|
||||
},
|
||||
}
|
||||
|
||||
fn init(_p: init::Peripherals, r: init::Resources) {
|
||||
let _buf: &'static mut [u8; 16] = r.BUFFER;
|
||||
}
|
||||
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
51
examples/schedule.rs
Normal file
51
examples/schedule.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
//! examples/schedule.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use rtfm::{app, Instant};
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE: does NOT work on QEMU!
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(schedule = [foo, bar])]
|
||||
fn init() {
|
||||
let now = Instant::now();
|
||||
|
||||
println!("init @ {:?}", now);
|
||||
|
||||
// Schedule `foo` to run 8e6 cycles (clock cycles) in the future
|
||||
schedule.foo(now + 8_000_000.cycles()).unwrap();
|
||||
|
||||
// Schedule `bar` to run 4e6 cycles in the future
|
||||
schedule.bar(now + 4_000_000.cycles()).unwrap();
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn foo() {
|
||||
println!("foo @ {:?}", Instant::now());
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn bar() {
|
||||
println!("bar @ {:?}", Instant::now());
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
}
|
||||
};
|
||||
69
examples/singleton.rs
Normal file
69
examples/singleton.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
//! examples/singleton.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use alloc_singleton::stable::pool::{Box, Pool};
|
||||
use cortex_m_semihosting::debug;
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[Singleton(Send)]
|
||||
static mut M: [u32; 2] = [0; 2];
|
||||
|
||||
static mut P: Pool<M> = ();
|
||||
|
||||
#[init(resources = [M])]
|
||||
fn init() {
|
||||
rtfm::pend(Interrupt::I2C0);
|
||||
|
||||
P = Pool::new(resources.M);
|
||||
}
|
||||
|
||||
#[interrupt(
|
||||
priority = 2,
|
||||
resources = [P],
|
||||
spawn = [foo, bar],
|
||||
)]
|
||||
fn I2C0() {
|
||||
spawn.foo(resources.P.alloc(1).unwrap()).unwrap();
|
||||
spawn.bar(resources.P.alloc(2).unwrap()).unwrap();
|
||||
}
|
||||
|
||||
#[task(resources = [P])]
|
||||
fn foo(x: Box<M>) {
|
||||
println!("foo({})", x);
|
||||
|
||||
resources.P.lock(|p| p.dealloc(x));
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#[task(priority = 2, resources = [P])]
|
||||
fn bar(x: Box<M>) {
|
||||
println!("bar({})", x);
|
||||
|
||||
resources.P.dealloc(x);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
17
examples/smallest.rs
Normal file
17
examples/smallest.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//! examples/smallest.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// panic-handler crate
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use rtfm::app;
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init]
|
||||
fn init() {}
|
||||
};
|
||||
47
examples/static.rs
Normal file
47
examples/static.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
//! examples/static.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use lm3s6965::Interrupt;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
static KEY: u32 = ();
|
||||
|
||||
#[init]
|
||||
fn init() {
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtfm::pend(Interrupt::UART1);
|
||||
|
||||
KEY = 0xdeadbeef;
|
||||
}
|
||||
|
||||
#[interrupt(resources = [KEY])]
|
||||
fn UART0() {
|
||||
println!("UART0(KEY = {:#x})", resources.KEY);
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#[interrupt(priority = 2, resources = [KEY])]
|
||||
fn UART1() {
|
||||
println!("UART1(KEY = {:#x})", resources.KEY);
|
||||
}
|
||||
};
|
||||
61
examples/task.rs
Normal file
61
examples/task.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//! examples/task.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::app;
|
||||
|
||||
macro_rules! println {
|
||||
($($tt:tt)*) => {
|
||||
if let Ok(mut stdout) = cortex_m_semihosting::hio::hstdout() {
|
||||
use core::fmt::Write;
|
||||
|
||||
writeln!(stdout, $($tt)*).ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(spawn = [foo])]
|
||||
fn init() {
|
||||
spawn.foo().unwrap();
|
||||
}
|
||||
|
||||
#[task(spawn = [bar, baz])]
|
||||
fn foo() {
|
||||
println!("foo");
|
||||
|
||||
// spawns `bar` onto the task scheduler
|
||||
// `foo` and `bar` have the same priority so `bar` will not run until
|
||||
// after `foo` terminates
|
||||
spawn.bar().unwrap();
|
||||
|
||||
// spawns `baz` onto the task scheduler
|
||||
// `baz` has higher priority than `foo` so it immediately preempts `foo`
|
||||
spawn.baz().unwrap();
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn bar() {
|
||||
println!("bar");
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#[task(priority = 2)]
|
||||
fn baz() {
|
||||
println!("baz");
|
||||
}
|
||||
|
||||
// Interrupt handlers used to dispatch software tasks
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
//! Two tasks running at the *same* priority with access to the same resource
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm;
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use rtfm::{app, Threshold};
|
||||
|
||||
app! {
|
||||
device: stm32f103xx,
|
||||
|
||||
resources: {
|
||||
static COUNTER: u64 = 0;
|
||||
},
|
||||
|
||||
// Both SYS_TICK and TIM2 have access to the `COUNTER` data
|
||||
tasks: {
|
||||
SYS_TICK: {
|
||||
path: sys_tick,
|
||||
resources: [COUNTER],
|
||||
},
|
||||
|
||||
TIM2: {
|
||||
path: tim2,
|
||||
resources: [COUNTER],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fn init(_p: init::Peripherals, _r: init::Resources) {
|
||||
// ..
|
||||
}
|
||||
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
// As both tasks are running at the same priority one can't preempt the other.
|
||||
// Thus both tasks have direct access to the resource
|
||||
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
|
||||
// ..
|
||||
|
||||
*r.COUNTER += 1;
|
||||
|
||||
// ..
|
||||
}
|
||||
|
||||
fn tim2(_t: &mut Threshold, mut r: TIM2::Resources) {
|
||||
// ..
|
||||
|
||||
*r.COUNTER += 1;
|
||||
|
||||
// ..
|
||||
}
|
||||
54
examples/types.rs
Normal file
54
examples/types.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//! examples/types.rs
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
use rtfm::{app, Instant};
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
static mut SHARED: u32 = 0;
|
||||
|
||||
#[init(schedule = [foo], spawn = [foo])]
|
||||
fn init() {
|
||||
let _: Instant = start;
|
||||
let _: rtfm::Peripherals = core;
|
||||
let _: lm3s6965::Peripherals = device;
|
||||
let _: init::Schedule = schedule;
|
||||
let _: init::Spawn = spawn;
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#[exception(schedule = [foo], spawn = [foo])]
|
||||
fn SVCall() {
|
||||
let _: Instant = start;
|
||||
let _: SVCall::Schedule = schedule;
|
||||
let _: SVCall::Spawn = spawn;
|
||||
}
|
||||
|
||||
#[interrupt(resources = [SHARED], schedule = [foo], spawn = [foo])]
|
||||
fn UART0() {
|
||||
let _: Instant = start;
|
||||
let _: resources::SHARED = resources.SHARED;
|
||||
let _: UART0::Schedule = schedule;
|
||||
let _: UART0::Spawn = spawn;
|
||||
}
|
||||
|
||||
#[task(priority = 2, resources = [SHARED], schedule = [foo], spawn = [foo])]
|
||||
fn foo() {
|
||||
let _: Instant = scheduled;
|
||||
let _: foo::Resources = resources;
|
||||
let _: foo::Schedule = schedule;
|
||||
let _: foo::Spawn = spawn;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
//! Minimal example with zero tasks
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rtfm as rtfm; // IMPORTANT always do this rename
|
||||
extern crate stm32f103xx; // the device crate
|
||||
|
||||
// import the procedural macro
|
||||
use rtfm::app;
|
||||
|
||||
// This macro call indicates that this is a RTFM application
|
||||
//
|
||||
// This macro will expand to a `main` function so you don't need to supply
|
||||
// `main` yourself.
|
||||
app! {
|
||||
// this is the path to the device crate
|
||||
device: stm32f103xx,
|
||||
}
|
||||
|
||||
// The initialization phase.
|
||||
//
|
||||
// This runs first and within a *global* critical section. Nothing can preempt
|
||||
// this function.
|
||||
fn init(p: init::Peripherals) {
|
||||
// This function has access to all the peripherals of the device
|
||||
p.core.SYST;
|
||||
p.device.GPIOA;
|
||||
p.device.RCC;
|
||||
// ..
|
||||
}
|
||||
|
||||
// The idle loop.
|
||||
//
|
||||
// This runs after `init` and has a priority of 0. All tasks can preempt this
|
||||
// function. This function can never return so it must contain some sort of
|
||||
// endless loop.
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
// This puts the processor to sleep until there's a task to service
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue