This commit is contained in:
Jorge Aparicio
2017-07-07 18:34:47 -05:00
parent 6780d81e4d
commit 805b63afb1
23 changed files with 400 additions and 222 deletions

View File

@@ -5,6 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
## [v0.2.0] - 2017-07-07
### Changed
- [breaking-change] Bumped the cortex-m and cortex-m-rt versions to v0.3.0.
## [v0.1.8] - 2017-05-30 ## [v0.1.8] - 2017-05-30
### Changed ### Changed

View File

@@ -6,12 +6,16 @@ keywords = ["arm", "cortex-m", "template"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
name = "cortex-m-quickstart" name = "cortex-m-quickstart"
repository = "https://github.com/japaric/cortex-m-quickstart" repository = "https://github.com/japaric/cortex-m-quickstart"
version = "0.1.8" version = "0.2.0"
[dependencies] [dependencies]
cortex-m = "0.2.7" cortex-m = "0.3.0"
cortex-m-rt = "0.2.3" cortex-m-semihosting = "0.2.0"
[dependencies.cortex-m-rt]
features = ["abort-on-panic"]
version = "0.3.2"
[profile.release] [profile.release]
lto = true
debug = true debug = true
lto = true

View File

@@ -1,6 +1,6 @@
[dependencies.core] [dependencies.core]
stage = 0
[dependencies.compiler_builtins] [dependencies.compiler_builtins]
features = ["mem"]
git = "https://github.com/rust-lang-nursery/compiler-builtins" git = "https://github.com/rust-lang-nursery/compiler-builtins"
stage = 1 stage = 1

View File

@@ -6,10 +6,12 @@
//! //!
//! ``` text //! ``` text
//! [dependencies.core] //! [dependencies.core]
//! [dependencies.collections] # new //! stage = 0
//!
//! [dependencies.collections] # NEW
//! stage = 0
//! //!
//! [dependencies.compiler_builtins] //! [dependencies.compiler_builtins]
//! features = ["mem"]
//! git = "https://github.com/rust-lang-nursery/compiler-builtins" //! git = "https://github.com/rust-lang-nursery/compiler-builtins"
//! stage = 1 //! stage = 1
//! ``` //! ```
@@ -21,7 +23,10 @@
//! # or edit the Cargo.toml file manually //! # or edit the Cargo.toml file manually
//! $ cargo add alloc-cortex-m //! $ cargo add alloc-cortex-m
//! ``` //! ```
//!
//! ---
#[allow(deprecated)]
#![feature(collections)] #![feature(collections)]
#![feature(used)] #![feature(used)]
#![no_std] #![no_std]
@@ -30,11 +35,14 @@
extern crate alloc_cortex_m; extern crate alloc_cortex_m;
#[macro_use] #[macro_use]
extern crate collections; extern crate collections;
#[macro_use]
extern crate cortex_m; extern crate cortex_m;
extern crate cortex_m_rt; extern crate cortex_m_rt;
extern crate cortex_m_semihosting;
use core::fmt::Write;
use cortex_m::asm; use cortex_m::asm;
use cortex_m_semihosting::hio;
fn main() { fn main() {
// Initialize the allocator // Initialize the allocator
@@ -45,25 +53,26 @@ fn main() {
} }
// Size of the heap in words (1 word = 4 bytes) // Size of the heap in words (1 word = 4 bytes)
// WARNING: The bigger the heap the greater the chance to run into a // NOTE The bigger the heap the greater the chance to run into a stack
// stack overflow (collision between the stack and the heap) // overflow (collision between the stack and the heap)
const SIZE: isize = 256; const SIZE: isize = 256;
// End of the heap // End of the heap
let _eheap = (&mut _sheap as *mut _).offset(SIZE); 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 // Growable array allocated on the heap
let xs = vec![0, 1, 2]; 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 // As we are not using interrupts, we just register a dummy catch all handler
#[allow(dead_code)] #[link_section = ".vector_table.interrupts"]
#[used] #[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
extern "C" fn default_handler() { extern "C" fn default_handler() {

View File

@@ -8,27 +8,55 @@
//! In you run the example below, you'll be able to inspect the state of your //! In you run the example below, you'll be able to inspect the state of your
//! program under the debugger using these commands: //! program under the debugger using these commands:
//! //!
//! ``` //! ``` text
//! (gdb) # Stacked registers = program state during the crash //! (gdb) # Exception frame = program state during the crash
//! (gdb) print/x *_sr //! (gdb) print/x *ef
//! $1 = cortex_m::exception::StackedRegisters { //! $1 = cortex_m::exception::ExceptionFrame {
//! r0 = 0x2fffffff, //! r0 = 0x2fffffff,
//! r1 = 0x2fffffff, //! r1 = 0x2fffffff,
//! r2 = 0x0, //! r2 = 0x0,
//! r3 = 0x0, //! r3 = 0x0,
//! r12 = 0x0, //! r12 = 0x0,
//! lr = 0x8000443, //! lr = 0x8000481,
//! pc = 0x8000190, //! pc = 0x8000460,
//! xpsr = 0x61000200, //! xpsr = 0x61000000,
//! } //! }
//! //!
//! (gdb) # What exception was triggered?
//! (gdb) print _e
//! $2 = cortex_m::exception::Exception::HardFault
//!
//! (gdb) # Where did we come from? //! (gdb) # Where did we come from?
//! (gdb) backtrace //! (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)] #![feature(used)]
#![no_std] #![no_std]
@@ -48,9 +76,8 @@ fn main() {
} }
// As we are not using interrupts, we just register a dummy catch all handler // As we are not using interrupts, we just register a dummy catch all handler
#[allow(dead_code)] #[link_section = ".vector_table.interrupts"]
#[used] #[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
extern "C" fn default_handler() { extern "C" fn default_handler() {

58
examples/device.rs Normal file
View 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;
// ..
}

View File

@@ -1,22 +1,27 @@
//! Prints "Hello, world!" on the OpenOCD console using semihosting //! Prints "Hello, world!" on the OpenOCD console using semihosting
//!
//! ---
#![feature(used)] #![feature(used)]
#![no_std] #![no_std]
#[macro_use]
extern crate cortex_m; extern crate cortex_m;
extern crate cortex_m_rt; extern crate cortex_m_rt;
extern crate cortex_m_semihosting;
use core::fmt::Write;
use cortex_m::asm; use cortex_m::asm;
use cortex_m_semihosting::hio;
fn main() { 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 // As we are not using interrupts, we just register a dummy catch all handler
#[allow(dead_code)] #[link_section = ".vector_table.interrupts"]
#[used] #[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
extern "C" fn default_handler() { extern "C" fn default_handler() {

View File

@@ -7,9 +7,11 @@
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so. //! 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 //! 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/ //! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
//!
//! ---
#![feature(used)] #![feature(used)]
#![no_std] #![no_std]
@@ -21,19 +23,16 @@ extern crate cortex_m_rt;
use cortex_m::{asm, interrupt, peripheral}; use cortex_m::{asm, interrupt, peripheral};
fn main() { fn main() {
interrupt::free( interrupt::free(|cs| {
|cs| { let itm = peripheral::ITM.borrow(&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 // As we are not using interrupts, we just register a dummy catch all handler
#[allow(dead_code)] #[link_section = ".vector_table.interrupts"]
#[used] #[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
extern "C" fn default_handler() { extern "C" fn default_handler() {

View File

@@ -1,17 +1,26 @@
//! Overriding an exception //! Overriding an exception handler
//! //!
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature //! You can override an exception handler using the [`exception!`][1] macro.
//! to make this work. //!
//! [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)] #![feature(used)]
#![no_std] #![no_std]
extern crate cortex_m; extern crate cortex_m;
#[macro_use(exception)]
extern crate cortex_m_rt; extern crate cortex_m_rt;
use core::ptr; use core::ptr;
use cortex_m::{asm, exception}; use cortex_m::asm;
fn main() { fn main() {
unsafe { 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 // You'll hit this breakpoint rather than the one in cortex-m-rt
asm::bkpt() 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 // As we are not using interrupts, we just register a dummy catch all handler
#[allow(dead_code)] #[allow(dead_code)]
#[used] #[used]
#[link_section = ".rodata.interrupts"] #[link_section = ".vector_table.interrupts"]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
extern "C" fn default_handler() { extern "C" fn default_handler() {

View File

@@ -1,33 +1,56 @@
//! Redirecting `panic!` messages //! Defining the panic handler
//! //!
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages //! The panic handler can be defined through the `panic_fmt` [language item][1].
//! through these two Cargo features: //! 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 //! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html
//! 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(core_intrinsics)]
#![feature(lang_items)]
#![feature(used)] #![feature(used)]
#![no_std] #![no_std]
extern crate cortex_m; extern crate cortex_m;
extern crate cortex_m_rt; extern crate cortex_m_rt;
extern crate cortex_m_semihosting;
use core::fmt::Write;
use core::intrinsics;
use cortex_m::asm; use cortex_m::asm;
use cortex_m_semihosting::hio;
fn main() { fn main() {
panic!("Oops"); 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 // As we are not using interrupts, we just register a dummy catch all handler
#[allow(dead_code)] #[link_section = ".vector_table.interrupts"]
#[used] #[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
extern "C" fn default_handler() { extern "C" fn default_handler() {

View File

@@ -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
};

View File

@@ -9,8 +9,8 @@ main() {
itm itm
panic panic
crash crash
register-interrupt-handler
override-exception-handler override-exception-handler
device
allocator allocator
) )

View File

@@ -8,12 +8,13 @@ MEMORY
/* This is where the call stack will be allocated. */ /* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */ /* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */ /* You may want to use this variable to locate the call stack and static
_stack_start = ORIGIN(RAM) + LENGTH(RAM); variables in different memory regions. Below is shown the default value */
/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */
/* You can use this symbol to customize the location of the .text section */ /* You can use this symbol to customize the location of the .text section */
/* If omitted the .text section will be placed right after the .vector_table /* If omitted the .text section will be placed right after the .vector_table
section */ section */
/* This is required only on some microcontrollers that store some configuration /* This is required only on microcontrollers that store some configuration right
right after the vector table */ after the vector table */
/* _stext = ORIGIN(FLASH) + 0x400; */ /* _stext = ORIGIN(FLASH) + 0x400; */

View File

@@ -1,24 +1,29 @@
//! Prints "Hello, world!" on the OpenOCD console using semihosting //! Prints "Hello, world!" on the OpenOCD console using semihosting
//! //!
//! ---
//!
//! ``` //! ```
//! //!
//! #![feature(used)] //! #![feature(used)]
//! #![no_std] //! #![no_std]
//! //!
//! #[macro_use]
//! extern crate cortex_m; //! extern crate cortex_m;
//! extern crate cortex_m_rt; //! extern crate cortex_m_rt;
//! extern crate cortex_m_semihosting;
//!
//! use core::fmt::Write;
//! //!
//! use cortex_m::asm; //! use cortex_m::asm;
//! use cortex_m_semihosting::hio;
//! //!
//! fn main() { //! 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 //! // As we are not using interrupts, we just register a dummy catch all handler
//! #[allow(dead_code)] //! #[link_section = ".vector_table.interrupts"]
//! #[used] //! #[used]
//! #[link_section = ".rodata.interrupts"]
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
//! //!
//! extern "C" fn default_handler() { //! extern "C" fn default_handler() {

View File

@@ -7,10 +7,12 @@
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so. //! 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 //! 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/ //! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
//! //!
//! ---
//!
//! ``` //! ```
//! //!
//! #![feature(used)] //! #![feature(used)]
@@ -23,19 +25,16 @@
//! use cortex_m::{asm, interrupt, peripheral}; //! use cortex_m::{asm, interrupt, peripheral};
//! //!
//! fn main() { //! fn main() {
//! interrupt::free( //! interrupt::free(|cs| {
//! |cs| { //! let itm = peripheral::ITM.borrow(&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 //! // As we are not using interrupts, we just register a dummy catch all handler
//! #[allow(dead_code)] //! #[link_section = ".vector_table.interrupts"]
//! #[used] //! #[used]
//! #[link_section = ".rodata.interrupts"]
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
//! //!
//! extern "C" fn default_handler() { //! extern "C" fn default_handler() {

View File

@@ -1,35 +1,58 @@
//! Redirecting `panic!` messages //! Defining the panic handler
//! //!
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages //! The panic handler can be defined through the `panic_fmt` [language item][1].
//! through these two Cargo features: //! 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 //! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html
//! 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(core_intrinsics)]
//! #![feature(lang_items)]
//! #![feature(used)] //! #![feature(used)]
//! #![no_std] //! #![no_std]
//! //!
//! extern crate cortex_m; //! extern crate cortex_m;
//! extern crate cortex_m_rt; //! extern crate cortex_m_rt;
//! extern crate cortex_m_semihosting;
//!
//! use core::fmt::Write;
//! use core::intrinsics;
//! //!
//! use cortex_m::asm; //! use cortex_m::asm;
//! use cortex_m_semihosting::hio;
//! //!
//! fn main() { //! fn main() {
//! panic!("Oops"); //! 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 //! // As we are not using interrupts, we just register a dummy catch all handler
//! #[allow(dead_code)] //! #[link_section = ".vector_table.interrupts"]
//! #[used] //! #[used]
//! #[link_section = ".rodata.interrupts"]
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
//! //!
//! extern "C" fn default_handler() { //! extern "C" fn default_handler() {

View File

@@ -8,28 +8,56 @@
//! In you run the example below, you'll be able to inspect the state of your //! In you run the example below, you'll be able to inspect the state of your
//! program under the debugger using these commands: //! program under the debugger using these commands:
//! //!
//! ``` //! ``` text
//! (gdb) # Stacked registers = program state during the crash //! (gdb) # Exception frame = program state during the crash
//! (gdb) print/x *_sr //! (gdb) print/x *ef
//! $1 = cortex_m::exception::StackedRegisters { //! $1 = cortex_m::exception::ExceptionFrame {
//! r0 = 0x2fffffff, //! r0 = 0x2fffffff,
//! r1 = 0x2fffffff, //! r1 = 0x2fffffff,
//! r2 = 0x0, //! r2 = 0x0,
//! r3 = 0x0, //! r3 = 0x0,
//! r12 = 0x0, //! r12 = 0x0,
//! lr = 0x8000443, //! lr = 0x8000481,
//! pc = 0x8000190, //! pc = 0x8000460,
//! xpsr = 0x61000200, //! xpsr = 0x61000000,
//! } //! }
//! //!
//! (gdb) # What exception was triggered?
//! (gdb) print _e
//! $2 = cortex_m::exception::Exception::HardFault
//!
//! (gdb) # Where did we come from? //! (gdb) # Where did we come from?
//! (gdb) backtrace //! (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)] //! #![feature(used)]
@@ -50,9 +78,8 @@
//! } //! }
//! //!
//! // As we are not using interrupts, we just register a dummy catch all handler //! // As we are not using interrupts, we just register a dummy catch all handler
//! #[allow(dead_code)] //! #[link_section = ".vector_table.interrupts"]
//! #[used] //! #[used]
//! #[link_section = ".rodata.interrupts"]
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
//! //!
//! extern "C" fn default_handler() { //! extern "C" fn default_handler() {

View File

@@ -1,7 +1,15 @@
//! Overriding an exception //! Overriding an exception handler
//! //!
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature //! You can override an exception handler using the [`exception!`][1] macro.
//! to make this work. //!
//! [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
//!
//! ---
//! //!
//! ``` //! ```
//! //!
@@ -9,11 +17,12 @@
//! #![no_std] //! #![no_std]
//! //!
//! extern crate cortex_m; //! extern crate cortex_m;
//! #[macro_use(exception)]
//! extern crate cortex_m_rt; //! extern crate cortex_m_rt;
//! //!
//! use core::ptr; //! use core::ptr;
//! //!
//! use cortex_m::{asm, exception}; //! use cortex_m::asm;
//! //!
//! fn main() { //! fn main() {
//! unsafe { //! unsafe {
@@ -22,25 +31,17 @@
//! } //! }
//! } //! }
//! //!
//! 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 //! // You'll hit this breakpoint rather than the one in cortex-m-rt
//! asm::bkpt() //! 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 //! // As we are not using interrupts, we just register a dummy catch all handler
//! #[allow(dead_code)] //! #[allow(dead_code)]
//! #[used] //! #[used]
//! #[link_section = ".rodata.interrupts"] //! #[link_section = ".vector_table.interrupts"]
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
//! //!
//! extern "C" fn default_handler() { //! extern "C" fn default_handler() {

View File

@@ -1,40 +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
//! };
//! ```
// Auto-generated. Do not modify.

62
src/examples/_5_device.rs Normal file
View File

@@ -0,0 +1,62 @@
//! 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;
//! // ..
//! }
//! ```
// Auto-generated. Do not modify.

View File

@@ -6,10 +6,12 @@
//! //!
//! ``` text //! ``` text
//! [dependencies.core] //! [dependencies.core]
//! [dependencies.collections] # new //! stage = 0
//!
//! [dependencies.collections] # NEW
//! stage = 0
//! //!
//! [dependencies.compiler_builtins] //! [dependencies.compiler_builtins]
//! features = ["mem"]
//! git = "https://github.com/rust-lang-nursery/compiler-builtins" //! git = "https://github.com/rust-lang-nursery/compiler-builtins"
//! stage = 1 //! stage = 1
//! ``` //! ```
@@ -22,8 +24,11 @@
//! $ cargo add alloc-cortex-m //! $ cargo add alloc-cortex-m
//! ``` //! ```
//! //!
//! ---
//!
//! ``` //! ```
//! //!
//! #[allow(deprecated)]
//! #![feature(collections)] //! #![feature(collections)]
//! #![feature(used)] //! #![feature(used)]
//! #![no_std] //! #![no_std]
@@ -32,11 +37,14 @@
//! extern crate alloc_cortex_m; //! extern crate alloc_cortex_m;
//! #[macro_use] //! #[macro_use]
//! extern crate collections; //! extern crate collections;
//! #[macro_use]
//! extern crate cortex_m; //! extern crate cortex_m;
//! extern crate cortex_m_rt; //! extern crate cortex_m_rt;
//! extern crate cortex_m_semihosting;
//!
//! use core::fmt::Write;
//! //!
//! use cortex_m::asm; //! use cortex_m::asm;
//! use cortex_m_semihosting::hio;
//! //!
//! fn main() { //! fn main() {
//! // Initialize the allocator //! // Initialize the allocator
@@ -47,25 +55,26 @@
//! } //! }
//! //!
//! // Size of the heap in words (1 word = 4 bytes) //! // Size of the heap in words (1 word = 4 bytes)
//! // WARNING: The bigger the heap the greater the chance to run into a //! // NOTE The bigger the heap the greater the chance to run into a stack
//! // stack overflow (collision between the stack and the heap) //! // overflow (collision between the stack and the heap)
//! const SIZE: isize = 256; //! const SIZE: isize = 256;
//! //!
//! // End of the heap //! // End of the heap
//! let _eheap = (&mut _sheap as *mut _).offset(SIZE); //! 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 //! // Growable array allocated on the heap
//! let xs = vec![0, 1, 2]; //! 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 //! // As we are not using interrupts, we just register a dummy catch all handler
//! #[allow(dead_code)] //! #[link_section = ".vector_table.interrupts"]
//! #[used] //! #[used]
//! #[link_section = ".rodata.interrupts"]
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
//! //!
//! extern "C" fn default_handler() { //! extern "C" fn default_handler() {

View File

@@ -4,6 +4,6 @@ pub mod _0_hello;
pub mod _1_itm; pub mod _1_itm;
pub mod _2_panic; pub mod _2_panic;
pub mod _3_crash; pub mod _3_crash;
pub mod _4_register_interrupt_handler; pub mod _4_override_exception_handler;
pub mod _5_override_exception_handler; pub mod _5_device;
pub mod _6_allocator; pub mod _6_allocator;

View File

@@ -42,11 +42,6 @@
//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K //! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
//! RAM : ORIGIN = 0x20000000, LENGTH = 40K //! RAM : ORIGIN = 0x20000000, LENGTH = 40K
//! } //! }
//!
//! /* This is where the call stack will be allocated. */
//! /* The stack is of the full descending type. */
//! /* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
//! _stack_start = ORIGIN(RAM) + LENGTH(RAM);
//! ``` //! ```
//! //!
//! - Optionally, set a default build target //! - Optionally, set a default build target
@@ -62,10 +57,10 @@
//! //!
//! ``` text //! ``` text
//! # add a device crate, or //! # add a device crate, or
//! $ cargo add stm32f30x //! $ cargo add stm32f103xx
//! //!
//! # add a board support crate //! # add a board support crate
//! $ cargo add f3 //! $ cargo add blue-pill --git https://github.com/japaric/blue-pill
//! ``` //! ```
//! //!
//! - Write the application or start from one of the examples //! - Write the application or start from one of the examples
@@ -117,7 +112,7 @@
//! ``` //! ```
//! //!
//! ``` text //! ``` text
//! # Start debug session //! # Start a debug session in another terminal
//! $ arm-none-eabi-gdb target/.. //! $ arm-none-eabi-gdb target/..
//! ``` //! ```
//! //!