turn into a Cargo crate
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
//! Device agnostic "Hello, world!"
|
||||
//!
|
||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [u32; 240] = [0; 240];
|
||||
@@ -1,25 +0,0 @@
|
||||
//! Device specific version of "Hello, world!"
|
||||
//!
|
||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate {{name}};
|
||||
|
||||
use {{name}}::interrupt;
|
||||
|
||||
fn main() {
|
||||
hprintln!("Hello, world!");
|
||||
}
|
||||
|
||||
// This is the device specific bit: properly populated interrupt handlers
|
||||
// Tough we are not using any of them in this example
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: interrupt::Handlers =
|
||||
interrupt::Handlers { ..interrupt::DEFAULT_HANDLERS };
|
||||
@@ -1,39 +0,0 @@
|
||||
//! Sends "Hello, world!" through the ITM port 0
|
||||
//!
|
||||
//! **NOTE** Not all Cortex-M chips support ITM. You'll have to connect your
|
||||
//! microcontroller's SWO pin to the debug interface. Some development boards
|
||||
//! don't provide this option.
|
||||
//!
|
||||
//! This is faster than using semihosting.
|
||||
//!
|
||||
//! You'll need [`itmdump`] to receive the message plus you'll need to enable
|
||||
//! OpenOCD's ITM support in `.gdbinit`.
|
||||
//!
|
||||
//! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate {{name}};
|
||||
|
||||
use cortex_m::peripheral;
|
||||
use {{name}}::interrupt;
|
||||
|
||||
fn main() {
|
||||
cortex_m::interrupt::free(
|
||||
|cs| {
|
||||
let itm = peripheral::ITM.borrow(&cs);
|
||||
|
||||
iprintln!(&itm.stim[0], "Hello, world!");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: interrupt::Handlers =
|
||||
interrupt::Handlers { ..interrupt::DEFAULT_HANDLERS };
|
||||
@@ -1,83 +0,0 @@
|
||||
//! Stack Resource Policy
|
||||
//!
|
||||
//! You should see the following output
|
||||
//!
|
||||
//! ``` text
|
||||
//! IDLE
|
||||
//! J1: enter
|
||||
//! J2: enter
|
||||
//! J2(R1)
|
||||
//! J2: exit
|
||||
//! J1: after requesting J2
|
||||
//! J1(R1): before requesting J2
|
||||
//! J1(R1): after requesting J2
|
||||
//! J2: enter
|
||||
//! J2(R1)
|
||||
//! J2: exit
|
||||
//! J1: exit
|
||||
//! ```
|
||||
|
||||
#![feature(const_fn)]
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
#[macro_use]
|
||||
extern crate cortex_m_srp as rtfm;
|
||||
extern crate {{name}};
|
||||
|
||||
use rtfm::{C2, C4, C16, P0, P1, P3, Resource};
|
||||
// NOTE device dependent
|
||||
use {{name}}::interrupt::{Exti0Irq, Exti1Irq};
|
||||
|
||||
static R1: Resource<(), C4> = Resource::new(());
|
||||
static R2: Resource<(), C2> = Resource::new(());
|
||||
|
||||
fn init(_prio: P0, _ceil: C16) {}
|
||||
|
||||
fn idle(_prio: P0) -> ! {
|
||||
hprintln!("IDLE");
|
||||
|
||||
rtfm::request(j1);
|
||||
|
||||
// Sleep
|
||||
loop {
|
||||
rtfm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE Exti0Irq and Exti1Irq are device dependent
|
||||
tasks!({{name}}, {
|
||||
j1: (Exti0Irq, P1),
|
||||
j2: (Exti1Irq, P3),
|
||||
});
|
||||
|
||||
fn j1(_task: Exti0Irq, prio: P1) {
|
||||
hprintln!("J1: enter");
|
||||
R2.lock(
|
||||
&prio, |_, _| {
|
||||
rtfm::request(j2);
|
||||
hprintln!("J1: after requesting J2");
|
||||
R1.lock(
|
||||
&prio, |_, _| {
|
||||
hprintln!("J1(R1): before requesting J2");
|
||||
rtfm::request(j2);
|
||||
hprintln!("J1(R1): after requesting J2");
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
hprintln!("J1: exit");
|
||||
}
|
||||
|
||||
fn j2(_task: Exti1Irq, prio: P3) {
|
||||
hprintln!("J2: enter");
|
||||
R1.lock(
|
||||
&prio, |_, _| {
|
||||
hprintln!("J2(R1)");
|
||||
}
|
||||
);
|
||||
hprintln!("J2: exit");
|
||||
}
|
||||
58
examples/crash.rs
Normal file
58
examples/crash.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
//! Debugging a crash (exception)
|
||||
//!
|
||||
//! The `cortex-m-rt` crate provides functionality for this through a default
|
||||
//! exception handler. When an exception is hit, the default handler will
|
||||
//! trigger a breakpoint and in this debugging context the stacked registers
|
||||
//! are accessible.
|
||||
//!
|
||||
//! In you run the example below, you'll be able to inspect the state of your
|
||||
//! program under the debugger using these commands:
|
||||
//!
|
||||
//! ```
|
||||
//! (gdb) # Stacked registers = program state during the crash
|
||||
//! (gdb) print/x *_sr
|
||||
//! $1 = cortex_m::exception::StackedRegisters {
|
||||
//! r0 = 0x2fffffff,
|
||||
//! r1 = 0x2fffffff,
|
||||
//! r2 = 0x0,
|
||||
//! r3 = 0x0,
|
||||
//! r12 = 0x0,
|
||||
//! lr = 0x8000443,
|
||||
//! pc = 0x8000190,
|
||||
//! xpsr = 0x61000200,
|
||||
//! }
|
||||
//!
|
||||
//! (gdb) # What exception was triggered?
|
||||
//! (gdb) print _e
|
||||
//! $2 = cortex_m::exception::Exception::HardFault
|
||||
//!
|
||||
//! (gdb) # Where did we come from?
|
||||
//! (gdb) print _e
|
||||
//! ```
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
use core::ptr;
|
||||
|
||||
use cortex_m::asm;
|
||||
|
||||
fn main() {
|
||||
// Read an invalid memory address
|
||||
unsafe {
|
||||
ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
||||
}
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
}
|
||||
24
examples/hello.rs
Normal file
24
examples/hello.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
use cortex_m::asm;
|
||||
|
||||
fn main() {
|
||||
hprintln!("Hello, world!");
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
}
|
||||
41
examples/itm.rs
Normal file
41
examples/itm.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
//! Sends "Hello, world!" through the ITM port 0
|
||||
//!
|
||||
//! **IMPORTANT** Not all Cortex-M chips support ITM. You'll have to connect the
|
||||
//! microcontroller's SWO pin to the SWD interface. Note that some development
|
||||
//! boards don't provide this option.
|
||||
//!
|
||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
||||
//!
|
||||
//! You'll need [`itmdump`] to receive the message on the host plus you'll need
|
||||
//! to uncomment OpenOCD's ITM support in `.gdbinit`.
|
||||
//!
|
||||
//! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
use cortex_m::{asm, interrupt, peripheral};
|
||||
|
||||
fn main() {
|
||||
interrupt::free(
|
||||
|cs| {
|
||||
let itm = peripheral::ITM.borrow(&cs);
|
||||
|
||||
iprintln!(&itm.stim[0], "Hello, world!");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
//! Overriding an exception
|
||||
//!
|
||||
//! **NOTE** You have to disable the `cortex-m-rt` crate "exceptions" feature to
|
||||
//! make this work.
|
||||
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature
|
||||
//! to make this work.
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate {{name}};
|
||||
|
||||
use core::ptr;
|
||||
|
||||
use cortex_m::{asm, exception};
|
||||
use {{name}}::interrupt;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
@@ -37,8 +35,12 @@ static EXCEPTIONS: exception::Handlers = exception::Handlers {
|
||||
..exception::DEFAULT_HANDLERS
|
||||
};
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: interrupt::Handlers =
|
||||
interrupt::Handlers { ..interrupt::DEFAULT_HANDLERS };
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
}
|
||||
35
examples/panic.rs
Normal file
35
examples/panic.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
//! Redirecting `panic!` messages
|
||||
//!
|
||||
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages
|
||||
//! through these two Cargo features:
|
||||
//!
|
||||
//! - `panic-over-semihosting`. `panic!` messages will be printed to the OpenOCD
|
||||
//! console using semihosting. This is slow.
|
||||
//!
|
||||
//! - `panic-over-itm`. `panic!` messages will be send through the ITM port 0.
|
||||
//! This is much faster but requires ITM support on the device.
|
||||
//!
|
||||
//! If neither of these options is specified then the `panic!` message will be
|
||||
//! lost. Note that all `panic!`s will trigger a debugger breakpoint.
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
use cortex_m::asm;
|
||||
|
||||
fn main() {
|
||||
panic!("Oops");
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
}
|
||||
36
examples/register-interrupt-handler.rs
Normal file
36
examples/register-interrupt-handler.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
//! Register an interrupt handler
|
||||
//!
|
||||
//! NOTE Requires a device crate generated using `svd2rust`
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
// NOTE this is the device crate
|
||||
extern crate stm32f30x;
|
||||
|
||||
use cortex_m::asm;
|
||||
use stm32f30x::interrupt;
|
||||
|
||||
fn main() {}
|
||||
|
||||
// NOTE each interrupt handler has a different signature
|
||||
extern "C" fn my_interrupt_handler(_ctxt: interrupt::Tim7) {
|
||||
asm::bkpt();
|
||||
}
|
||||
|
||||
extern "C" fn another_interrupt_handler(_ctxt: interrupt::Exti0) {
|
||||
asm::bkpt();
|
||||
}
|
||||
|
||||
// Here we override only two interrupt handlers, the rest of interrupt are
|
||||
// handled by the same interrupt handler
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: interrupt::Handlers = interrupt::Handlers {
|
||||
Tim7: my_interrupt_handler,
|
||||
Exti0: another_interrupt_handler,
|
||||
..interrupt::DEFAULT_HANDLERS
|
||||
};
|
||||
Reference in New Issue
Block a user