v0.2.0
This commit is contained in:
@@ -6,10 +6,12 @@
|
||||
//!
|
||||
//! ``` text
|
||||
//! [dependencies.core]
|
||||
//! [dependencies.collections] # new
|
||||
//! stage = 0
|
||||
//!
|
||||
//! [dependencies.collections] # NEW
|
||||
//! stage = 0
|
||||
//!
|
||||
//! [dependencies.compiler_builtins]
|
||||
//! features = ["mem"]
|
||||
//! git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
||||
//! stage = 1
|
||||
//! ```
|
||||
@@ -21,7 +23,10 @@
|
||||
//! # or edit the Cargo.toml file manually
|
||||
//! $ cargo add alloc-cortex-m
|
||||
//! ```
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#[allow(deprecated)]
|
||||
#![feature(collections)]
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
@@ -30,11 +35,14 @@
|
||||
extern crate alloc_cortex_m;
|
||||
#[macro_use]
|
||||
extern crate collections;
|
||||
#[macro_use]
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate cortex_m_semihosting;
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
use cortex_m::asm;
|
||||
use cortex_m_semihosting::hio;
|
||||
|
||||
fn main() {
|
||||
// Initialize the allocator
|
||||
@@ -45,25 +53,26 @@ fn main() {
|
||||
}
|
||||
|
||||
// Size of the heap in words (1 word = 4 bytes)
|
||||
// WARNING: The bigger the heap the greater the chance to run into a
|
||||
// stack overflow (collision between the stack and the heap)
|
||||
// NOTE The bigger the heap the greater the chance to run into a stack
|
||||
// overflow (collision between the stack and the heap)
|
||||
const SIZE: isize = 256;
|
||||
|
||||
// End of the heap
|
||||
let _eheap = (&mut _sheap as *mut _).offset(SIZE);
|
||||
|
||||
alloc_cortex_m::init(&mut _sheap as *mut _, _eheap);
|
||||
alloc_cortex_m::init(&mut _sheap, _eheap);
|
||||
}
|
||||
|
||||
// Growable array allocated on the heap
|
||||
let xs = vec![0, 1, 2];
|
||||
hprintln!("{:?}", xs);
|
||||
|
||||
let mut stdout = hio::hstdout().unwrap();
|
||||
writeln!(stdout, "{:?}", xs).unwrap();
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
|
||||
@@ -8,27 +8,55 @@
|
||||
//! 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 {
|
||||
//! ``` text
|
||||
//! (gdb) # Exception frame = program state during the crash
|
||||
//! (gdb) print/x *ef
|
||||
//! $1 = cortex_m::exception::ExceptionFrame {
|
||||
//! r0 = 0x2fffffff,
|
||||
//! r1 = 0x2fffffff,
|
||||
//! r2 = 0x0,
|
||||
//! r3 = 0x0,
|
||||
//! r12 = 0x0,
|
||||
//! lr = 0x8000443,
|
||||
//! pc = 0x8000190,
|
||||
//! xpsr = 0x61000200,
|
||||
//! lr = 0x8000481,
|
||||
//! pc = 0x8000460,
|
||||
//! xpsr = 0x61000000,
|
||||
//! }
|
||||
//!
|
||||
//! (gdb) # What exception was triggered?
|
||||
//! (gdb) print _e
|
||||
//! $2 = cortex_m::exception::Exception::HardFault
|
||||
//!
|
||||
//! (gdb) # Where did we come from?
|
||||
//! (gdb) backtrace
|
||||
//! #0 cortex_m_rt::default_handler (ef=0x20004f54) at (..)
|
||||
//! #1 <signal handler called>
|
||||
//! #2 0x08000460 in core::ptr::read_volatile<u32> (src=0x2fffffff) at (..)
|
||||
//! #3 0x08000480 in crash::main () at examples/crash.rs:68
|
||||
//!
|
||||
//! (gdb) # Nail down the location of the crash
|
||||
//! (gdb) disassemble/m ef.pc
|
||||
//! Dump of assembler code for function core::ptr::read_volatile<u32>:
|
||||
//! 408 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||
//! 0x08000454 <+0>: sub sp, #20
|
||||
//! 0x08000456 <+2>: mov r1, r0
|
||||
//! 0x08000458 <+4>: str r0, [sp, #8]
|
||||
//! 0x0800045a <+6>: ldr r0, [sp, #8]
|
||||
//! 0x0800045c <+8>: str r0, [sp, #12]
|
||||
//!
|
||||
//! 409 intrinsics::volatile_load(src)
|
||||
//! 0x0800045e <+10>: ldr r0, [sp, #12]
|
||||
//! 0x08000460 <+12>: ldr r0, [r0, #0]
|
||||
//! 0x08000462 <+14>: str r0, [sp, #16]
|
||||
//! 0x08000464 <+16>: ldr r0, [sp, #16]
|
||||
//! 0x08000466 <+18>: str r1, [sp, #4]
|
||||
//! 0x08000468 <+20>: str r0, [sp, #0]
|
||||
//! 0x0800046a <+22>: b.n 0x800046c <core::ptr::read_volatile<u32>+24>
|
||||
//!
|
||||
//! 410 }
|
||||
//! 0x0800046c <+24>: ldr r0, [sp, #0]
|
||||
//! 0x0800046e <+26>: add sp, #20
|
||||
//! 0x08000470 <+28>: bx lr
|
||||
//!
|
||||
//! End of assembler dump.
|
||||
//! ```
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
@@ -48,9 +76,8 @@ fn main() {
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
|
||||
58
examples/device.rs
Normal file
58
examples/device.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
//! Using a device crate
|
||||
//!
|
||||
//! Crates generated using [`svd2rust`] are referred to as device crates. These
|
||||
//! crates provides an API to access the peripherals of a device. When you
|
||||
//! depend on one of these crates and the "rt" feature is enabled you don't need
|
||||
//! link to the cortex-m-rt crate.
|
||||
//!
|
||||
//! [`svd2rust`]: https://crates.io/crates/svd2rust
|
||||
//!
|
||||
//! Device crates also provide an `interrupt!` macro to register interrupt
|
||||
//! handlers.
|
||||
//!
|
||||
//! This example depends on the [`stm32f103xx`] crate so you'll have to add it
|
||||
//! to your Cargo.toml.
|
||||
//!
|
||||
//! [`stm32f103xx`]: https://crates.io/crates/stm32f103xx
|
||||
//!
|
||||
//! ```
|
||||
//! $ edit Cargo.toml && cat $_
|
||||
//! [dependencies.stm32f103xx]
|
||||
//! features = ["rt"]
|
||||
//! version = "0.7.0"
|
||||
//! ```
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
#[macro_use(exception, interrupt)]
|
||||
extern crate stm32f103xx;
|
||||
|
||||
use cortex_m::interrupt;
|
||||
|
||||
fn main() {
|
||||
interrupt::free(|cs| {
|
||||
let _gpioa = stm32f103xx::GPIOA.borrow(cs);
|
||||
// do something with GPIOA
|
||||
});
|
||||
}
|
||||
|
||||
exception!(SYS_TICK, tick, locals: {
|
||||
ticks: u32 = 0;
|
||||
});
|
||||
|
||||
fn tick(l: &mut SYS_TICK::Locals) {
|
||||
l.ticks += 1;
|
||||
// ..
|
||||
}
|
||||
|
||||
interrupt!(TIM2, tock, locals: {
|
||||
tocks: u32 = 0;
|
||||
});
|
||||
|
||||
fn tock(l: &mut TIM2::Locals) {
|
||||
l.tocks += 1;
|
||||
// ..
|
||||
}
|
||||
@@ -1,22 +1,27 @@
|
||||
//! 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 cortex_m_semihosting;
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
use cortex_m::asm;
|
||||
use cortex_m_semihosting::hio;
|
||||
|
||||
fn main() {
|
||||
hprintln!("Hello, world!");
|
||||
let mut stdout = hio::hstdout().unwrap();
|
||||
writeln!(stdout, "Hello, world!").unwrap();
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
//! 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`.
|
||||
//! to uncomment the `monitor` commands in the `.gdbinit` file.
|
||||
//!
|
||||
//! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
@@ -21,19 +23,16 @@ extern crate cortex_m_rt;
|
||||
use cortex_m::{asm, interrupt, peripheral};
|
||||
|
||||
fn main() {
|
||||
interrupt::free(
|
||||
|cs| {
|
||||
let itm = peripheral::ITM.borrow(&cs);
|
||||
interrupt::free(|cs| {
|
||||
let itm = peripheral::ITM.borrow(&cs);
|
||||
|
||||
iprintln!(&itm.stim[0], "Hello, world!");
|
||||
},
|
||||
);
|
||||
iprintln!(&itm.stim[0], "Hello, world!");
|
||||
});
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
//! Overriding an exception
|
||||
//! Overriding an exception handler
|
||||
//!
|
||||
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature
|
||||
//! to make this work.
|
||||
//! You can override an exception handler using the [`exception!`][1] macro.
|
||||
//!
|
||||
//! [1]: https://docs.rs/cortex-m-rt/0.3.2/cortex_m_rt/macro.exception.html
|
||||
//!
|
||||
//! The default exception handler can be overridden using the
|
||||
//! [`default_handler!`][2] macro
|
||||
//!
|
||||
//! [2]: https://docs.rs/cortex-m-rt/0.3.2/cortex_m_rt/macro.default_handler.html
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
#[macro_use(exception)]
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
use core::ptr;
|
||||
|
||||
use cortex_m::{asm, exception};
|
||||
use cortex_m::asm;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
@@ -20,25 +29,17 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn hard_fault(_: exception::HardFault) {
|
||||
exception!(HARD_FAULT, handler);
|
||||
|
||||
fn handler() {
|
||||
// You'll hit this breakpoint rather than the one in cortex-m-rt
|
||||
asm::bkpt()
|
||||
}
|
||||
|
||||
// When the "exceptions" feature is disabled, you'll have to provide this symbol
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".rodata.exceptions"]
|
||||
static EXCEPTIONS: exception::Handlers = exception::Handlers {
|
||||
// This is the exception handler override
|
||||
hard_fault: hard_fault,
|
||||
..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"]
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
|
||||
@@ -1,33 +1,56 @@
|
||||
//! Redirecting `panic!` messages
|
||||
//! Defining the panic handler
|
||||
//!
|
||||
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages
|
||||
//! through these two Cargo features:
|
||||
//! The panic handler can be defined through the `panic_fmt` [language item][1].
|
||||
//! Make sure that the "abort-on-panic" feature of the cortex-m-rt crate is
|
||||
//! disabled to avoid redefining the language item.
|
||||
//!
|
||||
//! - `panic-over-semihosting`. `panic!` messages will be printed to the OpenOCD
|
||||
//! console using semihosting. This is slow.
|
||||
//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html
|
||||
//!
|
||||
//! - `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(core_intrinsics)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate cortex_m_semihosting;
|
||||
|
||||
use core::fmt::Write;
|
||||
use core::intrinsics;
|
||||
|
||||
use cortex_m::asm;
|
||||
use cortex_m_semihosting::hio;
|
||||
|
||||
fn main() {
|
||||
panic!("Oops");
|
||||
}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rust_begin_unwind(
|
||||
args: core::fmt::Arguments,
|
||||
file: &'static str,
|
||||
line: u32,
|
||||
col: u32,
|
||||
) -> ! {
|
||||
if let Ok(mut stdout) = hio::hstdout() {
|
||||
write!(stdout, "panicked at '")
|
||||
.and_then(|_| {
|
||||
stdout
|
||||
.write_fmt(args)
|
||||
.and_then(|_| writeln!(stdout, "', {}:{}", file, line))
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
intrinsics::abort()
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
#[link_section = ".rodata.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
//! 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